XPathNavigator.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. //
  2. // System.Xml.XPath.XPathNavigator
  3. //
  4. // Author:
  5. // Jason Diamond ([email protected])
  6. // Atsushi Enomoto ([email protected])
  7. //
  8. // (C) 2002 Jason Diamond http://injektilo.org/
  9. // (C) 2004 Novell Inc.
  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. using System;
  32. using System.Collections;
  33. using System.Xml;
  34. using System.Xml.Schema;
  35. using Mono.Xml.XPath;
  36. #if NET_2_0
  37. using NSResolver = System.Xml.IXmlNamespaceResolver;
  38. #else
  39. using NSResolver = System.Xml.XmlNamespaceManager;
  40. #endif
  41. namespace System.Xml.XPath
  42. {
  43. #if NET_2_0
  44. public abstract class XPathNavigator : XPathItem,
  45. ICloneable, IXPathNavigable, IXmlNamespaceResolver
  46. #else
  47. public abstract class XPathNavigator : ICloneable
  48. #endif
  49. {
  50. #region Constructor
  51. protected XPathNavigator ()
  52. {
  53. }
  54. #endregion
  55. #region Properties
  56. public abstract string BaseURI { get; }
  57. public abstract bool HasAttributes { get; }
  58. public abstract bool HasChildren { get; }
  59. public abstract bool IsEmptyElement { get; }
  60. public abstract string LocalName { get; }
  61. public abstract string Name { get; }
  62. public abstract string NamespaceURI { get; }
  63. public abstract XmlNameTable NameTable { get; }
  64. public abstract XPathNodeType NodeType { get; }
  65. public abstract string Prefix { get; }
  66. #if NET_2_0
  67. #else
  68. public abstract string Value { get; }
  69. #endif
  70. public abstract string XmlLang { get; }
  71. int Depth
  72. {
  73. get
  74. {
  75. int cLevels = 0;
  76. XPathNavigator nav = Clone ();
  77. while (nav.MoveToParent ())
  78. cLevels ++;
  79. return cLevels;
  80. }
  81. }
  82. #endregion
  83. #region Methods
  84. public abstract XPathNavigator Clone ();
  85. public virtual XmlNodeOrder ComparePosition (XPathNavigator nav)
  86. {
  87. if (IsSamePosition (nav))
  88. return XmlNodeOrder.Same;
  89. XPathNavigator nav1 = Clone ();
  90. XPathNavigator nav2 = nav.Clone ();
  91. int nDepth1 = nav1.Depth;
  92. int nDepth2 = nav2.Depth;
  93. if (nDepth1 > nDepth2)
  94. {
  95. while (nDepth1 > nDepth2)
  96. {
  97. if (!nav1.MoveToParent ())
  98. break;
  99. nDepth1 --;
  100. }
  101. if (nav1.IsSamePosition (nav2))
  102. return XmlNodeOrder.After;
  103. }
  104. else if (nDepth1 < nDepth2)
  105. {
  106. while (nDepth1 < nDepth2)
  107. {
  108. if (!nav2.MoveToParent ())
  109. break;
  110. nDepth2 --;
  111. }
  112. if (nav1.IsSamePosition (nav2))
  113. return XmlNodeOrder.Before;
  114. }
  115. XPathNavigator parent1 = nav1.Clone ();
  116. XPathNavigator parent2 = nav2.Clone ();
  117. while (parent1.MoveToParent () && parent2.MoveToParent ())
  118. {
  119. if (parent1.IsSamePosition (parent2))
  120. {
  121. // the ordering is namespace, attribute, children
  122. // assume that nav1 is before nav2, find counter-example
  123. if (nav1.NodeType == XPathNodeType.Namespace)
  124. {
  125. if (nav2.NodeType == XPathNodeType.Namespace)
  126. {
  127. // match namespaces
  128. while (nav2.MoveToNextNamespace ())
  129. if (nav2.IsSamePosition (nav1))
  130. return XmlNodeOrder.After;
  131. }
  132. }
  133. else if (nav1.NodeType == XPathNodeType.Attribute)
  134. {
  135. if (nav2.NodeType == XPathNodeType.Namespace)
  136. return XmlNodeOrder.After;
  137. else if (nav2.NodeType == XPathNodeType.Attribute)
  138. {
  139. // match attributes
  140. while (nav2.MoveToNextAttribute ())
  141. if (nav2.IsSamePosition (nav1))
  142. return XmlNodeOrder.After;
  143. }
  144. }
  145. else
  146. {
  147. switch (nav2.NodeType) {
  148. case XPathNodeType.Namespace:
  149. case XPathNodeType.Attribute:
  150. return XmlNodeOrder.After;
  151. }
  152. // match children
  153. while (nav2.MoveToNext ())
  154. if (nav2.IsSamePosition (nav1))
  155. return XmlNodeOrder.After;
  156. }
  157. return XmlNodeOrder.Before;
  158. }
  159. nav1.MoveToParent ();
  160. nav2.MoveToParent ();
  161. }
  162. return XmlNodeOrder.Unknown;
  163. }
  164. public virtual XPathExpression Compile (string xpath)
  165. {
  166. XPathParser parser = new XPathParser ();
  167. return new CompiledExpression (parser.Compile (xpath));
  168. }
  169. internal virtual XPathExpression Compile (string xpath, System.Xml.Xsl.IStaticXsltContext ctx)
  170. {
  171. XPathParser parser = new XPathParser (ctx);
  172. return new CompiledExpression (parser.Compile (xpath));
  173. }
  174. public virtual object Evaluate (string xpath)
  175. {
  176. return Evaluate (Compile (xpath));
  177. }
  178. public virtual object Evaluate (XPathExpression expr)
  179. {
  180. return Evaluate (expr, null);
  181. }
  182. public virtual object Evaluate (XPathExpression expr, XPathNodeIterator context)
  183. {
  184. return Evaluate (expr, context, null);
  185. }
  186. internal virtual object Evaluate (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
  187. {
  188. CompiledExpression cexpr = (CompiledExpression) expr;
  189. if (ctx == null)
  190. ctx = cexpr.NamespaceManager;
  191. if (context == null)
  192. context = new NullIterator (this, ctx);
  193. BaseIterator iterContext = (BaseIterator) context;
  194. iterContext.NamespaceManager = ctx;
  195. return cexpr.Evaluate (iterContext);
  196. }
  197. internal XPathNodeIterator EvaluateNodeSet (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
  198. {
  199. CompiledExpression cexpr = (CompiledExpression) expr;
  200. if (ctx == null)
  201. ctx = cexpr.NamespaceManager;
  202. if (context == null)
  203. context = new NullIterator (this, cexpr.NamespaceManager);
  204. BaseIterator iterContext = (BaseIterator) context;
  205. iterContext.NamespaceManager = ctx;
  206. return cexpr.EvaluateNodeSet (iterContext);
  207. }
  208. internal string EvaluateString (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
  209. {
  210. CompiledExpression cexpr = (CompiledExpression) expr;
  211. if (ctx == null)
  212. ctx = cexpr.NamespaceManager;
  213. if (context == null)
  214. context = new NullIterator (this, cexpr.NamespaceManager);
  215. BaseIterator iterContext = (BaseIterator) context;
  216. iterContext.NamespaceManager = ctx;
  217. return cexpr.EvaluateString (iterContext);
  218. }
  219. internal double EvaluateNumber (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
  220. {
  221. CompiledExpression cexpr = (CompiledExpression) expr;
  222. if (ctx == null)
  223. ctx = cexpr.NamespaceManager;
  224. if (context == null)
  225. context = new NullIterator (this, cexpr.NamespaceManager);
  226. BaseIterator iterContext = (BaseIterator) context;
  227. iterContext.NamespaceManager = ctx;
  228. return cexpr.EvaluateNumber (iterContext);
  229. }
  230. internal bool EvaluateBoolean (XPathExpression expr, XPathNodeIterator context, NSResolver ctx)
  231. {
  232. CompiledExpression cexpr = (CompiledExpression) expr;
  233. if (ctx == null)
  234. ctx = cexpr.NamespaceManager;
  235. if (context == null)
  236. context = new NullIterator (this, cexpr.NamespaceManager);
  237. BaseIterator iterContext = (BaseIterator) context;
  238. iterContext.NamespaceManager = ctx;
  239. return cexpr.EvaluateBoolean (iterContext);
  240. }
  241. public abstract string GetAttribute (string localName, string namespaceURI);
  242. public abstract string GetNamespace (string name);
  243. object ICloneable.Clone ()
  244. {
  245. return Clone ();
  246. }
  247. public virtual bool IsDescendant (XPathNavigator nav)
  248. {
  249. if (nav != null)
  250. {
  251. nav = nav.Clone ();
  252. while (nav.MoveToParent ())
  253. {
  254. if (IsSamePosition (nav))
  255. return true;
  256. }
  257. }
  258. return false;
  259. }
  260. public abstract bool IsSamePosition (XPathNavigator other);
  261. public virtual bool Matches (string xpath)
  262. {
  263. return Matches (Compile (xpath));
  264. }
  265. public virtual bool Matches (XPathExpression expr)
  266. {
  267. Expression e = ((CompiledExpression) expr).ExpressionNode;
  268. if (e is ExprRoot)
  269. return NodeType == XPathNodeType.Root;
  270. NodeTest nt = e as NodeTest;
  271. if (nt != null) {
  272. switch (nt.Axis.Axis) {
  273. case Axes.Child:
  274. case Axes.Attribute:
  275. break;
  276. default:
  277. throw new XPathException ("Only child and attribute pattern are allowed for a pattern.");
  278. }
  279. return nt.Match (((CompiledExpression)expr).NamespaceManager, this);
  280. }
  281. if (e is ExprFilter) {
  282. do {
  283. e = ((ExprFilter) e).LeftHandSide;
  284. } while (e is ExprFilter);
  285. if (e is NodeTest && !((NodeTest) e).Match (((CompiledExpression) expr).NamespaceManager, this))
  286. return false;
  287. }
  288. XPathResultType resultType = e.ReturnType;
  289. switch (resultType) {
  290. case XPathResultType.Any:
  291. case XPathResultType.NodeSet:
  292. break;
  293. default:
  294. return false;
  295. }
  296. switch (e.EvaluatedNodeType) {
  297. case XPathNodeType.Attribute:
  298. case XPathNodeType.Namespace:
  299. if (NodeType != e.EvaluatedNodeType)
  300. return false;
  301. break;
  302. }
  303. XPathNodeIterator nodes;
  304. nodes = this.Select (expr);
  305. while (nodes.MoveNext ()) {
  306. if (IsSamePosition (nodes.Current))
  307. return true;
  308. }
  309. // ancestors might select this node.
  310. XPathNavigator navigator = Clone ();
  311. while (navigator.MoveToParent ()) {
  312. nodes = navigator.Select (expr);
  313. while (nodes.MoveNext ()) {
  314. if (IsSamePosition (nodes.Current))
  315. return true;
  316. }
  317. }
  318. return false;
  319. }
  320. public abstract bool MoveTo (XPathNavigator other);
  321. public abstract bool MoveToAttribute (string localName, string namespaceURI);
  322. public abstract bool MoveToFirst ();
  323. public abstract bool MoveToFirstAttribute ();
  324. public abstract bool MoveToFirstChild ();
  325. public bool MoveToFirstNamespace ()
  326. {
  327. return MoveToFirstNamespace (XPathNamespaceScope.All);
  328. }
  329. public abstract bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope);
  330. public abstract bool MoveToId (string id);
  331. public abstract bool MoveToNamespace (string name);
  332. public abstract bool MoveToNext ();
  333. public abstract bool MoveToNextAttribute ();
  334. public bool MoveToNextNamespace ()
  335. {
  336. return MoveToNextNamespace (XPathNamespaceScope.All);
  337. }
  338. public abstract bool MoveToNextNamespace (XPathNamespaceScope namespaceScope);
  339. public abstract bool MoveToParent ();
  340. public abstract bool MoveToPrevious ();
  341. public abstract void MoveToRoot ();
  342. public virtual XPathNodeIterator Select (string xpath)
  343. {
  344. return Select (Compile (xpath));
  345. }
  346. public virtual XPathNodeIterator Select (XPathExpression expr)
  347. {
  348. return Select (expr, null);
  349. }
  350. internal virtual XPathNodeIterator Select (XPathExpression expr, NSResolver ctx)
  351. {
  352. CompiledExpression cexpr = (CompiledExpression) expr;
  353. if (ctx == null)
  354. ctx = cexpr.NamespaceManager;
  355. BaseIterator iter = new NullIterator (this, ctx);
  356. return cexpr.EvaluateNodeSet (iter);
  357. }
  358. public virtual XPathNodeIterator SelectAncestors (XPathNodeType type, bool matchSelf)
  359. {
  360. Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
  361. return SelectTest (new NodeTypeTest (axis, type));
  362. }
  363. public virtual XPathNodeIterator SelectAncestors (string name, string namespaceURI, bool matchSelf)
  364. {
  365. if (name == null)
  366. throw new ArgumentNullException ("name");
  367. if (namespaceURI == null)
  368. throw new ArgumentNullException ("namespaceURI");
  369. Axes axis = (matchSelf) ? Axes.AncestorOrSelf : Axes.Ancestor;
  370. XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
  371. return SelectTest (new NodeNameTest (axis, qname, true));
  372. }
  373. public virtual XPathNodeIterator SelectChildren (XPathNodeType type)
  374. {
  375. return SelectTest (new NodeTypeTest (Axes.Child, type));
  376. }
  377. public virtual XPathNodeIterator SelectChildren (string name, string namespaceURI)
  378. {
  379. if (name == null)
  380. throw new ArgumentNullException ("name");
  381. if (namespaceURI == null)
  382. throw new ArgumentNullException ("namespaceURI");
  383. Axes axis = Axes.Child;
  384. XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
  385. return SelectTest (new NodeNameTest (axis, qname, true));
  386. }
  387. public virtual XPathNodeIterator SelectDescendants (XPathNodeType type, bool matchSelf)
  388. {
  389. Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
  390. return SelectTest (new NodeTypeTest (axis, type));
  391. }
  392. public virtual XPathNodeIterator SelectDescendants (string name, string namespaceURI, bool matchSelf)
  393. {
  394. if (name == null)
  395. throw new ArgumentNullException ("name");
  396. if (namespaceURI == null)
  397. throw new ArgumentNullException ("namespaceURI");
  398. Axes axis = (matchSelf) ? Axes.DescendantOrSelf : Axes.Descendant;
  399. XmlQualifiedName qname = new XmlQualifiedName (name, namespaceURI);
  400. return SelectTest (new NodeNameTest (axis, qname, true));
  401. }
  402. internal XPathNodeIterator SelectTest (NodeTest test)
  403. {
  404. return test.EvaluateNodeSet (new NullIterator (this));
  405. }
  406. public override string ToString ()
  407. {
  408. return Value;
  409. }
  410. #endregion
  411. #if NET_2_0
  412. [MonoTODO]
  413. public virtual bool CheckValidity (XmlSchemaSet schemas, ValidationEventHandler handler)
  414. {
  415. throw new NotImplementedException ();
  416. }
  417. [MonoTODO]
  418. public virtual object CopyAsObject (Type targetType)
  419. {
  420. throw new NotImplementedException ();
  421. }
  422. public virtual XPathNavigator CreateNavigator ()
  423. {
  424. return Clone ();
  425. }
  426. [MonoTODO]
  427. public virtual object Evaluate (string xpath, IXmlNamespaceResolver nsResolver)
  428. {
  429. return Evaluate (Compile (xpath), null, nsResolver);
  430. }
  431. [MonoTODO]
  432. public virtual IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
  433. {
  434. throw new NotImplementedException ();
  435. }
  436. public virtual string LookupNamespace (string prefix)
  437. {
  438. return LookupNamespace (prefix, false);
  439. }
  440. [MonoTODO]
  441. public virtual string LookupNamespace (string prefix, bool atomizedNames)
  442. {
  443. throw new NotImplementedException ();
  444. }
  445. public virtual string LookupPrefix (string namespaceUri)
  446. {
  447. return LookupPrefix (namespaceUri, false);
  448. }
  449. [MonoTODO]
  450. public virtual string LookupPrefix (string namespaceUri, bool atomizedNames)
  451. {
  452. throw new NotImplementedException ();
  453. }
  454. [MonoTODO]
  455. public virtual XmlReader ReadSubtree ()
  456. {
  457. throw new NotImplementedException ();
  458. }
  459. public virtual XPathNavigator SelectSingleNode (string xpath)
  460. {
  461. return SelectSingleNode (xpath, null);
  462. }
  463. [MonoTODO]
  464. public virtual XPathNavigator SelectSingleNode (string xpath, IXmlNamespaceResolver nsResolver)
  465. {
  466. throw new NotImplementedException ();
  467. }
  468. public override object ValueAs (Type type)
  469. {
  470. return ValueAs (type, this);
  471. }
  472. [MonoTODO]
  473. public override object ValueAs (Type type, IXmlNamespaceResolver nsResolver)
  474. {
  475. throw new NotImplementedException ();
  476. }
  477. [MonoTODO]
  478. public virtual XmlWriter WriteSubtree ()
  479. {
  480. throw new NotImplementedException ();
  481. }
  482. [MonoTODO]
  483. public virtual string InnerXml {
  484. get { throw new NotImplementedException (); }
  485. }
  486. [MonoTODO]
  487. public override bool IsNode {
  488. get { throw new NotImplementedException (); }
  489. }
  490. [MonoTODO]
  491. public virtual IKeyComparer NavigatorComparer {
  492. get { throw new NotImplementedException (); }
  493. }
  494. [MonoTODO]
  495. public virtual string OuterXml {
  496. get { throw new NotImplementedException (); }
  497. }
  498. [MonoTODO]
  499. public virtual IXmlSchemaInfo SchemaInfo {
  500. get { throw new NotImplementedException (); }
  501. }
  502. [MonoTODO]
  503. public virtual object TypedValue {
  504. get { throw new NotImplementedException (); }
  505. }
  506. [MonoTODO]
  507. public virtual object UnderlyingObject {
  508. get { throw new NotImplementedException (); }
  509. }
  510. [MonoTODO]
  511. public override bool ValueAsBoolean {
  512. get { throw new NotImplementedException (); }
  513. }
  514. [MonoTODO]
  515. public override DateTime ValueAsDateTime {
  516. get { throw new NotImplementedException (); }
  517. }
  518. [MonoTODO]
  519. public override decimal ValueAsDecimal {
  520. get { throw new NotImplementedException (); }
  521. }
  522. [MonoTODO]
  523. public override double ValueAsDouble {
  524. get { throw new NotImplementedException (); }
  525. }
  526. [MonoTODO]
  527. public override int ValueAsInt32 {
  528. get { throw new NotImplementedException (); }
  529. }
  530. [MonoTODO]
  531. public override long ValueAsInt64 {
  532. get { throw new NotImplementedException (); }
  533. }
  534. [MonoTODO]
  535. public override ICollection ValueAsList {
  536. get { throw new NotImplementedException (); }
  537. }
  538. [MonoTODO]
  539. public override float ValueAsSingle {
  540. get { throw new NotImplementedException (); }
  541. }
  542. [MonoTODO]
  543. public virtual Type ValueType {
  544. get { throw new NotImplementedException (); }
  545. }
  546. [MonoTODO]
  547. public virtual XmlSchemaType XmlType {
  548. get { throw new NotImplementedException (); }
  549. }
  550. [MonoTODO]
  551. protected XmlReader GetValidatingReader (XmlSchemaSet schemas, ValidationEventHandler handler)
  552. {
  553. throw new NotImplementedException ();
  554. }
  555. #endif
  556. }
  557. }