XmlDocument.cs 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. //
  2. // System.Xml.XmlDocument
  3. //
  4. // Authors:
  5. // Daniel Weber ([email protected])
  6. // Kral Ferch <[email protected]>
  7. // Jason Diamond <[email protected]>
  8. // Miguel de Icaza ([email protected])
  9. // Duncan Mak ([email protected])
  10. // Atsushi Enomoto ([email protected])
  11. //
  12. // (C) 2001 Daniel Weber
  13. // (C) 2002 Kral Ferch, Jason Diamond, Miguel de Icaza, Duncan Mak,
  14. // Atsushi Enomoto
  15. // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
  16. //
  17. // Permission is hereby granted, free of charge, to any person obtaining
  18. // a copy of this software and associated documentation files (the
  19. // "Software"), to deal in the Software without restriction, including
  20. // without limitation the rights to use, copy, modify, merge, publish,
  21. // distribute, sublicense, and/or sell copies of the Software, and to
  22. // permit persons to whom the Software is furnished to do so, subject to
  23. // the following conditions:
  24. //
  25. // The above copyright notice and this permission notice shall be
  26. // included in all copies or substantial portions of the Software.
  27. //
  28. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  29. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  30. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  31. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  32. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  33. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  34. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  35. //
  36. using System.Globalization;
  37. using System.IO;
  38. using System.Security.Permissions;
  39. using System.Text;
  40. using System.Xml.XPath;
  41. using System.Diagnostics;
  42. using System.Collections;
  43. using Mono.Xml;
  44. #if NET_2_0
  45. using System.Xml.Schema;
  46. using Mono.Xml.XPath;
  47. #endif
  48. namespace System.Xml
  49. {
  50. public class XmlDocument : XmlNode, IHasXmlChildNode
  51. {
  52. #region Fields
  53. XmlNameTable nameTable;
  54. string baseURI = String.Empty;
  55. XmlImplementation implementation;
  56. bool preserveWhitespace = false;
  57. XmlResolver resolver;
  58. Hashtable idTable = new Hashtable ();
  59. XmlNameEntryCache nameCache;
  60. XmlLinkedNode lastLinkedChild;
  61. #if NET_2_0
  62. XmlSchemaSet schemas;
  63. IXmlSchemaInfo schemaInfo;
  64. #endif
  65. // MS.NET rejects undeclared entities _only_ during Load(),
  66. // while ReadNode() never rejects such node. So it signs
  67. // whether we are on Load() or not (MS.NET uses Loader class,
  68. // but we don't have to implement Load() as such)
  69. bool loadMode;
  70. #endregion
  71. #region Constructors
  72. public XmlDocument () : this (null, null)
  73. {
  74. }
  75. protected internal XmlDocument (XmlImplementation imp) : this (imp, null)
  76. {
  77. }
  78. public XmlDocument (XmlNameTable nt) : this (null, nt)
  79. {
  80. }
  81. XmlDocument (XmlImplementation impl, XmlNameTable nt) : base (null)
  82. {
  83. if (impl == null)
  84. implementation = new XmlImplementation ();
  85. else
  86. implementation = impl;
  87. nameTable = (nt != null) ? nt : implementation.InternalNameTable;
  88. nameCache = new XmlNameEntryCache (nameTable);
  89. AddDefaultNameTableKeys ();
  90. resolver = new XmlUrlResolver ();
  91. }
  92. #endregion
  93. #region Events
  94. public event XmlNodeChangedEventHandler NodeChanged;
  95. public event XmlNodeChangedEventHandler NodeChanging;
  96. public event XmlNodeChangedEventHandler NodeInserted;
  97. public event XmlNodeChangedEventHandler NodeInserting;
  98. public event XmlNodeChangedEventHandler NodeRemoved;
  99. public event XmlNodeChangedEventHandler NodeRemoving;
  100. #endregion
  101. #region Properties
  102. XmlLinkedNode IHasXmlChildNode.LastLinkedChild {
  103. get { return lastLinkedChild; }
  104. set { lastLinkedChild = value; }
  105. }
  106. public override string BaseURI {
  107. get {
  108. return baseURI;
  109. }
  110. }
  111. public XmlElement DocumentElement {
  112. get {
  113. XmlNode node = FirstChild;
  114. while (node != null) {
  115. if (node is XmlElement)
  116. break;
  117. node = node.NextSibling;
  118. }
  119. return node != null ? node as XmlElement : null;
  120. }
  121. }
  122. public virtual XmlDocumentType DocumentType {
  123. get {
  124. for (XmlNode n = FirstChild; n != null; n = n.NextSibling) {
  125. if (n.NodeType == XmlNodeType.DocumentType)
  126. return (XmlDocumentType) n;
  127. else if (n.NodeType == XmlNodeType.Element) // document element
  128. return null;
  129. }
  130. return null;
  131. }
  132. }
  133. public XmlImplementation Implementation {
  134. get { return implementation; }
  135. }
  136. public override string InnerXml {
  137. get {
  138. return base.InnerXml;
  139. }
  140. set { // reason for overriding
  141. this.LoadXml (value);
  142. }
  143. }
  144. public override bool IsReadOnly {
  145. get { return false; }
  146. }
  147. internal bool IsStandalone {
  148. get {
  149. return FirstChild != null &&
  150. FirstChild.NodeType == XmlNodeType.XmlDeclaration &&
  151. ((XmlDeclaration) this.FirstChild).Standalone == "yes";
  152. }
  153. }
  154. public override string LocalName {
  155. get { return "#document"; }
  156. }
  157. public override string Name {
  158. get { return "#document"; }
  159. }
  160. internal XmlNameEntryCache NameCache {
  161. get { return nameCache; }
  162. }
  163. public XmlNameTable NameTable {
  164. get { return nameTable; }
  165. }
  166. public override XmlNodeType NodeType {
  167. get { return XmlNodeType.Document; }
  168. }
  169. internal override XPathNodeType XPathNodeType {
  170. get {
  171. return XPathNodeType.Root;
  172. }
  173. }
  174. public override XmlDocument OwnerDocument {
  175. get { return null; }
  176. }
  177. public bool PreserveWhitespace {
  178. get { return preserveWhitespace; }
  179. set { preserveWhitespace = value; }
  180. }
  181. internal XmlResolver Resolver {
  182. get { return resolver; }
  183. }
  184. internal override string XmlLang {
  185. get { return String.Empty; }
  186. }
  187. public virtual XmlResolver XmlResolver {
  188. set { resolver = value; }
  189. }
  190. internal override XmlSpace XmlSpace {
  191. get {
  192. return XmlSpace.None;
  193. }
  194. }
  195. internal Encoding TextEncoding {
  196. get {
  197. XmlDeclaration dec = FirstChild as XmlDeclaration;
  198. if (dec == null || dec.Encoding == "")
  199. return null;
  200. return Encoding.GetEncoding (dec.Encoding);
  201. }
  202. }
  203. #if NET_2_0
  204. public override XmlNode ParentNode {
  205. get { return null; }
  206. }
  207. public XmlSchemaSet Schemas {
  208. get { return schemas; }
  209. set { schemas = value; }
  210. }
  211. public override IXmlSchemaInfo SchemaInfo {
  212. get { return schemaInfo; }
  213. internal set { schemaInfo = value; }
  214. }
  215. #endif
  216. #endregion
  217. #region Methods
  218. internal void AddIdenticalAttribute (XmlAttribute attr)
  219. {
  220. idTable [attr.Value] = attr;
  221. }
  222. public override XmlNode CloneNode (bool deep)
  223. {
  224. XmlDocument doc = implementation != null ? implementation.CreateDocument () : new XmlDocument ();
  225. doc.baseURI = baseURI;
  226. if(deep)
  227. {
  228. for (XmlNode n = FirstChild; n != null; n = n.NextSibling)
  229. doc.AppendChild (doc.ImportNode (n, deep), false);
  230. }
  231. return doc;
  232. }
  233. public XmlAttribute CreateAttribute (string name)
  234. {
  235. string prefix;
  236. string localName;
  237. string namespaceURI = String.Empty;
  238. ParseName (name, out prefix, out localName);
  239. if (prefix == "xmlns" || (prefix == "" && localName == "xmlns"))
  240. namespaceURI = XmlNamespaceManager.XmlnsXmlns;
  241. else if (prefix == "xml")
  242. namespaceURI = XmlNamespaceManager.XmlnsXml;
  243. return CreateAttribute (prefix, localName, namespaceURI );
  244. }
  245. public XmlAttribute CreateAttribute (string qualifiedName, string namespaceURI)
  246. {
  247. string prefix;
  248. string localName;
  249. ParseName (qualifiedName, out prefix, out localName);
  250. return CreateAttribute (prefix, localName, namespaceURI);
  251. }
  252. public virtual XmlAttribute CreateAttribute (string prefix, string localName, string namespaceURI)
  253. {
  254. return CreateAttribute (prefix, localName, namespaceURI, false, true);
  255. }
  256. internal XmlAttribute CreateAttribute (string prefix, string localName, string namespaceURI, bool atomizedNames, bool checkNamespace)
  257. {
  258. if ((localName == null) || (localName == String.Empty))
  259. throw new ArgumentException ("The attribute local name cannot be empty.");
  260. return new XmlAttribute (prefix, localName, namespaceURI, this, atomizedNames, checkNamespace);
  261. }
  262. public virtual XmlCDataSection CreateCDataSection (string data)
  263. {
  264. return new XmlCDataSection (data, this);
  265. }
  266. public virtual XmlComment CreateComment (string data)
  267. {
  268. return new XmlComment (data, this);
  269. }
  270. protected internal virtual XmlAttribute CreateDefaultAttribute (string prefix, string localName, string namespaceURI)
  271. {
  272. XmlAttribute attr = CreateAttribute (prefix, localName, namespaceURI);
  273. attr.isDefault = true;
  274. return attr;
  275. }
  276. public virtual XmlDocumentFragment CreateDocumentFragment ()
  277. {
  278. return new XmlDocumentFragment (this);
  279. }
  280. [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
  281. public virtual XmlDocumentType CreateDocumentType (string name, string publicId,
  282. string systemId, string internalSubset)
  283. {
  284. return new XmlDocumentType (name, publicId, systemId, internalSubset, this);
  285. }
  286. private XmlDocumentType CreateDocumentType (DTDObjectModel dtd)
  287. {
  288. return new XmlDocumentType (dtd, this);
  289. }
  290. public XmlElement CreateElement (string name)
  291. {
  292. return CreateElement (name, String.Empty);
  293. }
  294. public XmlElement CreateElement (
  295. string qualifiedName,
  296. string namespaceURI)
  297. {
  298. string prefix;
  299. string localName;
  300. ParseName (qualifiedName, out prefix, out localName);
  301. return CreateElement (prefix, localName, namespaceURI);
  302. }
  303. public virtual XmlElement CreateElement (
  304. string prefix,
  305. string localName,
  306. string namespaceURI)
  307. {
  308. if ((localName == null) || (localName == String.Empty))
  309. throw new ArgumentException ("The local name for elements or attributes cannot be null or an empty string.");
  310. // LAMESPEC: MS.NET has a weird behavior that they can Load() from XmlTextReader
  311. // whose Namespaces = false, but their CreateElement() never allows qualified name.
  312. // I leave it as it is.
  313. return new XmlElement (prefix != null ? prefix : String.Empty, localName, namespaceURI != null ? namespaceURI : String.Empty, this, false);
  314. }
  315. public virtual XmlEntityReference CreateEntityReference (string name)
  316. {
  317. return new XmlEntityReference (name, this);
  318. }
  319. #if NET_2_0
  320. public override XPathNavigator CreateNavigator ()
  321. {
  322. return CreateNavigator (this);
  323. }
  324. #endif
  325. protected internal virtual XPathNavigator CreateNavigator (XmlNode node)
  326. {
  327. #if NET_2_0
  328. return new XPathEditableDocument (node).CreateNavigator ();
  329. #else
  330. return new XmlDocumentNavigator (node);
  331. #endif
  332. }
  333. public virtual XmlNode CreateNode (
  334. string nodeTypeString,
  335. string name,
  336. string namespaceURI)
  337. {
  338. return CreateNode (GetNodeTypeFromString (nodeTypeString), name, namespaceURI);
  339. }
  340. public virtual XmlNode CreateNode (
  341. XmlNodeType type,
  342. string name,
  343. string namespaceURI)
  344. {
  345. string prefix = null;
  346. string localName = name;
  347. if ((type == XmlNodeType.Attribute) || (type == XmlNodeType.Element) || (type == XmlNodeType.EntityReference))
  348. ParseName (name, out prefix, out localName);
  349. return CreateNode (type, prefix, localName, namespaceURI);
  350. }
  351. public virtual XmlNode CreateNode (
  352. XmlNodeType type,
  353. string prefix,
  354. string name,
  355. string namespaceURI)
  356. {
  357. switch (type) {
  358. case XmlNodeType.Attribute: return CreateAttribute (prefix, name, namespaceURI);
  359. case XmlNodeType.CDATA: return CreateCDataSection (null);
  360. case XmlNodeType.Comment: return CreateComment (null);
  361. case XmlNodeType.Document: return new XmlDocument ();
  362. case XmlNodeType.DocumentFragment: return CreateDocumentFragment ();
  363. case XmlNodeType.DocumentType: return CreateDocumentType (null, null, null, null);
  364. case XmlNodeType.Element: return CreateElement (prefix, name, namespaceURI);
  365. case XmlNodeType.EntityReference: return CreateEntityReference (null);
  366. case XmlNodeType.ProcessingInstruction: return CreateProcessingInstruction (null, null);
  367. case XmlNodeType.SignificantWhitespace: return CreateSignificantWhitespace (String.Empty);
  368. case XmlNodeType.Text: return CreateTextNode (null);
  369. case XmlNodeType.Whitespace: return CreateWhitespace (String.Empty);
  370. case XmlNodeType.XmlDeclaration: return CreateXmlDeclaration ("1.0", null, null);
  371. default:
  372. #if NET_2_0
  373. throw new ArgumentException (
  374. #else // makes less sense
  375. throw new ArgumentOutOfRangeException (
  376. #endif
  377. String.Format("{0}\nParameter name: {1}",
  378. "Specified argument was out of the range of valid values", type.ToString ()));
  379. }
  380. }
  381. public virtual XmlProcessingInstruction CreateProcessingInstruction (
  382. string target,
  383. string data)
  384. {
  385. return new XmlProcessingInstruction (target, data, this);
  386. }
  387. public virtual XmlSignificantWhitespace CreateSignificantWhitespace (string text)
  388. {
  389. if (!XmlChar.IsWhitespace (text))
  390. throw new ArgumentException ("Invalid whitespace characters.");
  391. return new XmlSignificantWhitespace (text, this);
  392. }
  393. public virtual XmlText CreateTextNode (string text)
  394. {
  395. return new XmlText (text, this);
  396. }
  397. public virtual XmlWhitespace CreateWhitespace (string text)
  398. {
  399. if (!XmlChar.IsWhitespace (text))
  400. throw new ArgumentException ("Invalid whitespace characters.");
  401. return new XmlWhitespace (text, this);
  402. }
  403. public virtual XmlDeclaration CreateXmlDeclaration (string version, string encoding,
  404. string standalone)
  405. {
  406. if (version != "1.0")
  407. throw new ArgumentException ("version string is not correct.");
  408. if ((standalone != null && standalone != String.Empty) && !((standalone == "yes") || (standalone == "no")))
  409. throw new ArgumentException ("standalone string is not correct.");
  410. return new XmlDeclaration (version, encoding, standalone, this);
  411. }
  412. // FIXME: Currently XmlAttributeCollection.SetNamedItem() does
  413. // add to the identity table, but in fact I delayed identity
  414. // check on GetIdenticalAttribute. To make such way complete,
  415. // we have to use MultiMap, not Hashtable.
  416. //
  417. // Well, MS.NET is also fragile around here.
  418. public virtual XmlElement GetElementById (string elementId)
  419. {
  420. XmlAttribute attr = GetIdenticalAttribute (elementId);
  421. return attr != null ? attr.OwnerElement : null;
  422. }
  423. public virtual XmlNodeList GetElementsByTagName (string name)
  424. {
  425. ArrayList nodeArrayList = new ArrayList ();
  426. this.SearchDescendantElements (name, name == "*", nodeArrayList);
  427. return new XmlNodeArrayList (nodeArrayList);
  428. }
  429. public virtual XmlNodeList GetElementsByTagName (string localName, string namespaceURI)
  430. {
  431. ArrayList nodeArrayList = new ArrayList ();
  432. this.SearchDescendantElements (localName, localName == "*", namespaceURI, namespaceURI == "*", nodeArrayList);
  433. return new XmlNodeArrayList (nodeArrayList);
  434. }
  435. private XmlNodeType GetNodeTypeFromString (string nodeTypeString)
  436. {
  437. #if NET_2_0 // actually should be done in any version
  438. if (nodeTypeString == null)
  439. throw new ArgumentNullException ("nodeTypeString");
  440. #endif
  441. switch (nodeTypeString) {
  442. case "attribute": return XmlNodeType.Attribute;
  443. case "cdatasection": return XmlNodeType.CDATA;
  444. case "comment": return XmlNodeType.Comment;
  445. case "document": return XmlNodeType.Document;
  446. case "documentfragment": return XmlNodeType.DocumentFragment;
  447. case "documenttype": return XmlNodeType.DocumentType;
  448. case "element": return XmlNodeType.Element;
  449. case "entityreference": return XmlNodeType.EntityReference;
  450. case "processinginstruction": return XmlNodeType.ProcessingInstruction;
  451. case "significantwhitespace": return XmlNodeType.SignificantWhitespace;
  452. case "text": return XmlNodeType.Text;
  453. case "whitespace": return XmlNodeType.Whitespace;
  454. default:
  455. throw new ArgumentException(String.Format("The string doesn't represent any node type : {0}.", nodeTypeString));
  456. }
  457. }
  458. internal XmlAttribute GetIdenticalAttribute (string id)
  459. {
  460. XmlAttribute attr = this.idTable [id] as XmlAttribute;
  461. if (attr == null)
  462. return null;
  463. if (attr.OwnerElement == null || !attr.OwnerElement.IsRooted) {
  464. // idTable.Remove (id);
  465. return null;
  466. }
  467. return attr;
  468. }
  469. public virtual XmlNode ImportNode (XmlNode node, bool deep)
  470. {
  471. if (node == null)
  472. throw new NullReferenceException ("Null node cannot be imported.");
  473. switch (node.NodeType) {
  474. case XmlNodeType.Attribute:
  475. XmlAttribute srcAtt = node as XmlAttribute;
  476. XmlAttribute dstAtt = this.CreateAttribute (srcAtt.Prefix, srcAtt.LocalName, srcAtt.NamespaceURI);
  477. for (XmlNode n = srcAtt.FirstChild; n != null; n = n.NextSibling)
  478. dstAtt.AppendChild (this.ImportNode (n, deep));
  479. return dstAtt;
  480. case XmlNodeType.CDATA:
  481. return this.CreateCDataSection (node.Value);
  482. case XmlNodeType.Comment:
  483. return this.CreateComment (node.Value);
  484. case XmlNodeType.Document:
  485. throw new XmlException ("Document cannot be imported.");
  486. case XmlNodeType.DocumentFragment:
  487. XmlDocumentFragment df = this.CreateDocumentFragment ();
  488. if(deep)
  489. for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
  490. df.AppendChild (this.ImportNode (n, deep));
  491. return df;
  492. case XmlNodeType.DocumentType:
  493. throw new XmlException ("DocumentType cannot be imported.");
  494. case XmlNodeType.Element:
  495. XmlElement src = (XmlElement)node;
  496. XmlElement dst = this.CreateElement (src.Prefix, src.LocalName, src.NamespaceURI);
  497. for (int i = 0; i < src.Attributes.Count; i++) {
  498. XmlAttribute attr = src.Attributes [i];
  499. if(attr.Specified) // copies only specified attributes
  500. dst.SetAttributeNode ((XmlAttribute) this.ImportNode (attr, deep));
  501. }
  502. if(deep)
  503. for (XmlNode n = src.FirstChild; n != null; n = n.NextSibling)
  504. dst.AppendChild (this.ImportNode (n, deep));
  505. return dst;
  506. case XmlNodeType.EndElement:
  507. throw new XmlException ("Illegal ImportNode call for NodeType.EndElement");
  508. case XmlNodeType.EndEntity:
  509. throw new XmlException ("Illegal ImportNode call for NodeType.EndEntity");
  510. case XmlNodeType.EntityReference:
  511. return this.CreateEntityReference (node.Name);
  512. case XmlNodeType.None:
  513. throw new XmlException ("Illegal ImportNode call for NodeType.None");
  514. case XmlNodeType.ProcessingInstruction:
  515. XmlProcessingInstruction pi = node as XmlProcessingInstruction;
  516. return this.CreateProcessingInstruction (pi.Target, pi.Data);
  517. case XmlNodeType.SignificantWhitespace:
  518. return this.CreateSignificantWhitespace (node.Value);
  519. case XmlNodeType.Text:
  520. return this.CreateTextNode (node.Value);
  521. case XmlNodeType.Whitespace:
  522. return this.CreateWhitespace (node.Value);
  523. case XmlNodeType.XmlDeclaration:
  524. XmlDeclaration srcDecl = node as XmlDeclaration;
  525. return this.CreateXmlDeclaration (srcDecl.Version, srcDecl.Encoding, srcDecl.Standalone);
  526. default:
  527. throw new InvalidOperationException ("Cannot import specified node type: " + node.NodeType);
  528. }
  529. }
  530. public virtual void Load (Stream inStream)
  531. {
  532. XmlTextReader reader = new XmlTextReader (inStream, NameTable);
  533. reader.XmlResolver = resolver;
  534. Load (reader);
  535. }
  536. public virtual void Load (string filename)
  537. {
  538. XmlTextReader xr = null;
  539. try {
  540. xr = new XmlTextReader (filename, NameTable);
  541. xr.XmlResolver = resolver;
  542. Load (xr);
  543. } finally {
  544. if (xr != null)
  545. xr.Close ();
  546. }
  547. }
  548. public virtual void Load (TextReader txtReader)
  549. {
  550. XmlTextReader xr = new XmlTextReader (txtReader, NameTable);
  551. xr.XmlResolver = resolver;
  552. Load (xr);
  553. }
  554. public virtual void Load (XmlReader xmlReader)
  555. {
  556. // Reset our document
  557. // For now this just means removing all our children but later this
  558. // may turn out o need to call a private method that resets other things
  559. // like properties we have, etc.
  560. RemoveAll ();
  561. this.baseURI = xmlReader.BaseURI;
  562. // create all contents with use of ReadNode()
  563. try {
  564. loadMode = true;
  565. do {
  566. XmlNode n = ReadNode (xmlReader);
  567. if (n == null)
  568. break;
  569. if (preserveWhitespace || n.NodeType != XmlNodeType.Whitespace)
  570. AppendChild (n, false);
  571. } while (true);
  572. #if NET_2_0
  573. if (xmlReader.Settings != null)
  574. schemas = xmlReader.Settings.Schemas;
  575. #endif
  576. } finally {
  577. loadMode = false;
  578. }
  579. }
  580. public virtual void LoadXml (string xml)
  581. {
  582. XmlTextReader xmlReader = new XmlTextReader (
  583. xml,
  584. XmlNodeType.Document,
  585. new XmlParserContext (NameTable, null, null, XmlSpace.None));
  586. try {
  587. xmlReader.XmlResolver = resolver;
  588. Load (xmlReader);
  589. } finally {
  590. xmlReader.Close ();
  591. }
  592. }
  593. internal void onNodeChanged (XmlNode node, XmlNode parent, string oldValue, string newValue)
  594. {
  595. if (NodeChanged != null)
  596. NodeChanged (node, new XmlNodeChangedEventArgs
  597. (node, parent, parent, oldValue, newValue, XmlNodeChangedAction.Change));
  598. }
  599. internal void onNodeChanging(XmlNode node, XmlNode parent, string oldValue, string newValue)
  600. {
  601. if (node.IsReadOnly)
  602. throw new ArgumentException ("Node is read-only.");
  603. if (NodeChanging != null)
  604. NodeChanging (node, new XmlNodeChangedEventArgs
  605. (node, parent, parent, oldValue, newValue, XmlNodeChangedAction.Change));
  606. }
  607. internal void onNodeInserted (XmlNode node, XmlNode newParent)
  608. {
  609. if (NodeInserted != null)
  610. NodeInserted (node, new XmlNodeChangedEventArgs
  611. (node, null, newParent, null, null, XmlNodeChangedAction.Insert));
  612. }
  613. internal void onNodeInserting (XmlNode node, XmlNode newParent)
  614. {
  615. if (NodeInserting != null)
  616. NodeInserting (node, new XmlNodeChangedEventArgs
  617. (node, null, newParent, null, null, XmlNodeChangedAction.Insert));
  618. }
  619. internal void onNodeRemoved (XmlNode node, XmlNode oldParent)
  620. {
  621. if (NodeRemoved != null)
  622. NodeRemoved (node, new XmlNodeChangedEventArgs
  623. (node, oldParent, null, null, null, XmlNodeChangedAction.Remove));
  624. }
  625. internal void onNodeRemoving (XmlNode node, XmlNode oldParent)
  626. {
  627. if (NodeRemoving != null)
  628. NodeRemoving (node, new XmlNodeChangedEventArgs
  629. (node, oldParent, null, null, null, XmlNodeChangedAction.Remove));
  630. }
  631. private void ParseName (string name, out string prefix, out string localName)
  632. {
  633. int indexOfColon = name.IndexOf (':');
  634. if (indexOfColon != -1) {
  635. prefix = name.Substring (0, indexOfColon);
  636. localName = name.Substring (indexOfColon + 1);
  637. } else {
  638. prefix = "";
  639. localName = name;
  640. }
  641. }
  642. // Reads XmlReader and creates Attribute Node.
  643. private XmlAttribute ReadAttributeNode (XmlReader reader)
  644. {
  645. if (reader.NodeType == XmlNodeType.Element)
  646. reader.MoveToFirstAttribute ();
  647. else if (reader.NodeType != XmlNodeType.Attribute)
  648. throw new InvalidOperationException (MakeReaderErrorMessage ("bad position to read attribute.", reader));
  649. XmlAttribute attribute = CreateAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI, false, false); // different NameTable
  650. #if NET_2_0
  651. if (reader.SchemaInfo != null)
  652. SchemaInfo = new XmlSchemaInfo (reader.SchemaInfo);
  653. #endif
  654. bool isDefault = reader.IsDefault;
  655. ReadAttributeNodeValue (reader, attribute);
  656. if (isDefault)
  657. attribute.SetDefault ();
  658. return attribute;
  659. }
  660. // Reads attribute from XmlReader and then creates attribute value children. XmlAttribute also uses this.
  661. internal void ReadAttributeNodeValue (XmlReader reader, XmlAttribute attribute)
  662. {
  663. while (reader.ReadAttributeValue ()) {
  664. if (reader.NodeType == XmlNodeType.EntityReference)
  665. attribute.AppendChild (CreateEntityReference (reader.Name), false); // omit node type check
  666. else
  667. // Children of Attribute is restricted to CharacterData and EntityReference (Comment is not allowed).
  668. attribute.AppendChild (CreateTextNode (reader.Value), false); // omit node type check
  669. }
  670. }
  671. [PermissionSet (SecurityAction.InheritanceDemand, Unrestricted = true)]
  672. public virtual XmlNode ReadNode (XmlReader reader)
  673. {
  674. if (PreserveWhitespace)
  675. return ReadNodeCore (reader);
  676. XmlTextReader xtr = reader as XmlTextReader;
  677. if (xtr != null && xtr.WhitespaceHandling ==
  678. WhitespaceHandling.All) {
  679. try {
  680. xtr.WhitespaceHandling = WhitespaceHandling.Significant;
  681. return ReadNodeCore (reader);
  682. } finally {
  683. xtr.WhitespaceHandling = WhitespaceHandling.All;
  684. }
  685. }
  686. else
  687. return ReadNodeCore (reader);
  688. }
  689. public virtual XmlNode ReadNodeCore (XmlReader reader)
  690. {
  691. switch (reader.ReadState) {
  692. case ReadState.Interactive:
  693. break;
  694. case ReadState.Initial:
  695. #if NET_2_0
  696. if (reader.SchemaInfo != null)
  697. this.SchemaInfo = new XmlSchemaInfo (reader.SchemaInfo);
  698. #endif
  699. reader.Read ();
  700. break;
  701. default:
  702. return null;
  703. }
  704. XmlNode n;
  705. switch (reader.NodeType) {
  706. case XmlNodeType.Attribute:
  707. string localName = reader.LocalName;
  708. string ns = reader.NamespaceURI;
  709. n = ReadAttributeNode (reader);
  710. // Keep the current reader position on attribute.
  711. reader.MoveToAttribute (localName, ns);
  712. return n;
  713. case XmlNodeType.CDATA:
  714. n = CreateCDataSection (reader.Value);
  715. break;
  716. case XmlNodeType.Comment:
  717. n = CreateComment (reader.Value);
  718. break;
  719. case XmlNodeType.Element:
  720. XmlElement element = CreateElement (reader.Prefix, reader.LocalName, reader.NamespaceURI);
  721. #if NET_2_0
  722. if (reader.SchemaInfo != null)
  723. SchemaInfo = new XmlSchemaInfo (reader.SchemaInfo);
  724. #endif
  725. element.IsEmpty = reader.IsEmptyElement;
  726. // set the element's attributes.
  727. for (int i = 0; i < reader.AttributeCount; i++) {
  728. reader.MoveToAttribute (i);
  729. element.SetAttributeNode (
  730. ReadAttributeNode (reader));
  731. }
  732. // FIXME: the code below should be fine and
  733. // in some XmlReaders it is much faster, but
  734. // caused some breakage in sys.data test.
  735. /*
  736. if (reader.MoveToFirstAttribute ()) {
  737. do {
  738. element.SetAttributeNode (ReadAttributeNode (reader));
  739. } while (reader.MoveToNextAttribute ());
  740. reader.MoveToElement ();
  741. }
  742. */
  743. reader.MoveToElement ();
  744. int depth = reader.Depth;
  745. if (reader.IsEmptyElement) {
  746. n = element;
  747. break;
  748. }
  749. reader.Read ();
  750. while (reader.Depth > depth) {
  751. n = ReadNodeCore (reader);
  752. if (preserveWhitespace || n.NodeType != XmlNodeType.Whitespace)
  753. element.AppendChild (n, false);
  754. }
  755. n = element;
  756. break;
  757. case XmlNodeType.ProcessingInstruction:
  758. n = CreateProcessingInstruction (reader.Name, reader.Value);
  759. break;
  760. case XmlNodeType.Text:
  761. n = CreateTextNode (reader.Value);
  762. break;
  763. case XmlNodeType.XmlDeclaration:
  764. n = CreateXmlDeclaration ("1.0" , String.Empty, String.Empty);
  765. n.Value = reader.Value;
  766. break;
  767. case XmlNodeType.DocumentType:
  768. DTDObjectModel dtd = null;
  769. IHasXmlParserContext ctxReader = reader as IHasXmlParserContext;
  770. if (ctxReader != null)
  771. dtd = ctxReader.ParserContext.Dtd;
  772. if (dtd != null)
  773. n = CreateDocumentType (dtd);
  774. else
  775. n = CreateDocumentType (reader.Name, reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
  776. break;
  777. case XmlNodeType.EntityReference:
  778. if (this.loadMode && this.DocumentType != null &&
  779. DocumentType.Entities.GetNamedItem (reader.Name) == null)
  780. throw new XmlException ("Reference to undeclared entity was found.");
  781. n = CreateEntityReference (reader.Name);
  782. // IF argument XmlReader can resolve entity,
  783. // ReadNode() also fills children _from it_.
  784. // In this case, it is not from doctype node.
  785. // (it is kind of sucky design, but it happens
  786. // anyways when we modify doctype node).
  787. //
  788. // It does not happen when !CanResolveEntity.
  789. // (In such case AppendChild() will resolve
  790. // entity content, as XmlEntityReference does.)
  791. if (reader.CanResolveEntity)
  792. {
  793. reader.ResolveEntity ();
  794. reader.Read ();
  795. for (XmlNode child; reader.NodeType != XmlNodeType.EndEntity && (child = ReadNode (reader)) != null;)
  796. n.InsertBefore (child, null, false, false);
  797. }
  798. break;
  799. case XmlNodeType.SignificantWhitespace:
  800. n = CreateSignificantWhitespace (reader.Value);
  801. break;
  802. case XmlNodeType.Whitespace:
  803. n = CreateWhitespace (reader.Value);
  804. break;
  805. case XmlNodeType.None:
  806. return null;
  807. default:
  808. // No idea why MS does throw NullReferenceException ;-P
  809. throw new NullReferenceException ("Unexpected node type " + reader.NodeType + ".");
  810. }
  811. reader.Read ();
  812. return n;
  813. }
  814. private string MakeReaderErrorMessage (string message, XmlReader reader)
  815. {
  816. IXmlLineInfo li = reader as IXmlLineInfo;
  817. if (li != null)
  818. return String.Format (CultureInfo.InvariantCulture, "{0} Line number = {1}, Inline position = {2}.", message, li.LineNumber, li.LinePosition);
  819. else
  820. return message;
  821. }
  822. internal void RemoveIdenticalAttribute (string id)
  823. {
  824. idTable.Remove (id);
  825. }
  826. public virtual void Save (Stream outStream)
  827. {
  828. XmlTextWriter xmlWriter = new XmlTextWriter (outStream, TextEncoding);
  829. if (!PreserveWhitespace)
  830. xmlWriter.Formatting = Formatting.Indented;
  831. WriteContentTo (xmlWriter);
  832. xmlWriter.Flush ();
  833. }
  834. public virtual void Save (string filename)
  835. {
  836. XmlTextWriter xmlWriter = new XmlTextWriter (filename, TextEncoding);
  837. try {
  838. if (!PreserveWhitespace)
  839. xmlWriter.Formatting = Formatting.Indented;
  840. WriteContentTo (xmlWriter);
  841. } finally {
  842. xmlWriter.Close ();
  843. }
  844. }
  845. public virtual void Save (TextWriter writer)
  846. {
  847. XmlTextWriter xmlWriter = new XmlTextWriter (writer);
  848. if (!PreserveWhitespace)
  849. xmlWriter.Formatting = Formatting.Indented;
  850. if (FirstChild != null && FirstChild.NodeType != XmlNodeType.XmlDeclaration)
  851. xmlWriter.WriteStartDocument ();
  852. WriteContentTo (xmlWriter);
  853. xmlWriter.WriteEndDocument ();
  854. xmlWriter.Flush ();
  855. }
  856. public virtual void Save (XmlWriter xmlWriter)
  857. {
  858. //
  859. // This should preserve white space if PreserveWhiteSpace is true
  860. //
  861. bool autoXmlDecl = FirstChild != null && FirstChild.NodeType != XmlNodeType.XmlDeclaration;
  862. if (autoXmlDecl)
  863. xmlWriter.WriteStartDocument ();
  864. WriteContentTo (xmlWriter);
  865. if (autoXmlDecl)
  866. xmlWriter.WriteEndDocument ();
  867. xmlWriter.Flush ();
  868. }
  869. public override void WriteContentTo (XmlWriter w)
  870. {
  871. for (XmlNode n = FirstChild; n != null; n = n.NextSibling)
  872. n.WriteTo (w);
  873. }
  874. public override void WriteTo (XmlWriter w)
  875. {
  876. WriteContentTo (w);
  877. }
  878. private void AddDefaultNameTableKeys ()
  879. {
  880. // The following keys are default of MS .NET Framework
  881. nameTable.Add ("#text");
  882. nameTable.Add ("xml");
  883. nameTable.Add ("xmlns");
  884. nameTable.Add ("#entity");
  885. nameTable.Add ("#document-fragment");
  886. nameTable.Add ("#comment");
  887. nameTable.Add ("space");
  888. nameTable.Add ("id");
  889. nameTable.Add ("#whitespace");
  890. nameTable.Add ("http://www.w3.org/2000/xmlns/");
  891. nameTable.Add ("#cdata-section");
  892. nameTable.Add ("lang");
  893. nameTable.Add ("#document");
  894. nameTable.Add ("#significant-whitespace");
  895. }
  896. internal void CheckIdTableUpdate (XmlAttribute attr, string oldValue, string newValue)
  897. {
  898. if (idTable [oldValue] == attr) {
  899. idTable.Remove (oldValue);
  900. idTable [newValue] = attr;
  901. }
  902. }
  903. #if NET_2_0
  904. public void Validate (ValidationEventHandler handler)
  905. {
  906. Validate (handler, this,
  907. XmlSchemaValidationFlags.ProcessIdentityConstraints);
  908. }
  909. public void Validate (ValidationEventHandler handler,
  910. XmlNode node)
  911. {
  912. Validate (handler, node,
  913. XmlSchemaValidationFlags.ProcessIdentityConstraints);
  914. }
  915. private void Validate (ValidationEventHandler handler,
  916. XmlNode node, XmlSchemaValidationFlags flags)
  917. {
  918. XmlReaderSettings settings = new XmlReaderSettings ();
  919. settings.NameTable = NameTable;
  920. settings.Schemas = schemas;
  921. settings.Schemas.XmlResolver = resolver;
  922. settings.XmlResolver = resolver;
  923. settings.ValidationFlags = flags;
  924. settings.ValidationType = ValidationType.Schema;
  925. XmlReader r = XmlReader.Create (
  926. new XmlNodeReader (node), settings);
  927. while (!r.EOF)
  928. r.Read ();
  929. }
  930. #endif
  931. #endregion
  932. }
  933. }