DTMXPathNavigator2.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. //
  2. // Mono.Xml.XPath.DTMXPathNavigator2
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // (C) 2004 Novell Inc.
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections;
  31. using System.Text;
  32. using System.Xml;
  33. using System.Xml.Schema;
  34. using System.Xml.XPath;
  35. using System.ServiceModel.Dispatcher;
  36. namespace Mono.Xml.XPath
  37. {
  38. #if OUTSIDE_SYSTEM_XML
  39. public
  40. #else
  41. internal
  42. #endif
  43. class SeekableDTMXPathNavigator2 : SeekableXPathNavigator, IXmlLineInfo
  44. {
  45. public SeekableDTMXPathNavigator2 (DTMXPathDocument2 document)
  46. {
  47. this.MoveToRoot ();
  48. this.document = document;
  49. }
  50. // Copy constructor including position informations.
  51. public SeekableDTMXPathNavigator2 (SeekableDTMXPathNavigator2 org)
  52. {
  53. document = org.document;
  54. currentIsNode = org.currentIsNode;
  55. currentIsAttr = org.currentIsAttr;
  56. currentNode = org.currentNode;
  57. currentAttr = org.currentAttr;
  58. currentNs = org.currentNs;
  59. }
  60. #region SeekableXPathNavigator members
  61. public override long CurrentPosition {
  62. get { return currentIsNode ? currentNode : currentIsAttr ? nodes.Length + currentAttr : nodes.Length + attributes.Length + currentNs; }
  63. set {
  64. int pos = (int) value;
  65. if (pos < nodes.Length) {
  66. currentIsAttr = false;
  67. currentIsNode = true;
  68. currentNode = pos;
  69. } else if (pos < nodes.Length + attributes.Length) {
  70. currentIsAttr = true;
  71. currentIsNode = false;
  72. currentAttr = pos - nodes.Length;
  73. } else if (pos < nodes.Length + attributes.Length + namespaces.Length) {
  74. currentIsAttr = false;
  75. currentIsNode = false;
  76. currentNs = pos - nodes.Length - attributes.Length;
  77. } else
  78. throw new ArgumentOutOfRangeException ();
  79. }
  80. }
  81. public override XPathNodeType GetNodeType (long nodePosition)
  82. {
  83. return
  84. nodePosition < nodes.Length ? nodes [nodePosition].NodeType :
  85. nodePosition < nodes.Length + attributes.Length ? XPathNodeType.Attribute :
  86. XPathNodeType.Namespace;
  87. }
  88. public override string GetLocalName (long nodePosition)
  89. {
  90. switch (GetNodeType (nodePosition)) {
  91. case XPathNodeType.Namespace:
  92. return atomicStringPool [namespaces [nodePosition - nodes.Length - attributes.Length].Name];
  93. case XPathNodeType.Attribute:
  94. return atomicStringPool [attributes [nodePosition - nodes.Length].LocalName];
  95. default:
  96. return atomicStringPool [nodes [nodePosition].LocalName];
  97. }
  98. }
  99. public override string GetName (long nodePosition)
  100. {
  101. switch (GetNodeType (nodePosition)) {
  102. case XPathNodeType.Namespace:
  103. return atomicStringPool [namespaces [nodePosition - nodes.Length - attributes.Length].Name];
  104. case XPathNodeType.Attribute:
  105. return atomicStringPool [attributes [nodePosition - nodes.Length].LocalName];
  106. default:
  107. return atomicStringPool [nodes [nodePosition].LocalName];
  108. }
  109. }
  110. public override string GetNamespace (long nodePosition)
  111. {
  112. switch (GetNodeType (nodePosition)) {
  113. case XPathNodeType.Namespace:
  114. return atomicStringPool [namespaces [nodePosition - nodes.Length - attributes.Length].Namespace];
  115. case XPathNodeType.Attribute:
  116. return atomicStringPool [attributes [nodePosition - nodes.Length].NamespaceURI];
  117. default:
  118. return atomicStringPool [nodes [nodePosition].NamespaceURI];
  119. }
  120. }
  121. public override string GetValue (long nodePosition)
  122. {
  123. switch (GetNodeType (nodePosition)) {
  124. case XPathNodeType.Namespace:
  125. return atomicStringPool [namespaces [nodePosition - nodes.Length - attributes.Length].Namespace];
  126. case XPathNodeType.Attribute:
  127. return nonAtomicStringPool [attributes [nodePosition - nodes.Length].Value];
  128. default:
  129. return nonAtomicStringPool [nodes [nodePosition].Value];
  130. }
  131. }
  132. int GetOwnerPosition (long position)
  133. {
  134. int pos = (int) position;
  135. return pos < nodes.Length ? pos :
  136. pos < nodes.Length + attributes.Length ?
  137. attributes [(int) pos].OwnerElement :
  138. namespaces [(int) pos].DeclaredElement;
  139. }
  140. public override XmlNodeOrder ComparePosition (long firstPosition, long secondPosition)
  141. {
  142. if (firstPosition == secondPosition)
  143. return XmlNodeOrder.Same;
  144. int link1 = GetOwnerPosition (firstPosition);
  145. int link2 = GetOwnerPosition (secondPosition);
  146. if (link1 == link2)
  147. // on the same element. Comparison could be done numerically.
  148. return firstPosition < secondPosition ? XmlNodeOrder.Before :
  149. XmlNodeOrder.After;
  150. else
  151. // on different linked nodes.
  152. return link1 < link2 ?
  153. XmlNodeOrder.Before :
  154. XmlNodeOrder.After;
  155. }
  156. #endregion
  157. XmlNameTable nameTable {
  158. get { return document.NameTable; }
  159. }
  160. // Created XPathDocument. This is used to identify the origin of the navigator.
  161. DTMXPathDocument2 document;
  162. DTMXPathLinkedNode2 [] nodes {
  163. get { return document.Nodes; }
  164. }
  165. DTMXPathAttributeNode2 [] attributes {
  166. get { return document.Attributes; }
  167. }
  168. DTMXPathNamespaceNode2 [] namespaces {
  169. get { return document.Namespaces; }
  170. }
  171. string [] atomicStringPool {
  172. get { return document.AtomicStringPool; }
  173. }
  174. string [] nonAtomicStringPool {
  175. get { return document.NonAtomicStringPool; }
  176. }
  177. // ID table
  178. Hashtable idTable {
  179. get { return document.IdTable; }
  180. }
  181. bool currentIsNode;
  182. bool currentIsAttr;
  183. int currentNode;
  184. int currentAttr;
  185. int currentNs;
  186. #region Properties
  187. public override string BaseURI {
  188. get { return atomicStringPool [nodes [currentNode].BaseURI]; }
  189. }
  190. public override bool HasAttributes {
  191. get { return currentIsNode ? nodes [currentNode].FirstAttribute != 0 : false; }
  192. }
  193. public override bool HasChildren {
  194. get { return currentIsNode ? nodes [currentNode].FirstChild != 0 : false; }
  195. }
  196. public override bool IsEmptyElement {
  197. get { return currentIsNode ? nodes [currentNode].IsEmptyElement : false; }
  198. }
  199. int IXmlLineInfo.LineNumber {
  200. get {
  201. return currentIsAttr ? attributes [currentAttr].LineNumber :
  202. nodes [currentNode].LineNumber;
  203. }
  204. }
  205. int IXmlLineInfo.LinePosition {
  206. get {
  207. return currentIsAttr ? attributes [currentAttr].LinePosition :
  208. nodes [currentNode].LinePosition;
  209. }
  210. }
  211. public override string LocalName {
  212. get {
  213. if (currentIsNode)
  214. return atomicStringPool [nodes [currentNode].LocalName];
  215. else if (currentIsAttr)
  216. return atomicStringPool [attributes [currentAttr].LocalName];
  217. else
  218. return atomicStringPool [namespaces [currentNs].Name];
  219. }
  220. }
  221. // It maybe scarcely used, so I decided to compute it always.
  222. public override string Name {
  223. get {
  224. string prefix;
  225. string localName;
  226. if (currentIsNode) {
  227. prefix = atomicStringPool [nodes [currentNode].Prefix];
  228. localName = atomicStringPool [nodes [currentNode].LocalName];
  229. } else if (currentIsAttr) {
  230. prefix = atomicStringPool [attributes [currentAttr].Prefix];
  231. localName = atomicStringPool [attributes [currentAttr].LocalName];
  232. } else
  233. return atomicStringPool [namespaces [currentNs].Name];
  234. if (prefix != "")
  235. return prefix + ':' + localName;
  236. else
  237. return localName;
  238. }
  239. }
  240. public override string NamespaceURI {
  241. get {
  242. if (currentIsNode)
  243. return atomicStringPool [nodes [currentNode].NamespaceURI];
  244. if (currentIsAttr)
  245. return atomicStringPool [attributes [currentAttr].NamespaceURI];
  246. return String.Empty;
  247. }
  248. }
  249. public override XmlNameTable NameTable {
  250. get { return nameTable; }
  251. }
  252. public override XPathNodeType NodeType {
  253. get {
  254. if (currentIsNode)
  255. return nodes [currentNode].NodeType;
  256. else if (currentIsAttr)
  257. return XPathNodeType.Attribute;
  258. else
  259. return XPathNodeType.Namespace;
  260. }
  261. }
  262. public override string Prefix {
  263. get {
  264. if (currentIsNode)
  265. return atomicStringPool [nodes [currentNode].Prefix];
  266. else if (currentIsAttr)
  267. return atomicStringPool [attributes [currentAttr].Prefix];
  268. return String.Empty;
  269. }
  270. }
  271. public override string Value {
  272. get {
  273. if (currentIsAttr)
  274. return nonAtomicStringPool [attributes [currentAttr].Value];
  275. else if (!currentIsNode)
  276. return atomicStringPool [namespaces [currentNs].Namespace];
  277. switch (nodes [currentNode].NodeType) {
  278. case XPathNodeType.Comment:
  279. case XPathNodeType.ProcessingInstruction:
  280. case XPathNodeType.Text:
  281. case XPathNodeType.Whitespace:
  282. case XPathNodeType.SignificantWhitespace:
  283. return nonAtomicStringPool [nodes [currentNode].Value];
  284. }
  285. // Element - collect all content values
  286. int iter = nodes [currentNode].FirstChild;
  287. if (iter == 0)
  288. return String.Empty;
  289. StringBuilder builder = null;
  290. BuildValue (iter, ref builder);
  291. return builder == null ? String.Empty : builder.ToString ();
  292. }
  293. }
  294. void BuildValue (int iter, ref StringBuilder valueBuilder)
  295. {
  296. int end = nodes [currentNode].NextSibling;
  297. if (end == 0) {
  298. int tmp = currentNode;
  299. do {
  300. tmp = nodes [tmp].Parent;
  301. end = nodes [tmp].NextSibling;
  302. } while (end == 0 && tmp != 0);
  303. if (end == 0)
  304. end = nodes.Length;
  305. }
  306. while (iter < end) {
  307. switch (nodes [iter].NodeType) {
  308. case XPathNodeType.Text:
  309. case XPathNodeType.SignificantWhitespace:
  310. case XPathNodeType.Whitespace:
  311. if (valueBuilder == null)
  312. valueBuilder = new StringBuilder ();
  313. valueBuilder.Append (nonAtomicStringPool [nodes [iter].Value]);
  314. break;
  315. }
  316. iter++;
  317. }
  318. }
  319. public override string XmlLang {
  320. get { return atomicStringPool [nodes [currentNode].XmlLang]; }
  321. }
  322. #endregion
  323. #region Methods
  324. public override XPathNavigator Clone ()
  325. {
  326. return new SeekableDTMXPathNavigator2 (this);
  327. }
  328. public override XmlNodeOrder ComparePosition (XPathNavigator nav)
  329. {
  330. SeekableDTMXPathNavigator2 another = nav as SeekableDTMXPathNavigator2;
  331. if (another == null || another.document != this.document)
  332. return XmlNodeOrder.Unknown;
  333. if (currentNode > another.currentNode)
  334. return XmlNodeOrder.After;
  335. else if (currentNode < another.currentNode)
  336. return XmlNodeOrder.Before;
  337. // another may attr or ns,
  338. // and this may be also attr or ns.
  339. if (another.currentIsAttr) {
  340. if (this.currentIsAttr) {
  341. if (currentAttr > another.currentAttr)
  342. return XmlNodeOrder.After;
  343. else if (currentAttr < another.currentAttr)
  344. return XmlNodeOrder.Before;
  345. else
  346. return XmlNodeOrder.Same;
  347. } else
  348. return XmlNodeOrder.Before;
  349. } else if (!another.currentIsNode) {
  350. if (!this.currentIsNode) {
  351. if (currentNs > another.currentNs)
  352. return XmlNodeOrder.After;
  353. else if (currentNs < another.currentNs)
  354. return XmlNodeOrder.Before;
  355. else
  356. return XmlNodeOrder.Same;
  357. } else
  358. return XmlNodeOrder.Before;
  359. } else
  360. return !another.currentIsNode ? XmlNodeOrder.Before : XmlNodeOrder.Same;
  361. }
  362. private int findAttribute (string localName, string namespaceURI)
  363. {
  364. if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
  365. int cur = nodes [currentNode].FirstAttribute;
  366. while (cur != 0) {
  367. if (atomicStringPool [attributes [cur].LocalName] == localName && atomicStringPool [attributes [cur].NamespaceURI] == namespaceURI)
  368. return cur;
  369. cur = attributes [cur].NextAttribute;
  370. }
  371. }
  372. return 0;
  373. }
  374. public override string GetAttribute (string localName,
  375. string namespaceURI)
  376. {
  377. int attr = findAttribute (localName, namespaceURI);
  378. return (attr != 0) ? nonAtomicStringPool [attributes [attr].Value] : String.Empty;
  379. }
  380. public override string GetNamespace (string name)
  381. {
  382. if (currentIsNode && nodes [currentNode].NodeType == XPathNodeType.Element) {
  383. int nsNode = nodes [currentNode].FirstNamespace;
  384. while (nsNode != 0) {
  385. if (atomicStringPool [namespaces [nsNode].Name] == name)
  386. return atomicStringPool [namespaces [nsNode].Namespace];
  387. nsNode = namespaces [nsNode].NextNamespace;
  388. }
  389. }
  390. return String.Empty;
  391. }
  392. bool IXmlLineInfo.HasLineInfo ()
  393. {
  394. return true;
  395. }
  396. public override bool IsDescendant (XPathNavigator nav)
  397. {
  398. SeekableDTMXPathNavigator2 another = nav as SeekableDTMXPathNavigator2;
  399. if (another == null || another.document != this.document)
  400. return false;
  401. if (another.currentNode == currentNode)
  402. return !another.currentIsNode;
  403. int tmp = nodes [another.currentNode].Parent;
  404. // ancestors must appear in prior on the node list.
  405. if (tmp < currentNode)
  406. return false;
  407. while (tmp != 0) {
  408. if (tmp == currentNode)
  409. return true;
  410. tmp = nodes [tmp].Parent;
  411. }
  412. return false;
  413. }
  414. public override bool IsSamePosition (XPathNavigator other)
  415. {
  416. SeekableDTMXPathNavigator2 another = other as SeekableDTMXPathNavigator2;
  417. if (another == null || another.document != this.document)
  418. return false;
  419. if (this.currentNode != another.currentNode ||
  420. this.currentIsAttr != another.currentIsAttr ||
  421. this.currentIsNode != another.currentIsNode)
  422. return false;
  423. if (currentIsAttr)
  424. return this.currentAttr == another.currentAttr;
  425. else if (!currentIsNode)
  426. return this.currentNs == another.currentNs;
  427. return true;
  428. }
  429. public override bool MoveTo (XPathNavigator other)
  430. {
  431. SeekableDTMXPathNavigator2 another = other as SeekableDTMXPathNavigator2;
  432. if (another == null || another.document != this.document)
  433. return false;
  434. this.currentNode = another.currentNode;
  435. this.currentAttr = another.currentAttr;
  436. this.currentNs = another.currentNs;
  437. this.currentIsNode = another.currentIsNode;
  438. this.currentIsAttr = another.currentIsAttr;
  439. return true;
  440. }
  441. public override bool MoveToAttribute (string localName,
  442. string namespaceURI)
  443. {
  444. int attr = findAttribute (localName, namespaceURI);
  445. if (attr == 0)
  446. return false;
  447. currentAttr = attr;
  448. currentIsAttr = true;
  449. currentIsNode = false;
  450. return true;
  451. }
  452. public override bool MoveToFirst ()
  453. {
  454. if (currentIsAttr)
  455. return false;
  456. int cur = nodes [currentNode].PreviousSibling;
  457. if (cur == 0)
  458. return false;
  459. cur = nodes [cur].Parent;
  460. cur = nodes [cur].FirstChild;
  461. currentNode = cur;
  462. currentIsNode = true;
  463. return true;
  464. }
  465. public override bool MoveToFirstAttribute ()
  466. {
  467. if (!currentIsNode)
  468. return false;
  469. int first = nodes [currentNode].FirstAttribute;
  470. if (first == 0)
  471. return false;
  472. currentAttr = first;
  473. currentIsAttr = true;
  474. currentIsNode = false;
  475. return true;
  476. }
  477. public override bool MoveToFirstChild ()
  478. {
  479. if (!currentIsNode)
  480. return false;
  481. int first = nodes [currentNode].FirstChild;
  482. if (first == 0)
  483. return false;
  484. currentNode = first;
  485. return true;
  486. }
  487. private bool moveToSpecifiedNamespace (int cur,
  488. XPathNamespaceScope namespaceScope)
  489. {
  490. if (cur == 0)
  491. return false;
  492. if (namespaceScope == XPathNamespaceScope.Local &&
  493. namespaces [cur].DeclaredElement != currentNode)
  494. return false;
  495. if (namespaceScope != XPathNamespaceScope.All
  496. && namespaces [cur].Namespace == XmlNamespaces.IndexXML)
  497. return false;
  498. if (cur != 0) {
  499. moveToNamespace (cur);
  500. return true;
  501. }
  502. else
  503. return false;
  504. }
  505. public override bool MoveToFirstNamespace (
  506. XPathNamespaceScope namespaceScope)
  507. {
  508. if (!currentIsNode)
  509. return false;
  510. int cur = nodes [currentNode].FirstNamespace;
  511. return moveToSpecifiedNamespace (cur, namespaceScope);
  512. }
  513. // Note that this support is extension to XPathDocument.
  514. // XPathDocument does not support ID reference.
  515. public override bool MoveToId (string id)
  516. {
  517. if (idTable.ContainsKey (id)) {
  518. currentNode = (int) idTable [id];
  519. currentIsNode = true;
  520. currentIsAttr = false;
  521. return true;
  522. }
  523. else
  524. return false;
  525. }
  526. private void moveToNamespace (int nsNode)
  527. {
  528. currentIsNode = currentIsAttr = false;
  529. currentNs = nsNode;
  530. }
  531. public override bool MoveToNamespace (string name)
  532. {
  533. int cur = nodes [currentNode].FirstNamespace;
  534. if (cur == 0)
  535. return false;
  536. while (cur != 0) {
  537. if (atomicStringPool [namespaces [cur].Name] == name) {
  538. moveToNamespace (cur);
  539. return true;
  540. }
  541. cur = namespaces [cur].NextNamespace;
  542. }
  543. return false;
  544. }
  545. public override bool MoveToNext ()
  546. {
  547. if (currentIsAttr)
  548. return false;
  549. int next = nodes [currentNode].NextSibling;
  550. if (next == 0)
  551. return false;
  552. currentNode = next;
  553. currentIsNode = true;
  554. return true;
  555. }
  556. public override bool MoveToNextAttribute ()
  557. {
  558. if (!currentIsAttr)
  559. return false;
  560. int next = attributes [currentAttr].NextAttribute;
  561. if (next == 0)
  562. return false;
  563. currentAttr = next;
  564. return true;
  565. }
  566. public override bool MoveToNextNamespace (
  567. XPathNamespaceScope namespaceScope)
  568. {
  569. if (currentIsAttr || currentIsNode)
  570. return false;
  571. int cur = namespaces [currentNs].NextNamespace;
  572. return moveToSpecifiedNamespace (cur, namespaceScope);
  573. }
  574. public override bool MoveToParent ()
  575. {
  576. if (!currentIsNode) {
  577. currentIsNode = true;
  578. currentIsAttr = false;
  579. return true;
  580. }
  581. int parent = nodes [currentNode].Parent;
  582. if (parent == 0) // It is root itself.
  583. return false;
  584. currentNode = parent;
  585. return true;
  586. }
  587. public override bool MoveToPrevious ()
  588. {
  589. if (currentIsAttr)
  590. return false;
  591. int previous = nodes [currentNode].PreviousSibling;
  592. if (previous == 0)
  593. return false;
  594. currentNode = previous;
  595. currentIsNode = true;
  596. return true;
  597. }
  598. public override void MoveToRoot ()
  599. {
  600. currentNode = 1; // root is 1.
  601. currentIsNode = true;
  602. currentIsAttr = false;
  603. }
  604. #endregion
  605. }
  606. class XmlNamespaces
  607. {
  608. public const string XML = "http://www.w3.org/XML/1998/namespace";
  609. public const string XMLNS = "http://www.w3.org/2000/xmlns/";
  610. public const int IndexXML = 2;
  611. public const int IndexXMLNS = 3;
  612. }
  613. }