XPathDocument2.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. //
  2. // Mono.Xml.XPath.XPathDocument2.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // (C)2004 Novell Inc.
  8. //
  9. // Another Document tree model.
  10. //
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. #if NET_2_0
  32. using System;
  33. using System.Collections;
  34. using System.Collections.Specialized;
  35. using System.IO;
  36. using System.Text;
  37. using System.Xml;
  38. using System.Xml.XPath;
  39. namespace Mono.Xml.XPath
  40. {
  41. /*
  42. public class Driver
  43. {
  44. public static void Main ()
  45. {
  46. try {
  47. DateTime start = DateTime.Now;
  48. Console.WriteLine (DateTime.Now.Ticks);
  49. #if false
  50. XmlDocument doc = new XmlDocument ();
  51. doc.PreserveWhitespace = true;
  52. doc.Load (new XmlTextReader ("../TestResult.xml"));
  53. #else
  54. XPathDocument2 doc = new XPathDocument2 ();
  55. doc.Load (new XmlTextReader ("../TestResult.xml"));
  56. // XPathDocument doc = new XPathDocument ("../TestResult.xml", XmlSpace.Preserve);
  57. // XPathDocument doc = new XPathDocument ("test.xml", XmlSpace.Preserve);
  58. #endif
  59. // doc.Load (new XmlTextReader ("test.xml"));
  60. // doc.WriteTo (new XmlTextWriter (Console.Out));
  61. //return;
  62. Console.WriteLine (DateTime.Now.Ticks);
  63. XPathNavigator nav = doc.CreateNavigator ();
  64. //Console.WriteLine (nav.MoveToFirstChild ());
  65. //Console.WriteLine (nav.LocalName + nav.NodeType);
  66. //Console.WriteLine (nav.MoveToNext ());
  67. //Console.WriteLine (nav.LocalName + nav.NodeType);
  68. //Console.WriteLine (nav.MoveToNext ());
  69. //Console.WriteLine (nav.LocalName + nav.NodeType);
  70. //Console.WriteLine (nav.MoveToNext ());
  71. //Console.WriteLine (nav.LocalName + nav.NodeType);
  72. //nav.MoveToRoot ();
  73. XmlReader reader = nav.ReadSubtree ();
  74. XmlTextWriter w = new XmlTextWriter (new StringWriter ());
  75. // XmlTextWriter w = new XmlTextWriter (Console.Out);
  76. w.WriteNode (reader, false);
  77. Console.WriteLine (DateTime.Now.Ticks);
  78. Console.WriteLine (DateTime.Now.Ticks - start.Ticks);
  79. } catch (Exception ex) {
  80. Console.WriteLine (ex);
  81. }
  82. }
  83. }
  84. */
  85. // Wrapper
  86. public class XPathDocument2 : IXPathNavigable
  87. {
  88. XomRoot root;
  89. public XPathDocument2 ()
  90. : this (new NameTable ())
  91. {
  92. }
  93. public XPathDocument2 (XmlNameTable nameTable)
  94. {
  95. root = new XomRoot (nameTable);
  96. }
  97. public XmlNameTable NameTable {
  98. get { return root.NameTable; }
  99. }
  100. public void LoadXml (string xml)
  101. {
  102. Load (new XmlTextReader (xml, XmlNodeType.Document, null));
  103. }
  104. public void Load (TextReader reader)
  105. {
  106. Load (new XmlTextReader (reader));
  107. }
  108. public void Load (XmlReader reader)
  109. {
  110. Load (reader, XmlSpace.None);
  111. }
  112. public void Load (XmlReader reader, XmlSpace space)
  113. {
  114. root.Load (reader, space);
  115. }
  116. public void Save (TextWriter writer)
  117. {
  118. XmlTextWriter xtw = new XmlTextWriter (writer);
  119. xtw.Formatting = Formatting.Indented;
  120. WriteTo (xtw);
  121. }
  122. public void Save (XmlWriter writer)
  123. {
  124. WriteTo (writer);
  125. }
  126. public void WriteTo (XmlWriter writer)
  127. {
  128. root.WriteTo (writer);
  129. }
  130. public XPathNavigator CreateNavigator ()
  131. {
  132. return new XomNavigator (root);
  133. }
  134. }
  135. // Xom part
  136. public struct XmlName
  137. {
  138. public string Prefix;
  139. public string LocalName;
  140. public string Namespace;
  141. string fullName;
  142. public XmlName (string prefix, string name, string ns)
  143. {
  144. this.Prefix = prefix == null ? "" : prefix;
  145. this.LocalName = name;
  146. this.Namespace = ns == null ? "" : ns;
  147. fullName = null;
  148. }
  149. public override bool Equals (object o)
  150. {
  151. if ( !(o is XmlName))
  152. return false;
  153. XmlName other = (XmlName) o;
  154. return LocalName == other.LocalName && Namespace == other.Namespace;
  155. }
  156. public static bool operator == (XmlName n1, XmlName n2)
  157. {
  158. return n1.LocalName == n2.LocalName && n1.Namespace == n2.Namespace;
  159. }
  160. public static bool operator != (XmlName n1, XmlName n2)
  161. {
  162. return n1.LocalName != n2.LocalName || n1.Namespace != n2.Namespace;
  163. }
  164. public override int GetHashCode ()
  165. {
  166. if (fullName == null)
  167. fullName = String.Concat (LocalName, "/", Namespace);
  168. return fullName.GetHashCode ();
  169. }
  170. public override string ToString ()
  171. {
  172. if (fullName == null)
  173. fullName = String.Concat (LocalName, "/", Namespace);
  174. return fullName;
  175. }
  176. }
  177. public abstract class XomNode
  178. {
  179. XomParentNode parent;
  180. string prefixedName;
  181. XomNode previousSibling;
  182. XomNode nextSibling;
  183. public XomRoot Root {
  184. get {
  185. XomNode n = this;
  186. while (n.parent != null)
  187. n = n.parent;
  188. return (XomRoot) n;
  189. }
  190. }
  191. public string PrefixedName {
  192. get {
  193. if (prefixedName == null) {
  194. if (Prefix.Length > 0)
  195. prefixedName = Prefix + ':' + LocalName;
  196. else
  197. prefixedName = LocalName;
  198. }
  199. return prefixedName;
  200. }
  201. }
  202. public virtual string BaseURI {
  203. get { return Root.BaseURI; }
  204. }
  205. public virtual string XmlLang {
  206. get { return String.Empty; }
  207. }
  208. public XomParentNode Parent {
  209. get { return parent; }
  210. }
  211. public XomNode PreviousSibling {
  212. get { return previousSibling; }
  213. }
  214. public XomNode NextSibling {
  215. get { return nextSibling; }
  216. }
  217. internal void SetParent (XomParentNode parent)
  218. {
  219. this.parent = parent;
  220. }
  221. internal void SetPreviousSibling (XomNode previous)
  222. {
  223. if (previous.parent != parent || this == previous)
  224. throw new InvalidOperationException ();
  225. nextSibling = previous.nextSibling;
  226. previousSibling = previous;
  227. previous.nextSibling = this;
  228. }
  229. internal void SetNextSibling (XomNode next)
  230. {
  231. if (next.parent != parent || this == next)
  232. throw new InvalidOperationException ();
  233. previousSibling = next.previousSibling;
  234. nextSibling = next;
  235. next.previousSibling = this;
  236. }
  237. internal void RemoveItself ()
  238. {
  239. if (previousSibling != null)
  240. previousSibling.nextSibling = nextSibling;
  241. if (nextSibling != null)
  242. nextSibling.previousSibling = previousSibling;
  243. parent = null;
  244. }
  245. public string LookupPrefix (string ns)
  246. {
  247. XomElement n = this as XomElement;
  248. if (n == null)
  249. n = Parent as XomElement;
  250. while (n != null) {
  251. int len = n.NamespaceCount;
  252. for (int i = 0; i < len; i++) {
  253. XomNamespace nn = n.GetLocalNamespace (i);
  254. if (nn.Value == ns)
  255. return nn.LocalName;
  256. }
  257. }
  258. return null;
  259. }
  260. public string LookupNamespace (string ns)
  261. {
  262. XomElement n = this as XomElement;
  263. if (n == null)
  264. n = Parent as XomElement;
  265. while (n != null) {
  266. int len = n.NamespaceCount;
  267. for (int i = 0; i < len; i++) {
  268. XomNamespace nn = n.GetLocalNamespace (i);
  269. if (nn.Namespace== ns)
  270. return nn.Prefix;
  271. }
  272. }
  273. return null;
  274. }
  275. public virtual bool IsEmptyElement {
  276. get { return false; }
  277. }
  278. public abstract string LocalName { get; }
  279. public abstract string Namespace { get; }
  280. public abstract string Prefix { get; }
  281. public abstract string Value { get; set; }
  282. public abstract XPathNodeType NodeType { get; }
  283. public abstract int ChildCount { get; }
  284. public virtual XomNode FirstChild { get { return null; } }
  285. public virtual XomNode LastChild { get { return null; } }
  286. internal abstract void BuildValue (StringBuilder sb);
  287. public string OuterXml {
  288. get {
  289. StringWriter sw = new StringWriter ();
  290. XmlTextWriter xtw = new XmlTextWriter (sw);
  291. WriteTo (xtw);
  292. return sw.ToString ();
  293. }
  294. }
  295. public string InnerXml {
  296. get {
  297. StringWriter sw = new StringWriter ();
  298. XmlTextWriter xtw = new XmlTextWriter (sw);
  299. for (XomNode n = FirstChild; n != null; n = n.NextSibling)
  300. n.WriteTo (xtw);
  301. return sw.ToString ();
  302. }
  303. }
  304. public abstract void WriteTo (XmlWriter writer);
  305. }
  306. public interface IHasXomNode
  307. {
  308. XomNode GetNode ();
  309. }
  310. public abstract class XomParentNode : XomNode
  311. {
  312. XomNode firstChild;
  313. XomNode lastChild;
  314. int childCount;
  315. public void ReadNode (XmlReader reader, XmlSpace space)
  316. {
  317. switch (reader.ReadState) {
  318. case ReadState.Initial:
  319. reader.Read ();
  320. break;
  321. case ReadState.Error:
  322. case ReadState.Closed:
  323. case ReadState.EndOfFile:
  324. throw new ArgumentException ("Argument XmlReader is not readable.");
  325. }
  326. switch (reader.NodeType) {
  327. case XmlNodeType.Element:
  328. XomElement el = new XomElement (reader.Prefix, reader.LocalName, reader.NamespaceURI, this);
  329. if (reader.MoveToFirstAttribute ()) {
  330. do {
  331. new XomAttribute (reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value, el);
  332. } while (reader.MoveToNextAttribute ());
  333. reader.MoveToContent ();
  334. }
  335. if (reader.IsEmptyElement) {
  336. el.SetIsEmpty (true);
  337. reader.Read ();
  338. }
  339. else {
  340. reader.Read ();
  341. while (reader.NodeType != XmlNodeType.EndElement)
  342. el.ReadNode (reader, space);
  343. reader.ReadEndElement ();
  344. }
  345. return;
  346. case XmlNodeType.Text:
  347. case XmlNodeType.CDATA:
  348. XomText text = new XomText (reader.Value, this);
  349. reader.Read ();
  350. return;
  351. case XmlNodeType.SignificantWhitespace:
  352. XomSignificantWhitespace sws = new XomSignificantWhitespace (reader.Value, this);
  353. reader.Read ();
  354. return;
  355. case XmlNodeType.Whitespace:
  356. if (space == XmlSpace.Default) {
  357. reader.Skip ();
  358. return;
  359. }
  360. XomWhitespace ws = new XomWhitespace (reader.Value, this);
  361. reader.Read ();
  362. return;
  363. case XmlNodeType.ProcessingInstruction:
  364. XomPI pi = new XomPI (reader.LocalName, reader.Value, this);
  365. reader.Read ();
  366. return;
  367. case XmlNodeType.Comment:
  368. XomComment comment = new XomComment (reader.Value, this);
  369. reader.Read ();
  370. return;
  371. default:
  372. reader.Skip ();
  373. return;
  374. }
  375. }
  376. public void AppendChild (XomNode child)
  377. {
  378. InsertBefore (child, null);
  379. }
  380. public void InsertBefore (XomNode child, XomNode nextNode)
  381. {
  382. if (child.Parent != null)
  383. throw new InvalidOperationException ("The child already has a parent.");
  384. if (nextNode == null) {
  385. child.SetParent (this);
  386. if (firstChild == null)
  387. firstChild = lastChild = child;
  388. else {
  389. child.SetPreviousSibling (lastChild);
  390. lastChild = child;
  391. }
  392. } else {
  393. if (nextNode.Parent != this)
  394. throw new ArgumentException ("Argument nextNode is not a child of this node.");
  395. child.SetNextSibling (nextNode);
  396. }
  397. childCount++;
  398. }
  399. public abstract void Clear ();
  400. public override XomNode FirstChild {
  401. get { return firstChild; }
  402. }
  403. public override XomNode LastChild {
  404. get { return lastChild; }
  405. }
  406. public override int ChildCount {
  407. get { return childCount; }
  408. }
  409. internal void ClearChildren ()
  410. {
  411. firstChild = lastChild = null;
  412. childCount = 0;
  413. }
  414. public void RemoveChild (XomNode child)
  415. {
  416. if (child == firstChild)
  417. firstChild = child.NextSibling;
  418. if (child == lastChild)
  419. lastChild = child.PreviousSibling;
  420. child.RemoveItself ();
  421. childCount--;
  422. }
  423. public override string Value {
  424. get {
  425. StringBuilder sb = new StringBuilder ();
  426. BuildValue (sb);
  427. return sb.ToString ();
  428. }
  429. set {
  430. ClearChildren ();
  431. AppendChild (new XomText (value));
  432. }
  433. }
  434. internal override void BuildValue (StringBuilder sb)
  435. {
  436. for (XomNode n = FirstChild; n != null; n = n.NextSibling)
  437. n.BuildValue (sb);
  438. }
  439. }
  440. public class XomRoot : XomParentNode
  441. {
  442. XmlNameTable nameTable;
  443. Hashtable identicalElements;
  444. string baseUri;
  445. public XomRoot (XmlNameTable nameTable)
  446. {
  447. this.nameTable = nameTable;
  448. identicalElements = new Hashtable ();
  449. }
  450. public override string BaseURI {
  451. get { return baseUri; }
  452. }
  453. public void Load (XmlReader reader)
  454. {
  455. Load (reader, XmlSpace.None);
  456. }
  457. public void Load (XmlReader reader, XmlSpace space)
  458. {
  459. baseUri = reader.BaseURI;
  460. while (!reader.EOF)
  461. ReadNode (reader, space);
  462. }
  463. public XmlNameTable NameTable {
  464. get { return nameTable; }
  465. }
  466. public override string Prefix {
  467. get { return ""; }
  468. }
  469. public override string LocalName {
  470. get { return ""; }
  471. }
  472. public override string Namespace {
  473. get { return ""; }
  474. }
  475. public override XPathNodeType NodeType {
  476. get { return XPathNodeType.Root; }
  477. }
  478. public override void Clear ()
  479. {
  480. ClearChildren ();
  481. }
  482. public override void WriteTo (XmlWriter writer)
  483. {
  484. for (XomNode n = FirstChild; n != null; n = n.NextSibling)
  485. n.WriteTo (writer);
  486. }
  487. public XomElement GetIdenticalNode (string id)
  488. {
  489. return identicalElements [id] as XomElement;
  490. }
  491. internal void GetIdenticalNode (string id, XomElement element)
  492. {
  493. identicalElements.Add (id, element);
  494. }
  495. }
  496. public class XomElement : XomParentNode
  497. {
  498. XmlName qname;
  499. bool isEmptyElement;
  500. ArrayList attributes;
  501. ArrayList namespaces;
  502. public XomElement (string name)
  503. : this ("", name, "", null)
  504. {
  505. }
  506. public XomElement (string name, XomRoot root)
  507. : this ("", name, "", root)
  508. {
  509. }
  510. public XomElement (string name, string ns)
  511. : this ("", name, ns, null)
  512. {
  513. }
  514. public XomElement (string name, string ns, XomRoot root)
  515. : this ("", name, ns, root)
  516. {
  517. }
  518. public XomElement (string prefix, string name, string ns)
  519. : this (prefix, name, ns, null)
  520. {
  521. }
  522. public XomElement (string prefix, string name, string ns, XomParentNode parent)
  523. {
  524. qname.LocalName = name;
  525. qname.Namespace = ns == null ? "" : ns;
  526. qname.Prefix = prefix == null ? "" : prefix;
  527. if (parent != null)
  528. parent.AppendChild (this);
  529. }
  530. public override bool IsEmptyElement {
  531. get { return isEmptyElement; }
  532. }
  533. internal void SetIsEmpty (bool value)
  534. {
  535. isEmptyElement = value;
  536. }
  537. public override string Prefix {
  538. get { return qname.Prefix; }
  539. }
  540. public override string LocalName {
  541. get { return qname.LocalName; }
  542. }
  543. public override string Namespace {
  544. get { return qname.Namespace; }
  545. }
  546. public override XPathNodeType NodeType {
  547. get { return XPathNodeType.Element; }
  548. }
  549. public override void Clear ()
  550. {
  551. if (attributes != null)
  552. attributes.Clear ();
  553. if (namespaces != null)
  554. namespaces.Clear ();
  555. ClearChildren ();
  556. }
  557. public void AppendAttribute (XomAttribute attr)
  558. {
  559. if (attr.Parent != null)
  560. throw new InvalidOperationException ("The argument attribute already have another element owner.");
  561. attr.SetParent (this);
  562. if (attributes == null)
  563. attributes = new ArrayList ();
  564. attributes.Add (attr);
  565. }
  566. /*
  567. public void UpdateAttribute (XomAttribute attr)
  568. {
  569. if (attr.Parent != null)
  570. throw new InvalidOperationException ("The argument attribute already have another element owner.");
  571. XomAttribute existing = GetAttribute (attr.LocalName, attr.Namespace);
  572. if (existing != null)
  573. RemoveAttribute (existing);
  574. if (attributes == null)
  575. attributes = new ArrayList ();
  576. attr.SetParent (this);
  577. attributes.Add (attr);
  578. }
  579. */
  580. public XomAttribute GetAttribute (int index)
  581. {
  582. return attributes == null ? null : attributes [index] as XomAttribute;
  583. }
  584. public XomAttribute GetAttribute (string name, string ns)
  585. {
  586. if (attributes == null)
  587. return null;
  588. for (int i = 0; i < attributes.Count; i++) {
  589. XomAttribute a = attributes [i] as XomAttribute;
  590. if (a.LocalName == name && a.Namespace == ns)
  591. return a;
  592. }
  593. return null;
  594. }
  595. public XomAttribute GetNextAttribute (XomAttribute attr)
  596. {
  597. if (attributes == null || attributes.Count == 0)
  598. return null;
  599. if (attributes [attributes.Count - 1] == attr)
  600. return null;
  601. // It is not efficient, but usually there won't be so many attributes in an element.
  602. int index = attributes.IndexOf (attr);
  603. if (index < 0)
  604. return null;
  605. return attributes [index + 1] as XomAttribute;
  606. }
  607. public int AttributeCount {
  608. get { return attributes == null ? 0 : attributes.Count; }
  609. }
  610. public void RemoveAttribute (XomAttribute attr)
  611. {
  612. if (attributes == null)
  613. return;
  614. attributes.Remove (attr);
  615. attr.SetParent (null);
  616. }
  617. public void AppendNamespace (string prefix, string ns)
  618. {
  619. if (namespaces == null)
  620. namespaces = new ArrayList ();
  621. namespaces.Add (new XomNamespace (prefix, ns));
  622. }
  623. public XomNamespace GetLocalNamespace (int index)
  624. {
  625. if (namespaces == null || namespaces.Count <= index)
  626. return null;
  627. return namespaces [index] as XomNamespace;
  628. }
  629. public XomNamespace GetLocalNamespace (string prefix)
  630. {
  631. if (namespaces == null)
  632. return null;
  633. for (int i = 0; i < namespaces.Count; i++) {
  634. XomNamespace qname = namespaces [i] as XomNamespace;
  635. if (qname.LocalName == prefix)
  636. return qname;
  637. }
  638. return null;
  639. }
  640. public XomNamespace GetNextLocalNamespace (XomNamespace n)
  641. {
  642. if (namespaces == null || namespaces.Count == 0)
  643. return null;
  644. if (namespaces [namespaces.Count - 1] == n)
  645. return null;
  646. // It is not efficient, but usually there won't be so many attributes in an element.
  647. int index = namespaces.IndexOf (n);
  648. if (index < 0)
  649. return null;
  650. return namespaces [index + 1] as XomNamespace;
  651. }
  652. public int NamespaceCount {
  653. get { return namespaces == null ? 0 : namespaces.Count; }
  654. }
  655. public void RemoveNamespace (string prefix)
  656. {
  657. if (namespaces == null)
  658. return;
  659. for (int i = 0; i < namespaces.Count; i++) {
  660. XomNamespace qname = namespaces [i] as XomNamespace;
  661. if (qname.LocalName == prefix) {
  662. namespaces.RemoveAt (i);
  663. return;
  664. }
  665. }
  666. }
  667. public override void WriteTo (XmlWriter writer)
  668. {
  669. writer.WriteStartElement (Prefix, LocalName, Namespace);
  670. if (namespaces != null) {
  671. foreach (XomNamespace n in namespaces)
  672. n.WriteTo (writer);
  673. }
  674. if (attributes != null) {
  675. foreach (XomAttribute a in attributes)
  676. a.WriteTo (writer);
  677. }
  678. for (XomNode n = FirstChild; n != null; n = n.NextSibling)
  679. n.WriteTo (writer);
  680. writer.WriteEndElement ();
  681. }
  682. }
  683. public class XomAttribute : XomNode
  684. {
  685. XmlName qname;
  686. string value;
  687. public XomAttribute (string name, string value)
  688. : this ("", name, "", value, null)
  689. {
  690. }
  691. public XomAttribute (string name, string value, XomElement owner)
  692. : this ("", name, "", value, owner)
  693. {
  694. }
  695. public XomAttribute (string name, string ns, string value)
  696. : this ("", name, ns, value, null)
  697. {
  698. }
  699. public XomAttribute (string name, string ns, string value, XomElement owner)
  700. : this ("", name, ns, value, owner)
  701. {
  702. }
  703. public XomAttribute (string prefix, string name, string ns, string value)
  704. : this ("", name, ns, value, null)
  705. {
  706. }
  707. public XomAttribute (string prefix, string name, string ns, string value, XomElement owner)
  708. {
  709. qname.LocalName = name;
  710. qname.Namespace = ns;
  711. qname.Prefix = prefix;
  712. this.value = value;
  713. if (owner != null)
  714. owner.AppendAttribute (this);
  715. }
  716. public override string Prefix {
  717. get { return qname.Prefix; }
  718. }
  719. public override string LocalName {
  720. get { return qname.LocalName; }
  721. }
  722. public override string Namespace {
  723. get { return qname.Namespace; }
  724. }
  725. public override XPathNodeType NodeType {
  726. get { return XPathNodeType.Attribute; }
  727. }
  728. public override int ChildCount { get { return 0; } }
  729. public override string Value {
  730. get { return value; }
  731. set { this.value = value; }
  732. }
  733. internal override void BuildValue (StringBuilder sb)
  734. {
  735. sb.Append (value);
  736. }
  737. public override void WriteTo (XmlWriter writer)
  738. {
  739. writer.WriteAttributeString (Prefix, LocalName, Namespace, Value);
  740. }
  741. }
  742. public class XomNamespace : XomNode
  743. {
  744. #region static members
  745. static XomNamespace xml;
  746. static XomNamespace ()
  747. {
  748. xml = new XomNamespace ("xml", "http://www.w3.org/XML/1998/namespace");
  749. }
  750. public static XomNamespace Xml {
  751. get { return xml; }
  752. }
  753. #endregion
  754. XmlName qname;
  755. public XomNamespace (string prefix, string ns)
  756. {
  757. qname.LocalName = prefix;
  758. qname.Namespace = ns;
  759. }
  760. public override int ChildCount {
  761. get { return 0; }
  762. }
  763. public override string LocalName {
  764. get { return qname.LocalName; }
  765. }
  766. public override string Prefix {
  767. get { return LocalName; }
  768. }
  769. public override string Namespace {
  770. get { return Value; }
  771. }
  772. public override string Value {
  773. get { return qname.Namespace; }
  774. set { qname.Namespace = value; }
  775. }
  776. public override XPathNodeType NodeType {
  777. get { return XPathNodeType.Namespace; }
  778. }
  779. public override void WriteTo (XmlWriter writer)
  780. {
  781. if (LocalName != "")
  782. writer.WriteAttributeString ("xmlns", LocalName, "http://www.w3.org/2000/xmlns/", Namespace);
  783. else
  784. writer.WriteAttributeString ("", "xmlns", "http://www.w3.org/2000/xmlns/", Namespace);
  785. }
  786. internal override void BuildValue (StringBuilder sb)
  787. {
  788. sb.Append (Value);
  789. }
  790. }
  791. public class XomComment : XomNode
  792. {
  793. string value;
  794. public XomComment (string value)
  795. : this (value, null)
  796. {
  797. }
  798. public XomComment (string value, XomParentNode parent)
  799. {
  800. this.value = value;
  801. if (parent != null)
  802. parent.AppendChild (this);
  803. }
  804. public override string Prefix {
  805. get { return ""; }
  806. }
  807. public override string LocalName {
  808. get { return ""; }
  809. }
  810. public override string Namespace {
  811. get { return ""; }
  812. }
  813. public override XPathNodeType NodeType {
  814. get { return XPathNodeType.Comment; }
  815. }
  816. public override string Value {
  817. get { return value; }
  818. set { this.value += value; }
  819. }
  820. internal override void BuildValue (StringBuilder sb)
  821. {
  822. sb.Append (value);
  823. }
  824. public override int ChildCount { get { return 0; } }
  825. public override void WriteTo (XmlWriter writer)
  826. {
  827. writer.WriteComment (Value);
  828. }
  829. }
  830. public class XomPI : XomNode
  831. {
  832. string value;
  833. string name;
  834. public XomPI (string name, string value)
  835. : this (name, value, null)
  836. {
  837. }
  838. public XomPI (string name, string value, XomParentNode parent)
  839. {
  840. this.name = name;
  841. if (value == null)
  842. value = "";
  843. this.value = value;
  844. if (parent != null)
  845. parent.AppendChild (this);
  846. }
  847. public override string Prefix {
  848. get { return ""; }
  849. }
  850. public override string LocalName {
  851. get { return name; }
  852. }
  853. public override string Namespace {
  854. get { return ""; }
  855. }
  856. public override XPathNodeType NodeType {
  857. get { return XPathNodeType.ProcessingInstruction; }
  858. }
  859. public override string Value {
  860. get { return value; }
  861. set { this.value += value; }
  862. }
  863. internal override void BuildValue (StringBuilder sb)
  864. {
  865. sb.Append (value);
  866. }
  867. public override int ChildCount { get { return 0; } }
  868. public override void WriteTo (XmlWriter writer)
  869. {
  870. writer.WriteProcessingInstruction (LocalName, Value);
  871. }
  872. }
  873. public class XomText : XomNode
  874. {
  875. string value;
  876. public XomText (string value)
  877. : this (value, null)
  878. {
  879. }
  880. public XomText (string value, XomParentNode parent)
  881. {
  882. this.value = value;
  883. if (parent != null)
  884. parent.AppendChild (this);
  885. }
  886. public override string Prefix {
  887. get { return ""; }
  888. }
  889. public override string LocalName {
  890. get { return ""; }
  891. }
  892. public override string Namespace {
  893. get { return ""; }
  894. }
  895. public override string Value {
  896. get { return value; }
  897. set { this.value += value; }
  898. }
  899. public override XPathNodeType NodeType {
  900. get { return XPathNodeType.Text; }
  901. }
  902. internal override void BuildValue (StringBuilder sb)
  903. {
  904. sb.Append (value);
  905. }
  906. public override int ChildCount { get { return 0; } }
  907. public override void WriteTo (XmlWriter writer)
  908. {
  909. writer.WriteString (Value);
  910. }
  911. }
  912. public class XomWhitespace : XomNode
  913. {
  914. string value;
  915. public XomWhitespace (string value)
  916. : this (value, null)
  917. {
  918. }
  919. public XomWhitespace (string value, XomParentNode parent)
  920. {
  921. this.value = value;
  922. if (parent != null)
  923. parent.AppendChild (this);
  924. }
  925. public override string Prefix {
  926. get { return ""; }
  927. }
  928. public override string LocalName {
  929. get { return ""; }
  930. }
  931. public override string Namespace {
  932. get { return ""; }
  933. }
  934. public override string Value {
  935. get { return value; }
  936. set { this.value += value; }
  937. }
  938. public override XPathNodeType NodeType {
  939. get { return XPathNodeType.Whitespace; }
  940. }
  941. internal override void BuildValue (StringBuilder sb)
  942. {
  943. sb.Append (value);
  944. }
  945. public override int ChildCount { get { return 0; } }
  946. public override void WriteTo (XmlWriter writer)
  947. {
  948. writer.WriteString (Value);
  949. }
  950. }
  951. public class XomSignificantWhitespace : XomNode
  952. {
  953. string value;
  954. public XomSignificantWhitespace (string value)
  955. : this (value, null)
  956. {
  957. }
  958. public XomSignificantWhitespace (string value, XomParentNode parent)
  959. {
  960. this.value = value;
  961. if (parent != null)
  962. parent.AppendChild (this);
  963. }
  964. public override string Prefix {
  965. get { return ""; }
  966. }
  967. public override string LocalName {
  968. get { return ""; }
  969. }
  970. public override string Namespace {
  971. get { return ""; }
  972. }
  973. public override string Value {
  974. get { return value; }
  975. set { this.value += value; }
  976. }
  977. public override XPathNodeType NodeType {
  978. get { return XPathNodeType.SignificantWhitespace; }
  979. }
  980. internal override void BuildValue (StringBuilder sb)
  981. {
  982. sb.Append (value);
  983. }
  984. public override int ChildCount { get { return 0; } }
  985. public override void WriteTo (XmlWriter writer)
  986. {
  987. writer.WriteString (Value);
  988. }
  989. }
  990. }
  991. #endif