XPathNavigator.cs 16 KB

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