XmlDocument.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  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. //
  11. // (C) 2001 Daniel Weber
  12. // (C) 2002 Kral Ferch, Jason Diamond, Miguel de Icaza, Duncan Mak
  13. //
  14. using System;
  15. using System.IO;
  16. using System.Text;
  17. using System.Xml.XPath;
  18. using System.Diagnostics;
  19. namespace System.Xml
  20. {
  21. public class XmlDocument : XmlNode
  22. {
  23. #region Fields
  24. XmlLinkedNode lastLinkedChild;
  25. XmlNameTable nameTable;
  26. string baseURI = String.Empty;
  27. #endregion
  28. #region Constructors
  29. public XmlDocument () : base (null) { }
  30. [MonoTODO]
  31. protected internal XmlDocument (XmlImplementation imp) : base (null)
  32. {
  33. throw new NotImplementedException ();
  34. }
  35. public XmlDocument (XmlNameTable nt) : base (null)
  36. {
  37. nameTable = nt;
  38. }
  39. #endregion
  40. #region Events
  41. public event XmlNodeChangedEventHandler NodeChanged;
  42. public event XmlNodeChangedEventHandler NodeChanging;
  43. public event XmlNodeChangedEventHandler NodeInserted;
  44. public event XmlNodeChangedEventHandler NodeInserting;
  45. public event XmlNodeChangedEventHandler NodeRemoved;
  46. public event XmlNodeChangedEventHandler NodeRemoving;
  47. #endregion
  48. #region Properties
  49. public override string BaseURI {
  50. get {
  51. return baseURI;
  52. }
  53. }
  54. public XmlElement DocumentElement {
  55. get {
  56. XmlNode node = FirstChild;
  57. while (node != null) {
  58. if (node is XmlElement)
  59. break;
  60. node = node.NextSibling;
  61. }
  62. return node != null ? node as XmlElement : null;
  63. }
  64. }
  65. [MonoTODO]
  66. public virtual XmlDocumentType DocumentType {
  67. get { throw new NotImplementedException(); }
  68. }
  69. [MonoTODO]
  70. public XmlImplementation Implementation {
  71. get { throw new NotImplementedException(); }
  72. }
  73. [MonoTODO ("Setter.")]
  74. public override string InnerXml {
  75. get {
  76. // Not sure why this is an override. Passing through for now.
  77. return base.InnerXml;
  78. }
  79. set { throw new NotImplementedException(); }
  80. }
  81. public override bool IsReadOnly {
  82. get { return false; }
  83. }
  84. internal override XmlLinkedNode LastLinkedChild {
  85. get {
  86. return lastLinkedChild;
  87. }
  88. set {
  89. lastLinkedChild = value;
  90. }
  91. }
  92. public override string LocalName {
  93. get { return "#document"; }
  94. }
  95. public override string Name {
  96. get { return "#document"; }
  97. }
  98. public XmlNameTable NameTable {
  99. get { return nameTable; }
  100. }
  101. public override XmlNodeType NodeType {
  102. get { return XmlNodeType.Document; }
  103. }
  104. public override XmlDocument OwnerDocument {
  105. get { return null; }
  106. }
  107. [MonoTODO]
  108. public bool PreserveWhitespace {
  109. get { throw new NotImplementedException(); }
  110. set { throw new NotImplementedException(); }
  111. }
  112. [MonoTODO]
  113. public virtual XmlResolver XmlResolver {
  114. set { throw new NotImplementedException(); }
  115. }
  116. #endregion
  117. #region Methods
  118. [MonoTODO]
  119. public override XmlNode CloneNode (bool deep)
  120. {
  121. throw new NotImplementedException ();
  122. }
  123. public XmlAttribute CreateAttribute (string name)
  124. {
  125. return CreateAttribute (name, String.Empty);
  126. }
  127. public XmlAttribute CreateAttribute (string qualifiedName, string namespaceURI)
  128. {
  129. string prefix;
  130. string localName;
  131. ParseName (qualifiedName, out prefix, out localName);
  132. return CreateAttribute (prefix, localName, namespaceURI);
  133. }
  134. public virtual XmlAttribute CreateAttribute (string prefix, string localName, string namespaceURI)
  135. {
  136. if ((localName == null) || (localName == String.Empty))
  137. throw new ArgumentException ("The attribute local name cannot be empty.");
  138. return new XmlAttribute (prefix, localName, namespaceURI, this);
  139. }
  140. public virtual XmlCDataSection CreateCDataSection (string data)
  141. {
  142. return new XmlCDataSection (data, this);
  143. }
  144. public virtual XmlComment CreateComment (string data)
  145. {
  146. return new XmlComment(data, this);
  147. }
  148. [MonoTODO]
  149. protected internal virtual XmlAttribute CreateDefaultAttribute (string prefix, string localName, string namespaceURI)
  150. {
  151. throw new NotImplementedException ();
  152. }
  153. [MonoTODO]
  154. public virtual XmlDocumentFragment CreateDocumentFragment ()
  155. {
  156. throw new NotImplementedException ();
  157. }
  158. public virtual XmlDocumentType CreateDocumentType (string name, string publicId,
  159. string systemId, string internalSubset)
  160. {
  161. return new XmlDocumentType (name, publicId, systemId, internalSubset, this);
  162. }
  163. public XmlElement CreateElement (string name)
  164. {
  165. return CreateElement (name, String.Empty);
  166. }
  167. public XmlElement CreateElement (
  168. string qualifiedName,
  169. string namespaceURI)
  170. {
  171. string prefix;
  172. string localName;
  173. ParseName (qualifiedName, out prefix, out localName);
  174. return CreateElement (prefix, localName, namespaceURI);
  175. }
  176. public virtual XmlElement CreateElement (
  177. string prefix,
  178. string localName,
  179. string namespaceURI)
  180. {
  181. if ((localName == null) || (localName == String.Empty))
  182. throw new ArgumentException ("The local name for elements or attributes cannot be null or an empty string.");
  183. return new XmlElement (prefix != null ? prefix : String.Empty, localName, namespaceURI != null ? namespaceURI : String.Empty, this);
  184. }
  185. [MonoTODO]
  186. public virtual XmlEntityReference CreateEntityReference (string name)
  187. {
  188. throw new NotImplementedException ();
  189. }
  190. public virtual XmlNode CreateNode (
  191. string nodeTypeString,
  192. string name,
  193. string namespaceURI)
  194. {
  195. return CreateNode (GetNodeTypeFromString (nodeTypeString), name, namespaceURI);
  196. }
  197. public virtual XmlNode CreateNode (
  198. XmlNodeType type,
  199. string name,
  200. string namespaceURI)
  201. {
  202. string prefix = null;
  203. string localName = name;
  204. if ((type == XmlNodeType.Attribute) || (type == XmlNodeType.Element) || (type == XmlNodeType.EntityReference))
  205. ParseName (name, out prefix, out localName);
  206. return CreateNode (type, prefix, localName, namespaceURI);
  207. }
  208. public virtual XmlNode CreateNode (
  209. XmlNodeType type,
  210. string prefix,
  211. string name,
  212. string namespaceURI)
  213. {
  214. switch (type) {
  215. case XmlNodeType.Attribute: return CreateAttribute (prefix, name, namespaceURI);
  216. case XmlNodeType.CDATA: return CreateCDataSection (null);
  217. case XmlNodeType.Comment: return CreateComment (null);
  218. case XmlNodeType.Document: return new XmlDocument (); // TODO - test to see which constructor to use, i.e. use existing NameTable or not.
  219. case XmlNodeType.DocumentFragment: return CreateDocumentFragment ();
  220. case XmlNodeType.DocumentType: return CreateDocumentType (null, null, null, null);
  221. case XmlNodeType.Element: return CreateElement (prefix, name, namespaceURI);
  222. case XmlNodeType.EntityReference: return CreateEntityReference (null);
  223. case XmlNodeType.ProcessingInstruction: return CreateProcessingInstruction (null, null);
  224. case XmlNodeType.SignificantWhitespace: return CreateSignificantWhitespace (String.Empty);
  225. case XmlNodeType.Text: return CreateTextNode (null);
  226. case XmlNodeType.Whitespace: return CreateWhitespace (String.Empty);
  227. case XmlNodeType.XmlDeclaration: return CreateXmlDeclaration ("1.0", null, null);
  228. default: throw new ArgumentOutOfRangeException(String.Format("{0}\nParameter name: {1}",
  229. "Specified argument was out of the range of valid values", type.ToString ()));
  230. }
  231. }
  232. public virtual XmlProcessingInstruction CreateProcessingInstruction (
  233. string target,
  234. string data)
  235. {
  236. return new XmlProcessingInstruction (target, data, this);
  237. }
  238. public virtual XmlSignificantWhitespace CreateSignificantWhitespace (string text)
  239. {
  240. foreach (char c in text)
  241. if ((c != ' ') && (c != '\r') && (c != '\n') && (c != '\t'))
  242. throw new ArgumentException ("Invalid whitespace characters.");
  243. return new XmlSignificantWhitespace (text, this);
  244. }
  245. public virtual XmlText CreateTextNode (string text)
  246. {
  247. return new XmlText (text, this);
  248. }
  249. public virtual XmlWhitespace CreateWhitespace (string text)
  250. {
  251. foreach (char c in text)
  252. if ((c != ' ') && (c != '\r') && (c != '\n') && (c != '\t'))
  253. throw new ArgumentException ("Invalid whitespace characters.");
  254. return new XmlWhitespace (text, this);
  255. }
  256. public virtual XmlDeclaration CreateXmlDeclaration (string version, string encoding,
  257. string standalone)
  258. {
  259. if (version != "1.0")
  260. throw new ArgumentException ("version string is not correct.");
  261. if ((standalone != null) && !((standalone == "yes") || (standalone == "no")))
  262. throw new ArgumentException ("standalone string is not correct.");
  263. return new XmlDeclaration (version, encoding, standalone, this);
  264. }
  265. [MonoTODO]
  266. public virtual XmlElement GetElementById (string elementId)
  267. {
  268. throw new NotImplementedException ();
  269. }
  270. [MonoTODO]
  271. public virtual XmlNodeList GetElementsByTagName (string name)
  272. {
  273. throw new NotImplementedException ();
  274. }
  275. [MonoTODO]
  276. public virtual XmlNodeList GetElementsByTagName (string localName, string namespaceURI)
  277. {
  278. throw new NotImplementedException();
  279. }
  280. private XmlNodeType GetNodeTypeFromString (string nodeTypeString)
  281. {
  282. switch (nodeTypeString) {
  283. case "attribute": return XmlNodeType.Attribute;
  284. case "cdatasection": return XmlNodeType.CDATA;
  285. case "comment": return XmlNodeType.Comment;
  286. case "document": return XmlNodeType.Document;
  287. case "documentfragment": return XmlNodeType.DocumentFragment;
  288. case "documenttype": return XmlNodeType.DocumentType;
  289. case "element": return XmlNodeType.Element;
  290. case "entityreference": return XmlNodeType.EntityReference;
  291. case "processinginstruction": return XmlNodeType.ProcessingInstruction;
  292. case "significantwhitespace": return XmlNodeType.SignificantWhitespace;
  293. case "text": return XmlNodeType.Text;
  294. case "whitespace": return XmlNodeType.Whitespace;
  295. default:
  296. throw new ArgumentException(String.Format("The string doesn't represent any node type : {0}.", nodeTypeString));
  297. }
  298. }
  299. [MonoTODO]
  300. public virtual XmlNode ImportNode (XmlNode node, bool deep)
  301. {
  302. throw new NotImplementedException ();
  303. }
  304. [MonoTODO]
  305. public virtual void Load (Stream inStream)
  306. {
  307. throw new NotImplementedException ();
  308. }
  309. public virtual void Load (string filename)
  310. {
  311. baseURI = filename;
  312. XmlReader xmlReader = new XmlTextReader (new StreamReader (filename));
  313. Load (xmlReader);
  314. }
  315. [MonoTODO]
  316. public virtual void Load (TextReader txtReader)
  317. {
  318. throw new NotImplementedException ();
  319. }
  320. public virtual void Load (XmlReader xmlReader)
  321. {
  322. // Reset our document
  323. // For now this just means removing all our children but later this
  324. // may turn out o need to call a private method that resets other things
  325. // like properties we have, etc.
  326. RemoveAll ();
  327. XmlNode currentNode = this;
  328. XmlNode newNode;
  329. while (xmlReader.Read ())
  330. {
  331. switch (xmlReader.NodeType) {
  332. case XmlNodeType.CDATA:
  333. newNode = CreateCDataSection(xmlReader.Value);
  334. currentNode.AppendChild (newNode);
  335. break;
  336. case XmlNodeType.Comment:
  337. newNode = CreateComment (xmlReader.Value);
  338. currentNode.AppendChild (newNode);
  339. break;
  340. case XmlNodeType.Element:
  341. XmlElement element = CreateElement (xmlReader.Prefix, xmlReader.LocalName, xmlReader.NamespaceURI);
  342. currentNode.AppendChild (element);
  343. // set the element's attributes.
  344. while (xmlReader.MoveToNextAttribute ()) {
  345. XmlAttribute attribute = CreateAttribute (xmlReader.Prefix, xmlReader.LocalName, xmlReader.NamespaceURI);
  346. attribute.Value = xmlReader.Value;
  347. element.SetAttributeNode (attribute);
  348. }
  349. xmlReader.MoveToElement ();
  350. // if this element isn't empty, push it onto our "stack".
  351. if (!xmlReader.IsEmptyElement)
  352. currentNode = element;
  353. break;
  354. case XmlNodeType.EndElement:
  355. currentNode = currentNode.ParentNode;
  356. break;
  357. case XmlNodeType.ProcessingInstruction:
  358. newNode = CreateProcessingInstruction (xmlReader.Name, xmlReader.Value);
  359. currentNode.AppendChild (newNode);
  360. break;
  361. case XmlNodeType.Text:
  362. newNode = CreateTextNode (xmlReader.Value);
  363. currentNode.AppendChild (newNode);
  364. break;
  365. }
  366. }
  367. }
  368. public virtual void LoadXml (string xml)
  369. {
  370. XmlReader xmlReader = new XmlTextReader (new StringReader (xml));
  371. Load (xmlReader);
  372. }
  373. internal void onNodeChanged (XmlNode node, XmlNode Parent)
  374. {
  375. if (NodeChanged != null)
  376. NodeInserted (node, new XmlNodeChangedEventArgs
  377. (XmlNodeChangedAction.Change,
  378. node, Parent, Parent));
  379. }
  380. internal void onNodeChanging(XmlNode node, XmlNode Parent)
  381. {
  382. if (NodeInserting != null)
  383. NodeChanging (node, new XmlNodeChangedEventArgs
  384. (XmlNodeChangedAction.Change,
  385. node, Parent, Parent));
  386. }
  387. internal void onNodeInserted (XmlNode node, XmlNode newParent)
  388. {
  389. if (NodeInserted != null)
  390. NodeInserted (node, new XmlNodeChangedEventArgs
  391. (XmlNodeChangedAction.Insert,
  392. node, null, newParent));
  393. }
  394. internal void onNodeInserting (XmlNode node, XmlNode newParent)
  395. {
  396. if (NodeInserting != null)
  397. NodeInserting (node, new XmlNodeChangedEventArgs
  398. (XmlNodeChangedAction.Insert,
  399. node, null, newParent));
  400. }
  401. internal void onNodeRemoved (XmlNode node, XmlNode oldParent)
  402. {
  403. if (NodeRemoved != null)
  404. NodeRemoved (node, new XmlNodeChangedEventArgs
  405. (XmlNodeChangedAction.Remove,
  406. node, oldParent, null));
  407. }
  408. internal void onNodeRemoving (XmlNode node, XmlNode oldParent)
  409. {
  410. if (NodeRemoving != null)
  411. NodeRemoving (node, new XmlNodeChangedEventArgs
  412. (XmlNodeChangedAction.Remove,
  413. node, oldParent, null));
  414. }
  415. private void ParseName (string name, out string prefix, out string localName)
  416. {
  417. int indexOfColon = name.IndexOf (':');
  418. if (indexOfColon != -1) {
  419. prefix = name.Substring (0, indexOfColon);
  420. localName = name.Substring (indexOfColon + 1);
  421. } else {
  422. prefix = "";
  423. localName = name;
  424. }
  425. }
  426. [MonoTODO]
  427. public virtual XmlNode ReadNode(XmlReader reader)
  428. {
  429. throw new NotImplementedException ();
  430. }
  431. [MonoTODO ("Verify what encoding is used by default; Should use PreserveWhiteSpace")]
  432. public virtual void Save(Stream outStream)
  433. {
  434. XmlTextWriter xmlWriter = new XmlTextWriter (outStream, Encoding.UTF8);
  435. WriteContentTo (xmlWriter);
  436. xmlWriter.Close ();
  437. }
  438. [MonoTODO ("Verify what encoding is used by default; Should use PreseveWhiteSpace")]
  439. public virtual void Save (string filename)
  440. {
  441. XmlTextWriter xmlWriter = new XmlTextWriter (filename, Encoding.UTF8);
  442. WriteContentTo (xmlWriter);
  443. xmlWriter.Close ();
  444. }
  445. [MonoTODO]
  446. public virtual void Save (TextWriter writer)
  447. {
  448. XmlTextWriter xmlWriter = new XmlTextWriter (writer);
  449. WriteContentTo (xmlWriter);
  450. xmlWriter.Flush ();
  451. }
  452. [MonoTODO ("Should preserve white space if PreserveWhisspace is set")]
  453. public virtual void Save (XmlWriter xmlWriter)
  454. {
  455. //
  456. // This should preserve white space if PreserveWhiteSpace is true
  457. //
  458. WriteContentTo (xmlWriter);
  459. xmlWriter.Flush ();
  460. }
  461. public override void WriteContentTo (XmlWriter w)
  462. {
  463. foreach(XmlNode childNode in ChildNodes)
  464. childNode.WriteTo(w);
  465. }
  466. public override void WriteTo (XmlWriter w)
  467. {
  468. WriteContentTo(w);
  469. }
  470. #endregion
  471. }
  472. }