/mcs/class/referencesource/System.Xml.Linq/System/Xml/Linq/XNodeNavigator.cs
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
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Xml;
- using System.Xml.Linq;
- namespace System.Xml.XPath
- {
- internal class XNodeNavigator : XPathNavigator, IXmlLineInfo
- {
- const int DocumentContentMask =
- (1 << (int)XmlNodeType.Element) |
- (1 << (int)XmlNodeType.ProcessingInstruction) |
- (1 << (int)XmlNodeType.Comment);
- static readonly int[] ElementContentMasks = {
- 0, // Root
- (1 << (int)XmlNodeType.Element), // Element
- 0, // Attribute
- 0, // Namespace
- (1 << (int)XmlNodeType.CDATA) |
- (1 << (int)XmlNodeType.Text), // Text
- 0, // SignificantWhitespace
- 0, // Whitespace
- (1 << (int)XmlNodeType.ProcessingInstruction), // ProcessingInstruction
- (1 << (int)XmlNodeType.Comment), // Comment
- (1 << (int)XmlNodeType.Element) |
- (1 << (int)XmlNodeType.CDATA) |
- (1 << (int)XmlNodeType.Text) |
- (1 << (int)XmlNodeType.ProcessingInstruction) |
- (1 << (int)XmlNodeType.Comment) // All
- };
- new const int TextMask =
- (1 << (int)XmlNodeType.CDATA) |
- (1 << (int)XmlNodeType.Text);
- static XAttribute XmlNamespaceDeclaration;
- // The navigator position is encoded by the tuple (source, parent).
- // Lazy text uses (instance, parent element). Namespace declaration uses
- // (instance, parent element). Common XObjects uses (instance, null).
- object source;
- XElement parent;
- XmlNameTable nameTable;
- public XNodeNavigator(XNode node, XmlNameTable nameTable) {
- this.source = node;
- this.nameTable = nameTable != null ? nameTable : CreateNameTable();
- }
- public XNodeNavigator(XNodeNavigator other) {
- source = other.source;
- parent = other.parent;
- nameTable = other.nameTable;
- }
- public override string BaseURI {
- get {
- XObject o = source as XObject;
- if (o != null) {
- return o.BaseUri;
- }
- if (parent != null) {
- return parent.BaseUri;
- }
- return string.Empty;
- }
- }
-
- public override bool HasAttributes {
- get {
- XElement e = source as XElement;
- if (e != null) {
- XAttribute a = e.lastAttr;
- if (a != null) {
- do {
- a = a.next;
- if (!a.IsNamespaceDeclaration) {
- return true;
- }
- } while (a != e.lastAttr);
- }
- }
- return false;
- }
- }
- public override bool HasChildren {
- get {
- XContainer c = source as XContainer;
- if (c != null && c.content != null) {
- XNode n = c.content as XNode;
- if (n != null) {
- do {
- n = n.next;
- if (IsContent(c, n)) {
- return true;
- }
- } while (n != c.content);
- return false;
- }
- string s = (string)c.content;
- if (s.Length != 0 && (c.parent != null || c is XElement)) {
- return true;
- }
- }
- return false;
- }
- }
- public override bool IsEmptyElement {
- get {
- XElement e = source as XElement;
- return e != null && e.IsEmpty;
- }
- }
-
- public override string LocalName {
- get { return nameTable.Add(GetLocalName()); }
- }
- string GetLocalName() {
- XElement e = source as XElement;
- if (e != null) {
- return e.Name.LocalName;
- }
- XAttribute a = source as XAttribute;
- if (a != null) {
- if (parent != null && a.Name.NamespaceName.Length == 0) {
- return string.Empty; // backcompat
- }
- return a.Name.LocalName;
- }
- XProcessingInstruction p = source as XProcessingInstruction;
- if (p != null) {
- return p.Target;
- }
- return string.Empty;
- }
- public override string Name {
- get {
- string prefix = GetPrefix();
- if (prefix.Length == 0) {
- return nameTable.Add(GetLocalName());
- }
- return nameTable.Add(string.Concat(prefix, ":", GetLocalName()));
- }
- }
- public override string NamespaceURI {
- get { return nameTable.Add(GetNamespaceURI()); }
- }
- string GetNamespaceURI() {
- XElement e = source as XElement;
- if (e != null) {
- return e.Name.NamespaceName;
- }
- XAttribute a = source as XAttribute;
- if (a != null) {
- if (parent != null) {
- return string.Empty; // backcompat
- }
- return a.Name.NamespaceName;
- }
- return string.Empty;
- }
- public override XmlNameTable NameTable {
- get { return nameTable; }
- }
- public override XPathNodeType NodeType {
- get {
- XObject o = source as XObject;
- if (o != null) {
- switch (o.NodeType) {
- case XmlNodeType.Element:
- return XPathNodeType.Element;
- case XmlNodeType.Attribute:
- if (parent != null) {
- return XPathNodeType.Namespace;
- }
- return XPathNodeType.Attribute;
- case XmlNodeType.Document:
- return XPathNodeType.Root;
- case XmlNodeType.Comment:
- return XPathNodeType.Comment;
- case XmlNodeType.ProcessingInstruction:
- return XPathNodeType.ProcessingInstruction;
- default:
- return XPathNodeType.Text;
- }
- }
- return XPathNodeType.Text;
- }
- }
- public override string Prefix {
- get { return nameTable.Add(GetPrefix()); }
- }
- string GetPrefix() {
- XElement e = source as XElement;
- if (e != null) {
- string prefix = e.GetPrefixOfNamespace(e.Name.Namespace);
- if (prefix != null) {
- return prefix;
- }
- return string.Empty;
- }
- XAttribute a = source as XAttribute;
- if (a != null) {
- if (parent != null) {
- return string.Empty; // backcompat
- }
- string prefix = a.GetPrefixOfNamespace(a.Name.Namespace);
- if (prefix != null) {
- return prefix;
- }
- }
- return string.Empty;
- }
- public override object UnderlyingObject {
- get {
- if (source is string) {
- // convert lazy text to eager text
- source = parent.LastNode;
- parent = null;
- }
- return source;
- }
- }
- public override string Value {
- get {
- XObject o = source as XObject;
- if (o != null) {
- switch (o.NodeType) {
- case XmlNodeType.Element:
- return ((XElement)o).Value;
- case XmlNodeType.Attribute:
- return ((XAttribute)o).Value;
- case XmlNodeType.Document:
- XElement root = ((XDocument)o).Root;
- return root != null ? root.Value : string.Empty;
- case XmlNodeType.Text:
- case XmlNodeType.CDATA:
- return CollectText((XText)o);
- case XmlNodeType.Comment:
- return ((XComment)o).Value;
- case XmlNodeType.ProcessingInstruction:
- return ((XProcessingInstruction)o).Data;
- default:
- return string.Empty;
- }
- }
- return (string)source;
- }
- }
- public override bool CheckValidity(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.Schema.ValidationEventHandler validationEventHandler) {
- throw new NotSupportedException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.NotSupported_CheckValidity));
- }
- public override XPathNavigator Clone() {
- return new XNodeNavigator(this);
- }
- public override bool IsSamePosition(XPathNavigator navigator) {
- XNodeNavigator other = navigator as XNodeNavigator;
- if (other == null) {
- return false;
- }
- return IsSamePosition(this, other);
- }
- public override bool MoveTo(XPathNavigator navigator) {
- XNodeNavigator other = navigator as XNodeNavigator;
- if (other != null) {
- source = other.source;
- parent = other.parent;
- return true;
- }
- return false;
- }
- public override bool MoveToAttribute(string localName, string namespaceName) {
- XElement e = source as XElement;
- if (e != null) {
- XAttribute a = e.lastAttr;
- if (a != null) {
- do {
- a = a.next;
- if (a.Name.LocalName == localName &&
- a.Name.NamespaceName == namespaceName &&
- !a.IsNamespaceDeclaration) {
- source = a;
- return true;
- }
- } while (a != e.lastAttr);
- }
- }
- return false;
- }
- public override bool MoveToChild(string localName, string namespaceName) {
- XContainer c = source as XContainer;
- if (c != null && c.content != null) {
- XNode n = c.content as XNode;
- if (n != null) {
- do {
- n = n.next;
- XElement e = n as XElement;
- if (e != null &&
- e.Name.LocalName == localName &&
- e.Name.NamespaceName == namespaceName) {
- source = e;
- return true;
- }
- } while (n != c.content);
- }
- }
- return false;
- }
- public override bool MoveToChild(XPathNodeType type) {
- XContainer c = source as XContainer;
- if (c != null && c.content != null) {
- XNode n = c.content as XNode;
- if (n != null) {
- int mask = GetElementContentMask(type);
- if ((TextMask & mask) != 0 && c.parent == null && c is XDocument) {
- mask &= ~TextMask;
- }
- do {
- n = n.next;
- if (((1 << (int)n.NodeType) & mask) != 0) {
- source = n;
- return true;
- }
- } while (n != c.content);
- return false;
- }
- string s = (string)c.content;
- if (s.Length != 0) {
- int mask = GetElementContentMask(type);
- if ((TextMask & mask) != 0 && c.parent == null && c is XDocument) {
- return false;
- }
- if (((1 << (int)XmlNodeType.Text) & mask) != 0) {
- source = s;
- parent = (XElement)c;
- return true;
- }
- }
- }
- return false;
- }
-
- public override bool MoveToFirstAttribute() {
- XElement e = source as XElement;
- if (e != null) {
- XAttribute a = e.lastAttr;
- if (a != null) {
- do {
- a = a.next;
- if (!a.IsNamespaceDeclaration) {
- source = a;
- return true;
- }
- } while (a != e.lastAttr);
- }
- }
- return false;
- }
-
- public override bool MoveToFirstChild() {
- XContainer c = source as XContainer;
- if (c != null && c.content != null) {
- XNode n = c.content as XNode;
- if (n != null) {
- do {
- n = n.next;
- if (IsContent(c, n)) {
- source = n;
- return true;
- }
- } while (n != c.content);
- return false;
- }
- string s = (string)c.content;
- if (s.Length != 0 && (c.parent != null || c is XElement)) {
- source = s;
- parent = (XElement)c;
- return true;
- }
- }
- return false;
- }
- public override bool MoveToFirstNamespace(XPathNamespaceScope scope) {
- XElement e = source as XElement;
- if (e != null) {
- XAttribute a = null;
- switch (scope) {
- case XPathNamespaceScope.Local:
- a = GetFirstNamespaceDeclarationLocal(e);
- break;
- case XPathNamespaceScope.ExcludeXml:
- a = GetFirstNamespaceDeclarationGlobal(e);
- while (a != null && a.Name.LocalName == "xml") {
- a = GetNextNamespaceDeclarationGlobal(a);
- }
- break;
- case XPathNamespaceScope.All:
- a = GetFirstNamespaceDeclarationGlobal(e);
- if (a == null) {
- a = GetXmlNamespaceDeclaration();
- }
- break;
- }
- if (a != null) {
- source = a;
- parent = e;
- return true;
- }
- }
- return false;
- }
- public override bool MoveToId(string id) {
- throw new NotSupportedException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.NotSupported_MoveToId));
- }
- public override bool MoveToNamespace(string localName) {
- XElement e = source as XElement;
- if (e != null) {
- if (localName == "xmlns") {
- return false; // backcompat
- }
- if (localName != null && localName.Length == 0) {
- localName = "xmlns"; // backcompat
- }
- XAttribute a = GetFirstNamespaceDeclarationGlobal(e);
- while (a != null) {
- if (a.Name.LocalName == localName) {
- source = a;
- parent = e;
- return true;
- }
- a = GetNextNamespaceDeclarationGlobal(a);
- }
- if (localName == "xml") {
- source = GetXmlNamespaceDeclaration();
- parent = e;
- return true;
- }
- }
- return false;
- }
-
- public override bool MoveToNext() {
- XNode n = source as XNode;
- if (n != null) {
- XContainer c = n.parent;
- if (c != null && n != c.content) {
- do {
- XNode next = n.next;
- if (IsContent(c, next) && !(n is XText && next is XText)) {
- source = next;
- return true;
- }
- n = next;
- } while (n != c.content);
- }
- }
- return false;
- }
- public override bool MoveToNext(string localName, string namespaceName) {
- XNode n = source as XNode;
- if (n != null) {
- XContainer c = n.parent;
- if (c != null && n != c.content) {
- do {
- n = n.next;
- XElement e = n as XElement;
- if (e != null &&
- e.Name.LocalName == localName &&
- e.Name.NamespaceName == namespaceName) {
- source = e;
- return true;
- }
- } while (n != c.content);
- }
- }
- return false;
- }
- public override bool MoveToNext(XPathNodeType type) {
- XNode n = source as XNode;
- if (n != null) {
- XContainer c = n.parent;
- if (c != null && n != c.content) {
- int mask = GetElementContentMask(type);
- if ((TextMask & mask) != 0 && c.parent == null && c is XDocument) {
- mask &= ~TextMask;
- }
- do {
- XNode next = n.next;
- if (((1 << (int)next.NodeType) & mask) != 0 && !(n is XText && next is XText)) {
- source = next;
- return true;
- }
- n = next;
- } while (n != c.content);
- }
- }
- return false;
- }
- public override bool MoveToNextAttribute() {
- XAttribute a = source as XAttribute;
- if (a != null && parent == null) {
- XElement e = (XElement)a.parent;
- if (e != null) {
- while (a != e.lastAttr) {
- a = a.next;
- if (!a.IsNamespaceDeclaration) {
- source = a;
- return true;
- }
- }
- }
- }
- return false;
- }
- public override bool MoveToNextNamespace(XPathNamespaceScope scope) {
- XAttribute a = source as XAttribute;
- if (a != null && parent != null && !IsXmlNamespaceDeclaration(a)) {
- switch (scope) {
- case XPathNamespaceScope.Local:
- if (a.parent != parent) {
- return false;
- }
- a = GetNextNamespaceDeclarationLocal(a);
- break;
- case XPathNamespaceScope.ExcludeXml:
- do {
- a = GetNextNamespaceDeclarationGlobal(a);
- } while (a != null &&
- (a.Name.LocalName == "xml" ||
- HasNamespaceDeclarationInScope(a, parent)));
- break;
- case XPathNamespaceScope.All:
- do {
- a = GetNextNamespaceDeclarationGlobal(a);
- } while (a != null &&
- HasNamespaceDeclarationInScope(a, parent));
- if (a == null &&
- !HasNamespaceDeclarationInScope(GetXmlNamespaceDeclaration(), parent)) {
- a = GetXmlNamespaceDeclaration();
- }
- break;
- }
- if (a != null) {
- source = a;
- return true;
- }
- }
- return false;
- }
- public override bool MoveToParent() {
- if (parent != null) {
- source = parent;
- parent = null;
- return true;
- }
- XObject o = (XObject)source;
- if (o.parent != null) {
- source = o.parent;
- return true;
- }
- return false;
- }
- public override bool MoveToPrevious() {
- XNode n = source as XNode;
- if (n != null) {
- XContainer c = n.parent;
- if (c != null) {
- XNode q = (XNode)c.content;
- if (q.next != n) {
- XNode p = null;
- do {
- q = q.next;
- if (IsContent(c, q)) {
- p = p is XText && q is XText ? p : q;
- }
- } while (q.next != n);
- if (p != null) {
- source = p;
- return true;
- }
- }
- }
- }
- return false;
- }
- public override XmlReader ReadSubtree() {
- XContainer c = source as XContainer;
- if (c == null) throw new InvalidOperationException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.InvalidOperation_BadNodeType, NodeType));
- return new XNodeReader(c, nameTable);
- }
- bool IXmlLineInfo.HasLineInfo() {
- IXmlLineInfo li = source as IXmlLineInfo;
- if (li != null) {
- return li.HasLineInfo();
- }
- return false;
- }
- int IXmlLineInfo.LineNumber {
- get {
- IXmlLineInfo li = source as IXmlLineInfo;
- if (li != null) {
- return li.LineNumber;
- }
- return 0;
- }
- }
- int IXmlLineInfo.LinePosition {
- get {
- IXmlLineInfo li = source as IXmlLineInfo;
- if (li != null) {
- return li.LinePosition;
- }
- return 0;
- }
- }
- static string CollectText(XText n) {
- string s = n.Value;
- if (n.parent != null) {
- while (n != n.parent.content) {
- n = n.next as XText;
- if (n == null) break;
- s += n.Value;
- }
- }
- return s;
- }
- static XmlNameTable CreateNameTable() {
- XmlNameTable nameTable = new NameTable();
- nameTable.Add(string.Empty);
- nameTable.Add(XNamespace.xmlnsPrefixNamespace);
- nameTable.Add(XNamespace.xmlPrefixNamespace);
- return nameTable;
- }
- static bool IsContent(XContainer c, XNode n) {
- if (c.parent != null || c is XElement) {
- return true;
- }
- return ((1 << (int)n.NodeType) & DocumentContentMask) != 0;
- }
- static bool IsSamePosition(XNodeNavigator n1, XNodeNavigator n2) {
- if (n1.source == n2.source && n1.parent == n2.parent) {
- return true;
- }
- // compare lazy text with eager text
- if (n1.parent != null ^ n2.parent != null) {
- XText t1 = n1.source as XText;
- if (t1 != null) {
- return (object)t1.Value == (object)n2.source && t1.parent == n2.parent;
- }
- XText t2 = n2.source as XText;
- if (t2 != null) {
- return (object)t2.Value == (object)n1.source && t2.parent == n1.parent;
- }
- }
- return false;
- }
- static bool IsXmlNamespaceDeclaration(XAttribute a) {
- return (object)a == (object)GetXmlNamespaceDeclaration();
- }
- static int GetElementContentMask(XPathNodeType type) {
- return ElementContentMasks[(int)type];
- }
- static XAttribute GetFirstNamespaceDeclarationGlobal(XElement e) {
- do {
- XAttribute a = GetFirstNamespaceDeclarationLocal(e);
- if (a != null) {
- return a;
- }
- e = e.parent as XElement;
- } while (e != null);
- return null;
- }
- static XAttribute GetFirstNamespaceDeclarationLocal(XElement e) {
- XAttribute a = e.lastAttr;
- if (a != null) {
- do {
- a = a.next;
- if (a.IsNamespaceDeclaration) {
- return a;
- }
- } while (a != e.lastAttr);
- }
- return null;
- }
- static XAttribute GetNextNamespaceDeclarationGlobal(XAttribute a) {
- XElement e = (XElement)a.parent;
- if (e == null) {
- return null;
- }
- XAttribute next = GetNextNamespaceDeclarationLocal(a);
- if (next != null) {
- return next;
- }
- e = e.parent as XElement;
- if (e == null) {
- return null;
- }
- return GetFirstNamespaceDeclarationGlobal(e);
- }
- static XAttribute GetNextNamespaceDeclarationLocal(XAttribute a) {
- XElement e = (XElement)a.parent;
- if (e == null) {
- return null;
- }
- while (a != e.lastAttr) {
- a = a.next;
- if (a.IsNamespaceDeclaration) {
- return a;
- }
- }
- return null;
- }
- static XAttribute GetXmlNamespaceDeclaration() {
- if (XmlNamespaceDeclaration == null) {
- System.Threading.Interlocked.CompareExchange(ref XmlNamespaceDeclaration, new XAttribute(XNamespace.Xmlns.GetName("xml"), XNamespace.xmlPrefixNamespace), null);
- }
- return XmlNamespaceDeclaration;
- }
- static bool HasNamespaceDeclarationInScope(XAttribute a, XElement e) {
- XName name = a.Name;
- while (e != null && e != a.parent) {
- if (e.Attribute(name) != null) {
- return true;
- }
- e = e.parent as XElement;
- }
- return false;
- }
- }
- struct XPathEvaluator
- {
- public object Evaluate<T>(XNode node, string expression, IXmlNamespaceResolver resolver) where T : class {
- XPathNavigator navigator = node.CreateNavigator();
- object result = navigator.Evaluate(expression, resolver);
- if (result is XPathNodeIterator) {
- return EvaluateIterator<T>((XPathNodeIterator)result);
- }
- if (!(result is T)) throw new InvalidOperationException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.InvalidOperation_UnexpectedEvaluation, result.GetType()));
- return (T)result;
- }
- IEnumerable<T> EvaluateIterator<T>(XPathNodeIterator result) {
- foreach (XPathNavigator navigator in result) {
- object r = navigator.UnderlyingObject;
- if (!(r is T)) throw new InvalidOperationException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.InvalidOperation_UnexpectedEvaluation, r.GetType()));
- yield return (T)r;
- XText t = r as XText;
- if (t != null && t.parent != null) {
- while (t != t.parent.content) {
- t = t.next as XText;
- if (t == null) break;
- yield return (T)(object)t;
- }
- }
- }
- }
- }
- /// <summary>
- /// Extension methods
- /// </summary>
- public static class Extensions
- {
- /// <summary>
- /// Creates an <see cref="XPathNavigator"/> for a given <see cref="XNode"/>
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <returns>An <see cref="XPathNavigator"/></returns>
- public static XPathNavigator CreateNavigator(this XNode node) {
- return node.CreateNavigator(null);
- }
- /// <summary>
- /// Creates an <see cref="XPathNavigator"/> for a given <see cref="XNode"/>
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <param name="nameTable">The <see cref="XmlNameTable"/> to be used by
- /// the <see cref="XPathNavigator"/></param>
- /// <returns>An <see cref="XPathNavigator"/></returns>
- public static XPathNavigator CreateNavigator(this XNode node, XmlNameTable nameTable) {
- if (node == null) throw new ArgumentNullException("node");
- if (node is XDocumentType) throw new ArgumentException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.Argument_CreateNavigator, XmlNodeType.DocumentType));
- XText text = node as XText;
- if (text != null) {
- if (text.parent is XDocument) throw new ArgumentException(System.Xml.Linq.Res.GetString(System.Xml.Linq.Res.Argument_CreateNavigator, XmlNodeType.Whitespace));
- node = CalibrateText(text);
- }
- return new XNodeNavigator(node, nameTable);
- }
- /// <summary>
- /// Evaluates an XPath expression
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <param name="expression">The XPath expression</param>
- /// <returns>The result of evaluating the expression which can be typed as bool, double, string or
- /// IEnumerable</returns>
- public static object XPathEvaluate(this XNode node, string expression) {
- return node.XPathEvaluate(expression, null);
- }
- /// <summary>
- /// Evaluates an XPath expression
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <param name="expression">The XPath expression</param>
- /// <param name="resolver">A <see cref="IXmlNamespaceResolver"> for the namespace
- /// prefixes used in the XPath expression</see></param>
- /// <returns>The result of evaluating the expression which can be typed as bool, double, string or
- /// IEnumerable</returns>
- public static object XPathEvaluate(this XNode node, string expression, IXmlNamespaceResolver resolver) {
- if (node == null) throw new ArgumentNullException("node");
- return new XPathEvaluator().Evaluate<object>(node, expression, resolver);
- }
- /// <summary>
- /// Select an <see cref="XElement"/> using a XPath expression
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <param name="expression">The XPath expression</param>
- /// <returns>An <see cref="XElement"> or null</see></returns>
- public static XElement XPathSelectElement(this XNode node, string expression) {
- return node.XPathSelectElement(expression, null);
- }
- /// <summary>
- /// Select an <see cref="XElement"/> using a XPath expression
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <param name="expression">The XPath expression</param>
- /// <param name="resolver">A <see cref="IXmlNamespaceResolver"/> for the namespace
- /// prefixes used in the XPath expression</param>
- /// <returns>An <see cref="XElement"> or null</see></returns>
- public static XElement XPathSelectElement(this XNode node, string expression, IXmlNamespaceResolver resolver) {
- return node.XPathSelectElements(expression, resolver).FirstOrDefault();
- }
-
- /// <summary>
- /// Select a set of <see cref="XElement"/> using a XPath expression
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <param name="expression">The XPath expression</param>
- /// <returns>An <see cref="IEnumerable<XElement>"/> corresponding to the resulting set of elements</returns>
- public static IEnumerable<XElement> XPathSelectElements(this XNode node, string expression) {
- return node.XPathSelectElements(expression, null);
- }
- /// <summary>
- /// Select a set of <see cref="XElement"/> using a XPath expression
- /// </summary>
- /// <param name="node">Extension point <see cref="XNode"/></param>
- /// <param name="expression">The XPath expression</param>
- /// <param name="resolver">A <see cref="IXmlNamespaceResolver"/> for the namespace
- /// prefixes used in the XPath expression</param>
- /// <returns>An <see cref="IEnumerable<XElement>"/> corresponding to the resulting set of elements</returns>
- public static IEnumerable<XElement> XPathSelectElements(this XNode node, string expression, IXmlNamespaceResolver resolver) {
- if (node == null) throw new ArgumentNullException("node");
- return (IEnumerable<XElement>)new XPathEvaluator().Evaluate<XElement>(node, expression, resolver);
- }
- static XText CalibrateText(XText n) {
- if (n.parent == null) {
- return n;
- }
- XNode p = (XNode)n.parent.content;
- while (true) {
- p = p.next;
- XText t = p as XText;
- if (t != null) {
- do {
- if (p == n) {
- return t;
- }
- p = p.next;
- } while (p is XText);
- }
- }
- }
- }
- }