PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/referencesource/System.Xml.Linq/System/Xml/Linq/XNodeNavigator.cs

http://github.com/mono/mono
C# | 927 lines | 796 code | 67 blank | 64 comment | 340 complexity | 026943eba6263799f2df3ebf01cd6b76 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Xml;
  6. using System.Xml.Linq;
  7. namespace System.Xml.XPath
  8. {
  9. internal class XNodeNavigator : XPathNavigator, IXmlLineInfo
  10. {
  11. const int DocumentContentMask =
  12. (1 << (int)XmlNodeType.Element) |
  13. (1 << (int)XmlNodeType.ProcessingInstruction) |
  14. (1 << (int)XmlNodeType.Comment);
  15. static readonly int[] ElementContentMasks = {
  16. 0, // Root
  17. (1 << (int)XmlNodeType.Element), // Element
  18. 0, // Attribute
  19. 0, // Namespace
  20. (1 << (int)XmlNodeType.CDATA) |
  21. (1 << (int)XmlNodeType.Text), // Text
  22. 0, // SignificantWhitespace
  23. 0, // Whitespace
  24. (1 << (int)XmlNodeType.ProcessingInstruction), // ProcessingInstruction
  25. (1 << (int)XmlNodeType.Comment), // Comment
  26. (1 << (int)XmlNodeType.Element) |
  27. (1 << (int)XmlNodeType.CDATA) |
  28. (1 << (int)XmlNodeType.Text) |
  29. (1 << (int)XmlNodeType.ProcessingInstruction) |
  30. (1 << (int)XmlNodeType.Comment) // All
  31. };
  32. new const int TextMask =
  33. (1 << (int)XmlNodeType.CDATA) |
  34. (1 << (int)XmlNodeType.Text);
  35. static XAttribute XmlNamespaceDeclaration;
  36. // The navigator position is encoded by the tuple (source, parent).
  37. // Lazy text uses (instance, parent element). Namespace declaration uses
  38. // (instance, parent element). Common XObjects uses (instance, null).
  39. object source;
  40. XElement parent;
  41. XmlNameTable nameTable;
  42. public XNodeNavigator(XNode node, XmlNameTable nameTable) {
  43. this.source = node;
  44. this.nameTable = nameTable != null ? nameTable : CreateNameTable();
  45. }
  46. public XNodeNavigator(XNodeNavigator other) {
  47. source = other.source;
  48. parent = other.parent;
  49. nameTable = other.nameTable;
  50. }
  51. public override string BaseURI {
  52. get {
  53. XObject o = source as XObject;
  54. if (o != null) {
  55. return o.BaseUri;
  56. }
  57. if (parent != null) {
  58. return parent.BaseUri;
  59. }
  60. return string.Empty;
  61. }
  62. }
  63. public override bool HasAttributes {
  64. get {
  65. XElement e = source as XElement;
  66. if (e != null) {
  67. XAttribute a = e.lastAttr;
  68. if (a != null) {
  69. do {
  70. a = a.next;
  71. if (!a.IsNamespaceDeclaration) {
  72. return true;
  73. }
  74. } while (a != e.lastAttr);
  75. }
  76. }
  77. return false;
  78. }
  79. }
  80. public override bool HasChildren {
  81. get {
  82. XContainer c = source as XContainer;
  83. if (c != null && c.content != null) {
  84. XNode n = c.content as XNode;
  85. if (n != null) {
  86. do {
  87. n = n.next;
  88. if (IsContent(c, n)) {
  89. return true;
  90. }
  91. } while (n != c.content);
  92. return false;
  93. }
  94. string s = (string)c.content;
  95. if (s.Length != 0 && (c.parent != null || c is XElement)) {
  96. return true;
  97. }
  98. }
  99. return false;
  100. }
  101. }
  102. public override bool IsEmptyElement {
  103. get {
  104. XElement e = source as XElement;
  105. return e != null && e.IsEmpty;
  106. }
  107. }
  108. public override string LocalName {
  109. get { return nameTable.Add(GetLocalName()); }
  110. }
  111. string GetLocalName() {
  112. XElement e = source as XElement;
  113. if (e != null) {
  114. return e.Name.LocalName;
  115. }
  116. XAttribute a = source as XAttribute;
  117. if (a != null) {
  118. if (parent != null && a.Name.NamespaceName.Length == 0) {
  119. return string.Empty; // backcompat
  120. }
  121. return a.Name.LocalName;
  122. }
  123. XProcessingInstruction p = source as XProcessingInstruction;
  124. if (p != null) {
  125. return p.Target;
  126. }
  127. return string.Empty;
  128. }
  129. public override string Name {
  130. get {
  131. string prefix = GetPrefix();
  132. if (prefix.Length == 0) {
  133. return nameTable.Add(GetLocalName());
  134. }
  135. return nameTable.Add(string.Concat(prefix, ":", GetLocalName()));
  136. }
  137. }
  138. public override string NamespaceURI {
  139. get { return nameTable.Add(GetNamespaceURI()); }
  140. }
  141. string GetNamespaceURI() {
  142. XElement e = source as XElement;
  143. if (e != null) {
  144. return e.Name.NamespaceName;
  145. }
  146. XAttribute a = source as XAttribute;
  147. if (a != null) {
  148. if (parent != null) {
  149. return string.Empty; // backcompat
  150. }
  151. return a.Name.NamespaceName;
  152. }
  153. return string.Empty;
  154. }
  155. public override XmlNameTable NameTable {
  156. get { return nameTable; }
  157. }
  158. public override XPathNodeType NodeType {
  159. get {
  160. XObject o = source as XObject;
  161. if (o != null) {
  162. switch (o.NodeType) {
  163. case XmlNodeType.Element:
  164. return XPathNodeType.Element;
  165. case XmlNodeType.Attribute:
  166. if (parent != null) {
  167. return XPathNodeType.Namespace;
  168. }
  169. return XPathNodeType.Attribute;
  170. case XmlNodeType.Document:
  171. return XPathNodeType.Root;
  172. case XmlNodeType.Comment:
  173. return XPathNodeType.Comment;
  174. case XmlNodeType.ProcessingInstruction:
  175. return XPathNodeType.ProcessingInstruction;
  176. default:
  177. return XPathNodeType.Text;
  178. }
  179. }
  180. return XPathNodeType.Text;
  181. }
  182. }
  183. public override string Prefix {
  184. get { return nameTable.Add(GetPrefix()); }
  185. }
  186. string GetPrefix() {
  187. XElement e = source as XElement;
  188. if (e != null) {
  189. string prefix = e.GetPrefixOfNamespace(e.Name.Namespace);
  190. if (prefix != null) {
  191. return prefix;
  192. }
  193. return string.Empty;
  194. }
  195. XAttribute a = source as XAttribute;
  196. if (a != null) {
  197. if (parent != null) {
  198. return string.Empty; // backcompat
  199. }
  200. string prefix = a.GetPrefixOfNamespace(a.Name.Namespace);
  201. if (prefix != null) {
  202. return prefix;
  203. }
  204. }
  205. return string.Empty;
  206. }
  207. public override object UnderlyingObject {
  208. get {
  209. if (source is string) {
  210. // convert lazy text to eager text
  211. source = parent.LastNode;
  212. parent = null;
  213. }
  214. return source;
  215. }
  216. }
  217. public override string Value {
  218. get {
  219. XObject o = source as XObject;
  220. if (o != null) {
  221. switch (o.NodeType) {
  222. case XmlNodeType.Element:
  223. return ((XElement)o).Value;
  224. case XmlNodeType.Attribute:
  225. return ((XAttribute)o).Value;
  226. case XmlNodeType.Document:
  227. XElement root = ((XDocument)o).Root;
  228. return root != null ? root.Value : string.Empty;
  229. case XmlNodeType.Text:
  230. case XmlNodeType.CDATA:
  231. return CollectText((XText)o);
  232. case XmlNodeType.Comment:
  233. return ((XComment)o).Value;
  234. case XmlNodeType.ProcessingInstruction:
  235. return ((XProcessingInstruction)o).Data;
  236. default:
  237. return string.Empty;
  238. }
  239. }
  240. return (string)source;
  241. }
  242. }
  243. public override bool CheckValidity(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.Schema.ValidationEventHandler validationEventHandler) {
  244. throw new NotSupportedException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.NotSupported_CheckValidity));
  245. }
  246. public override XPathNavigator Clone() {
  247. return new XNodeNavigator(this);
  248. }
  249. public override bool IsSamePosition(XPathNavigator navigator) {
  250. XNodeNavigator other = navigator as XNodeNavigator;
  251. if (other == null) {
  252. return false;
  253. }
  254. return IsSamePosition(this, other);
  255. }
  256. public override bool MoveTo(XPathNavigator navigator) {
  257. XNodeNavigator other = navigator as XNodeNavigator;
  258. if (other != null) {
  259. source = other.source;
  260. parent = other.parent;
  261. return true;
  262. }
  263. return false;
  264. }
  265. public override bool MoveToAttribute(string localName, string namespaceName) {
  266. XElement e = source as XElement;
  267. if (e != null) {
  268. XAttribute a = e.lastAttr;
  269. if (a != null) {
  270. do {
  271. a = a.next;
  272. if (a.Name.LocalName == localName &&
  273. a.Name.NamespaceName == namespaceName &&
  274. !a.IsNamespaceDeclaration) {
  275. source = a;
  276. return true;
  277. }
  278. } while (a != e.lastAttr);
  279. }
  280. }
  281. return false;
  282. }
  283. public override bool MoveToChild(string localName, string namespaceName) {
  284. XContainer c = source as XContainer;
  285. if (c != null && c.content != null) {
  286. XNode n = c.content as XNode;
  287. if (n != null) {
  288. do {
  289. n = n.next;
  290. XElement e = n as XElement;
  291. if (e != null &&
  292. e.Name.LocalName == localName &&
  293. e.Name.NamespaceName == namespaceName) {
  294. source = e;
  295. return true;
  296. }
  297. } while (n != c.content);
  298. }
  299. }
  300. return false;
  301. }
  302. public override bool MoveToChild(XPathNodeType type) {
  303. XContainer c = source as XContainer;
  304. if (c != null && c.content != null) {
  305. XNode n = c.content as XNode;
  306. if (n != null) {
  307. int mask = GetElementContentMask(type);
  308. if ((TextMask & mask) != 0 && c.parent == null && c is XDocument) {
  309. mask &= ~TextMask;
  310. }
  311. do {
  312. n = n.next;
  313. if (((1 << (int)n.NodeType) & mask) != 0) {
  314. source = n;
  315. return true;
  316. }
  317. } while (n != c.content);
  318. return false;
  319. }
  320. string s = (string)c.content;
  321. if (s.Length != 0) {
  322. int mask = GetElementContentMask(type);
  323. if ((TextMask & mask) != 0 && c.parent == null && c is XDocument) {
  324. return false;
  325. }
  326. if (((1 << (int)XmlNodeType.Text) & mask) != 0) {
  327. source = s;
  328. parent = (XElement)c;
  329. return true;
  330. }
  331. }
  332. }
  333. return false;
  334. }
  335. public override bool MoveToFirstAttribute() {
  336. XElement e = source as XElement;
  337. if (e != null) {
  338. XAttribute a = e.lastAttr;
  339. if (a != null) {
  340. do {
  341. a = a.next;
  342. if (!a.IsNamespaceDeclaration) {
  343. source = a;
  344. return true;
  345. }
  346. } while (a != e.lastAttr);
  347. }
  348. }
  349. return false;
  350. }
  351. public override bool MoveToFirstChild() {
  352. XContainer c = source as XContainer;
  353. if (c != null && c.content != null) {
  354. XNode n = c.content as XNode;
  355. if (n != null) {
  356. do {
  357. n = n.next;
  358. if (IsContent(c, n)) {
  359. source = n;
  360. return true;
  361. }
  362. } while (n != c.content);
  363. return false;
  364. }
  365. string s = (string)c.content;
  366. if (s.Length != 0 && (c.parent != null || c is XElement)) {
  367. source = s;
  368. parent = (XElement)c;
  369. return true;
  370. }
  371. }
  372. return false;
  373. }
  374. public override bool MoveToFirstNamespace(XPathNamespaceScope scope) {
  375. XElement e = source as XElement;
  376. if (e != null) {
  377. XAttribute a = null;
  378. switch (scope) {
  379. case XPathNamespaceScope.Local:
  380. a = GetFirstNamespaceDeclarationLocal(e);
  381. break;
  382. case XPathNamespaceScope.ExcludeXml:
  383. a = GetFirstNamespaceDeclarationGlobal(e);
  384. while (a != null && a.Name.LocalName == "xml") {
  385. a = GetNextNamespaceDeclarationGlobal(a);
  386. }
  387. break;
  388. case XPathNamespaceScope.All:
  389. a = GetFirstNamespaceDeclarationGlobal(e);
  390. if (a == null) {
  391. a = GetXmlNamespaceDeclaration();
  392. }
  393. break;
  394. }
  395. if (a != null) {
  396. source = a;
  397. parent = e;
  398. return true;
  399. }
  400. }
  401. return false;
  402. }
  403. public override bool MoveToId(string id) {
  404. throw new NotSupportedException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.NotSupported_MoveToId));
  405. }
  406. public override bool MoveToNamespace(string localName) {
  407. XElement e = source as XElement;
  408. if (e != null) {
  409. if (localName == "xmlns") {
  410. return false; // backcompat
  411. }
  412. if (localName != null && localName.Length == 0) {
  413. localName = "xmlns"; // backcompat
  414. }
  415. XAttribute a = GetFirstNamespaceDeclarationGlobal(e);
  416. while (a != null) {
  417. if (a.Name.LocalName == localName) {
  418. source = a;
  419. parent = e;
  420. return true;
  421. }
  422. a = GetNextNamespaceDeclarationGlobal(a);
  423. }
  424. if (localName == "xml") {
  425. source = GetXmlNamespaceDeclaration();
  426. parent = e;
  427. return true;
  428. }
  429. }
  430. return false;
  431. }
  432. public override bool MoveToNext() {
  433. XNode n = source as XNode;
  434. if (n != null) {
  435. XContainer c = n.parent;
  436. if (c != null && n != c.content) {
  437. do {
  438. XNode next = n.next;
  439. if (IsContent(c, next) && !(n is XText && next is XText)) {
  440. source = next;
  441. return true;
  442. }
  443. n = next;
  444. } while (n != c.content);
  445. }
  446. }
  447. return false;
  448. }
  449. public override bool MoveToNext(string localName, string namespaceName) {
  450. XNode n = source as XNode;
  451. if (n != null) {
  452. XContainer c = n.parent;
  453. if (c != null && n != c.content) {
  454. do {
  455. n = n.next;
  456. XElement e = n as XElement;
  457. if (e != null &&
  458. e.Name.LocalName == localName &&
  459. e.Name.NamespaceName == namespaceName) {
  460. source = e;
  461. return true;
  462. }
  463. } while (n != c.content);
  464. }
  465. }
  466. return false;
  467. }
  468. public override bool MoveToNext(XPathNodeType type) {
  469. XNode n = source as XNode;
  470. if (n != null) {
  471. XContainer c = n.parent;
  472. if (c != null && n != c.content) {
  473. int mask = GetElementContentMask(type);
  474. if ((TextMask & mask) != 0 && c.parent == null && c is XDocument) {
  475. mask &= ~TextMask;
  476. }
  477. do {
  478. XNode next = n.next;
  479. if (((1 << (int)next.NodeType) & mask) != 0 && !(n is XText && next is XText)) {
  480. source = next;
  481. return true;
  482. }
  483. n = next;
  484. } while (n != c.content);
  485. }
  486. }
  487. return false;
  488. }
  489. public override bool MoveToNextAttribute() {
  490. XAttribute a = source as XAttribute;
  491. if (a != null && parent == null) {
  492. XElement e = (XElement)a.parent;
  493. if (e != null) {
  494. while (a != e.lastAttr) {
  495. a = a.next;
  496. if (!a.IsNamespaceDeclaration) {
  497. source = a;
  498. return true;
  499. }
  500. }
  501. }
  502. }
  503. return false;
  504. }
  505. public override bool MoveToNextNamespace(XPathNamespaceScope scope) {
  506. XAttribute a = source as XAttribute;
  507. if (a != null && parent != null && !IsXmlNamespaceDeclaration(a)) {
  508. switch (scope) {
  509. case XPathNamespaceScope.Local:
  510. if (a.parent != parent) {
  511. return false;
  512. }
  513. a = GetNextNamespaceDeclarationLocal(a);
  514. break;
  515. case XPathNamespaceScope.ExcludeXml:
  516. do {
  517. a = GetNextNamespaceDeclarationGlobal(a);
  518. } while (a != null &&
  519. (a.Name.LocalName == "xml" ||
  520. HasNamespaceDeclarationInScope(a, parent)));
  521. break;
  522. case XPathNamespaceScope.All:
  523. do {
  524. a = GetNextNamespaceDeclarationGlobal(a);
  525. } while (a != null &&
  526. HasNamespaceDeclarationInScope(a, parent));
  527. if (a == null &&
  528. !HasNamespaceDeclarationInScope(GetXmlNamespaceDeclaration(), parent)) {
  529. a = GetXmlNamespaceDeclaration();
  530. }
  531. break;
  532. }
  533. if (a != null) {
  534. source = a;
  535. return true;
  536. }
  537. }
  538. return false;
  539. }
  540. public override bool MoveToParent() {
  541. if (parent != null) {
  542. source = parent;
  543. parent = null;
  544. return true;
  545. }
  546. XObject o = (XObject)source;
  547. if (o.parent != null) {
  548. source = o.parent;
  549. return true;
  550. }
  551. return false;
  552. }
  553. public override bool MoveToPrevious() {
  554. XNode n = source as XNode;
  555. if (n != null) {
  556. XContainer c = n.parent;
  557. if (c != null) {
  558. XNode q = (XNode)c.content;
  559. if (q.next != n) {
  560. XNode p = null;
  561. do {
  562. q = q.next;
  563. if (IsContent(c, q)) {
  564. p = p is XText && q is XText ? p : q;
  565. }
  566. } while (q.next != n);
  567. if (p != null) {
  568. source = p;
  569. return true;
  570. }
  571. }
  572. }
  573. }
  574. return false;
  575. }
  576. public override XmlReader ReadSubtree() {
  577. XContainer c = source as XContainer;
  578. if (c == null) throw new InvalidOperationException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.InvalidOperation_BadNodeType, NodeType));
  579. return new XNodeReader(c, nameTable);
  580. }
  581. bool IXmlLineInfo.HasLineInfo() {
  582. IXmlLineInfo li = source as IXmlLineInfo;
  583. if (li != null) {
  584. return li.HasLineInfo();
  585. }
  586. return false;
  587. }
  588. int IXmlLineInfo.LineNumber {
  589. get {
  590. IXmlLineInfo li = source as IXmlLineInfo;
  591. if (li != null) {
  592. return li.LineNumber;
  593. }
  594. return 0;
  595. }
  596. }
  597. int IXmlLineInfo.LinePosition {
  598. get {
  599. IXmlLineInfo li = source as IXmlLineInfo;
  600. if (li != null) {
  601. return li.LinePosition;
  602. }
  603. return 0;
  604. }
  605. }
  606. static string CollectText(XText n) {
  607. string s = n.Value;
  608. if (n.parent != null) {
  609. while (n != n.parent.content) {
  610. n = n.next as XText;
  611. if (n == null) break;
  612. s += n.Value;
  613. }
  614. }
  615. return s;
  616. }
  617. static XmlNameTable CreateNameTable() {
  618. XmlNameTable nameTable = new NameTable();
  619. nameTable.Add(string.Empty);
  620. nameTable.Add(XNamespace.xmlnsPrefixNamespace);
  621. nameTable.Add(XNamespace.xmlPrefixNamespace);
  622. return nameTable;
  623. }
  624. static bool IsContent(XContainer c, XNode n) {
  625. if (c.parent != null || c is XElement) {
  626. return true;
  627. }
  628. return ((1 << (int)n.NodeType) & DocumentContentMask) != 0;
  629. }
  630. static bool IsSamePosition(XNodeNavigator n1, XNodeNavigator n2) {
  631. if (n1.source == n2.source && n1.parent == n2.parent) {
  632. return true;
  633. }
  634. // compare lazy text with eager text
  635. if (n1.parent != null ^ n2.parent != null) {
  636. XText t1 = n1.source as XText;
  637. if (t1 != null) {
  638. return (object)t1.Value == (object)n2.source && t1.parent == n2.parent;
  639. }
  640. XText t2 = n2.source as XText;
  641. if (t2 != null) {
  642. return (object)t2.Value == (object)n1.source && t2.parent == n1.parent;
  643. }
  644. }
  645. return false;
  646. }
  647. static bool IsXmlNamespaceDeclaration(XAttribute a) {
  648. return (object)a == (object)GetXmlNamespaceDeclaration();
  649. }
  650. static int GetElementContentMask(XPathNodeType type) {
  651. return ElementContentMasks[(int)type];
  652. }
  653. static XAttribute GetFirstNamespaceDeclarationGlobal(XElement e) {
  654. do {
  655. XAttribute a = GetFirstNamespaceDeclarationLocal(e);
  656. if (a != null) {
  657. return a;
  658. }
  659. e = e.parent as XElement;
  660. } while (e != null);
  661. return null;
  662. }
  663. static XAttribute GetFirstNamespaceDeclarationLocal(XElement e) {
  664. XAttribute a = e.lastAttr;
  665. if (a != null) {
  666. do {
  667. a = a.next;
  668. if (a.IsNamespaceDeclaration) {
  669. return a;
  670. }
  671. } while (a != e.lastAttr);
  672. }
  673. return null;
  674. }
  675. static XAttribute GetNextNamespaceDeclarationGlobal(XAttribute a) {
  676. XElement e = (XElement)a.parent;
  677. if (e == null) {
  678. return null;
  679. }
  680. XAttribute next = GetNextNamespaceDeclarationLocal(a);
  681. if (next != null) {
  682. return next;
  683. }
  684. e = e.parent as XElement;
  685. if (e == null) {
  686. return null;
  687. }
  688. return GetFirstNamespaceDeclarationGlobal(e);
  689. }
  690. static XAttribute GetNextNamespaceDeclarationLocal(XAttribute a) {
  691. XElement e = (XElement)a.parent;
  692. if (e == null) {
  693. return null;
  694. }
  695. while (a != e.lastAttr) {
  696. a = a.next;
  697. if (a.IsNamespaceDeclaration) {
  698. return a;
  699. }
  700. }
  701. return null;
  702. }
  703. static XAttribute GetXmlNamespaceDeclaration() {
  704. if (XmlNamespaceDeclaration == null) {
  705. System.Threading.Interlocked.CompareExchange(ref XmlNamespaceDeclaration, new XAttribute(XNamespace.Xmlns.GetName("xml"), XNamespace.xmlPrefixNamespace), null);
  706. }
  707. return XmlNamespaceDeclaration;
  708. }
  709. static bool HasNamespaceDeclarationInScope(XAttribute a, XElement e) {
  710. XName name = a.Name;
  711. while (e != null && e != a.parent) {
  712. if (e.Attribute(name) != null) {
  713. return true;
  714. }
  715. e = e.parent as XElement;
  716. }
  717. return false;
  718. }
  719. }
  720. struct XPathEvaluator
  721. {
  722. public object Evaluate<T>(XNode node, string expression, IXmlNamespaceResolver resolver) where T : class {
  723. XPathNavigator navigator = node.CreateNavigator();
  724. object result = navigator.Evaluate(expression, resolver);
  725. if (result is XPathNodeIterator) {
  726. return EvaluateIterator<T>((XPathNodeIterator)result);
  727. }
  728. if (!(result is T)) throw new InvalidOperationException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.InvalidOperation_UnexpectedEvaluation, result.GetType()));
  729. return (T)result;
  730. }
  731. IEnumerable<T> EvaluateIterator<T>(XPathNodeIterator result) {
  732. foreach (XPathNavigator navigator in result) {
  733. object r = navigator.UnderlyingObject;
  734. if (!(r is T)) throw new InvalidOperationException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.InvalidOperation_UnexpectedEvaluation, r.GetType()));
  735. yield return (T)r;
  736. XText t = r as XText;
  737. if (t != null && t.parent != null) {
  738. while (t != t.parent.content) {
  739. t = t.next as XText;
  740. if (t == null) break;
  741. yield return (T)(object)t;
  742. }
  743. }
  744. }
  745. }
  746. }
  747. /// <summary>
  748. /// Extension methods
  749. /// </summary>
  750. public static class Extensions
  751. {
  752. /// <summary>
  753. /// Creates an <see cref="XPathNavigator"/> for a given <see cref="XNode"/>
  754. /// </summary>
  755. /// <param name="node">Extension point <see cref="XNode"/></param>
  756. /// <returns>An <see cref="XPathNavigator"/></returns>
  757. public static XPathNavigator CreateNavigator(this XNode node) {
  758. return node.CreateNavigator(null);
  759. }
  760. /// <summary>
  761. /// Creates an <see cref="XPathNavigator"/> for a given <see cref="XNode"/>
  762. /// </summary>
  763. /// <param name="node">Extension point <see cref="XNode"/></param>
  764. /// <param name="nameTable">The <see cref="XmlNameTable"/> to be used by
  765. /// the <see cref="XPathNavigator"/></param>
  766. /// <returns>An <see cref="XPathNavigator"/></returns>
  767. public static XPathNavigator CreateNavigator(this XNode node, XmlNameTable nameTable) {
  768. if (node == null) throw new ArgumentNullException("node");
  769. if (node is XDocumentType) throw new ArgumentException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.Argument_CreateNavigator, XmlNodeType.DocumentType));
  770. XText text = node as XText;
  771. if (text != null) {
  772. if (text.parent is XDocument) throw new ArgumentException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.Argument_CreateNavigator, XmlNodeType.Whitespace));
  773. node = CalibrateText(text);
  774. }
  775. return new XNodeNavigator(node, nameTable);
  776. }
  777. /// <summary>
  778. /// Evaluates an XPath expression
  779. /// </summary>
  780. /// <param name="node">Extension point <see cref="XNode"/></param>
  781. /// <param name="expression">The XPath expression</param>
  782. /// <returns>The result of evaluating the expression which can be typed as bool, double, string or
  783. /// IEnumerable</returns>
  784. public static object XPathEvaluate(this XNode node, string expression) {
  785. return node.XPathEvaluate(expression, null);
  786. }
  787. /// <summary>
  788. /// Evaluates an XPath expression
  789. /// </summary>
  790. /// <param name="node">Extension point <see cref="XNode"/></param>
  791. /// <param name="expression">The XPath expression</param>
  792. /// <param name="resolver">A <see cref="IXmlNamespaceResolver"> for the namespace
  793. /// prefixes used in the XPath expression</see></param>
  794. /// <returns>The result of evaluating the expression which can be typed as bool, double, string or
  795. /// IEnumerable</returns>
  796. public static object XPathEvaluate(this XNode node, string expression, IXmlNamespaceResolver resolver) {
  797. if (node == null) throw new ArgumentNullException("node");
  798. return new XPathEvaluator().Evaluate<object>(node, expression, resolver);
  799. }
  800. /// <summary>
  801. /// Select an <see cref="XElement"/> using a XPath expression
  802. /// </summary>
  803. /// <param name="node">Extension point <see cref="XNode"/></param>
  804. /// <param name="expression">The XPath expression</param>
  805. /// <returns>An <see cref="XElement"> or null</see></returns>
  806. public static XElement XPathSelectElement(this XNode node, string expression) {
  807. return node.XPathSelectElement(expression, null);
  808. }
  809. /// <summary>
  810. /// Select an <see cref="XElement"/> using a XPath expression
  811. /// </summary>
  812. /// <param name="node">Extension point <see cref="XNode"/></param>
  813. /// <param name="expression">The XPath expression</param>
  814. /// <param name="resolver">A <see cref="IXmlNamespaceResolver"/> for the namespace
  815. /// prefixes used in the XPath expression</param>
  816. /// <returns>An <see cref="XElement"> or null</see></returns>
  817. public static XElement XPathSelectElement(this XNode node, string expression, IXmlNamespaceResolver resolver) {
  818. return node.XPathSelectElements(expression, resolver).FirstOrDefault();
  819. }
  820. /// <summary>
  821. /// Select a set of <see cref="XElement"/> using a XPath expression
  822. /// </summary>
  823. /// <param name="node">Extension point <see cref="XNode"/></param>
  824. /// <param name="expression">The XPath expression</param>
  825. /// <returns>An <see cref="IEnumerable&lt;XElement&gt;"/> corresponding to the resulting set of elements</returns>
  826. public static IEnumerable<XElement> XPathSelectElements(this XNode node, string expression) {
  827. return node.XPathSelectElements(expression, null);
  828. }
  829. /// <summary>
  830. /// Select a set of <see cref="XElement"/> using a XPath expression
  831. /// </summary>
  832. /// <param name="node">Extension point <see cref="XNode"/></param>
  833. /// <param name="expression">The XPath expression</param>
  834. /// <param name="resolver">A <see cref="IXmlNamespaceResolver"/> for the namespace
  835. /// prefixes used in the XPath expression</param>
  836. /// <returns>An <see cref="IEnumerable&lt;XElement&gt;"/> corresponding to the resulting set of elements</returns>
  837. public static IEnumerable<XElement> XPathSelectElements(this XNode node, string expression, IXmlNamespaceResolver resolver) {
  838. if (node == null) throw new ArgumentNullException("node");
  839. return (IEnumerable<XElement>)new XPathEvaluator().Evaluate<XElement>(node, expression, resolver);
  840. }
  841. static XText CalibrateText(XText n) {
  842. if (n.parent == null) {
  843. return n;
  844. }
  845. XNode p = (XNode)n.parent.content;
  846. while (true) {
  847. p = p.next;
  848. XText t = p as XText;
  849. if (t != null) {
  850. do {
  851. if (p == n) {
  852. return t;
  853. }
  854. p = p.next;
  855. } while (p is XText);
  856. }
  857. }
  858. }
  859. }
  860. }