|
From: Oleg T. <he...@us...> - 2005-10-19 14:46:41
|
Update of /cvsroot/mvp-xml/Common/v2/src/XPath In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28965/v2/src/XPath Added Files: DynamicContext.cs IHasXPathNavigator.cs IndexingXPathNavigator.cs SubtreeeXPathNavigator.cs XPathCache.cs XPathIteratorReader.cs XPathNavigatorIterator.cs XPathVariable.cs Log Message: --- NEW FILE: DynamicContext.cs --- #region using using System; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Xml; using System.Xml.XPath; using System.Xml.Xsl; #endregion using namespace Mvp.Xml.Common.XPath { /// <summary> /// Provides the evaluation context for fast execution and custom /// variables resolution. /// </summary> /// <remarks> /// This class is responsible for resolving variables during dynamic expression execution. /// <para>Discussed in http://weblogs.asp.net/cazzu/archive/2003/10/07/30888.aspx</para> /// <para>Author: Daniel Cazzulino, kz...@gm...</para> /// </remarks> public class DynamicContext : XsltContext { #region Private vars IDictionary<string, DynamicVariable> _variables = new Dictionary<string, DynamicVariable>(); #endregion Private #region Constructors & Initialization /// <summary> /// Initializes a new instance of the <see cref="DynamicContext"/> class. /// </summary> public DynamicContext() : base(new NameTable()) { } /// <summary> /// Initializes a new instance of the <see cref="DynamicContext"/> /// class with the specified <see cref="NameTable"/>. /// </summary> /// <param name="table">The NameTable to use.</param> public DynamicContext(NameTable table) : base(table) { } /// <summary> /// Initializes a new instance of the <see cref="DynamicContext"/> class. /// </summary> /// <param name="context">A previously filled context with the namespaces to use.</param> public DynamicContext(XmlNamespaceManager context) : this(context, new NameTable()) { } /// <summary> /// Initializes a new instance of the <see cref="DynamicContext"/> class. /// </summary> /// <param name="context">A previously filled context with the namespaces to use.</param> /// <param name="table">The NameTable to use.</param> public DynamicContext(XmlNamespaceManager context, NameTable table) : base(table) { object xml = table.Add(XmlNamespaces.Xml); object xmlns = table.Add(XmlNamespaces.XmlNs); if (context != null) { foreach (string prefix in context) { string uri = context.LookupNamespace(prefix); // Use fast object reference comparison to omit forbidden namespace declarations. if (Object.Equals(uri, xml) || Object.Equals(uri, xmlns)) continue; base.AddNamespace(prefix, uri); } } } #endregion Constructors & Initialization #region Common Overrides /// <summary> /// Implementation equal to <see cref="XsltContext.CompareDocument(string, string)"/>. /// </summary> public override int CompareDocument(string baseUri, string nextbaseUri) { return String.Compare(baseUri, nextbaseUri, false, System.Globalization.CultureInfo.InvariantCulture); } /// <summary> /// Same as <see cref="XmlNamespaceManager"/>. /// </summary> public override string LookupNamespace(string prefix) { string key = NameTable.Get(prefix); if (key == null) return null; else return base.LookupNamespace(key); } /// <summary> /// Same as <see cref="XmlNamespaceManager"/>. /// </summary> public override string LookupPrefix(string uri) { string key = NameTable.Get(uri); if (key == null) return null; else return base.LookupPrefix(key); } /// <summary> /// Same as <see cref="XsltContext.PreserveWhitespace(XPathNavigator)"/>. /// </summary> public override bool PreserveWhitespace(XPathNavigator node) { return true; } /// <summary> /// Same as <see cref="XsltContext.Whitespace"/>. /// </summary> public override bool Whitespace { get { return true; } } #endregion Common Overrides #region Public Members /// <summary> /// Shortcut method that compiles an expression using an empty navigator. /// </summary> /// <param name="xpath">The expression to compile</param> /// <returns>A compiled <see cref="XPathExpression"/>.</returns> public static XPathExpression Compile(string xpath) { return new XmlDocument().CreateNavigator().Compile(xpath); } #endregion Public Members #region Variable Handling Code /// <summary> /// Adds the variable to the dynamic evaluation context. /// </summary> /// <param name="name">The name of the variable to add to the context.</param> /// <param name="value">The value of the variable to add to the context.</param> /// <remarks> /// Value type conversion for XPath evaluation is as follows: /// <list type="table"> /// <listheader> /// <term>CLR Type</term> /// <description>XPath type</description> /// </listheader> /// <item> /// <term>System.String</term> /// <description>XPathResultType.String</description> /// </item> /// <item> /// <term>System.Double (or types that can be converted to)</term> /// <description>XPathResultType.Number</description> /// </item> /// <item> /// <term>System.Boolean</term> /// <description>XPathResultType.Boolean</description> /// </item> /// <item> /// <term>System.Xml.XPath.XPathNavigator</term> /// <description>XPathResultType.Navigator</description> /// </item> /// <item> /// <term>System.Xml.XPath.XPathNodeIterator</term> /// <description>XPathResultType.NodeSet</description> /// </item> /// <item> /// <term>Others</term> /// <description>XPathResultType.Any</description> /// </item> /// </list> /// <note type="note">See the topic "Compile, Select, Evaluate, and Matches with /// XPath and XPathExpressions" in MSDN documentation for additional information.</note> /// </remarks> /// <exception cref="ArgumentNullException">The <paramref name="value"/> is null.</exception> public void AddVariable(string name, object value) { if (value == null) throw new ArgumentNullException("value"); _variables[name] = new DynamicVariable(name, value); } /// <summary> /// See <see cref="XsltContext"/>. Not used in our implementation. /// </summary> public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes) { return null; } /// <summary> /// Resolves the dynamic variables added to the context. See <see cref="XsltContext"/>. /// </summary> public override IXsltContextVariable ResolveVariable(string prefix, string name) { return _variables[name] as IXsltContextVariable; } #endregion Variable Handling Code #region Internal DynamicVariable class /// <summary> /// Represents a variable during dynamic expression execution. /// </summary> internal class DynamicVariable : IXsltContextVariable { string _name; object _value; #region Public Members /// <summary> /// Initializes a new instance of the class. /// </summary> /// <param name="name">The name of the variable.</param> /// <param name="value">The value of the variable.</param> public DynamicVariable(string name, object value) { _name = name; _value = value; if (value is String) _type = XPathResultType.String; else if (value is bool) _type = XPathResultType.Boolean; else if (value is XPathNavigator) _type = XPathResultType.Navigator; else if (value is XPathNodeIterator) _type = XPathResultType.NodeSet; else { // Try to convert to double (native XPath numeric type) if (value is double) { _type = XPathResultType.Number; } else { if (value is IConvertible) { try { _value = Convert.ToDouble(value); // We suceeded, so it's a number. _type = XPathResultType.Number; } catch (FormatException) { _type = XPathResultType.Any; } catch (OverflowException) { _type = XPathResultType.Any; } } else { _type = XPathResultType.Any; } } } } #endregion Public Members #region IXsltContextVariable Implementation XPathResultType IXsltContextVariable.VariableType { get { return _type; } } XPathResultType _type; object IXsltContextVariable.Evaluate(XsltContext context) { return _value; } bool IXsltContextVariable.IsLocal { get { return false; } } bool IXsltContextVariable.IsParam { get { return false; } } #endregion IXsltContextVariable Implementation } #endregion Internal DynamicVariable class } } --- NEW FILE: XPathIteratorReader.cs --- #region using using System; using System.Collections; using System.Collections.Specialized; using System.IO; using System.Xml; using System.Xml.Serialization; using System.Xml.XPath; #endregion using namespace Mvp.Xml.Common.XPath { /// <summary> /// Provides an <see cref="XmlReader"/> over an /// <see cref="XPathNodeIterator"/>. /// </summary> /// <remarks> /// The reader exposes a new root element enclosing all navigators from the /// iterator. This root node is configured in the constructor, by /// passing the desired name and optional namespace for it. /// <para>Author: Daniel Cazzulino, kz...@gm...</para> /// See: http://weblogs.asp.net/cazzu/archive/2004/04/26/120684.aspx /// </remarks> public class XPathIteratorReader : XmlTextReader, IXmlSerializable { #region Fields // Holds the current child being read. XmlReader _current; // Holds the iterator passed to the ctor. XPathNodeIterator _iterator; // The name for the root element. XmlQualifiedName _rootname; #endregion Fields #region Ctor /// <summary> /// Parameterless constructor for XML serialization. /// </summary> /// <remarks>Supports the .NET serialization infrastructure. Don't use this /// constructor in your regular application.</remarks> [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public XPathIteratorReader() { } /// <summary> /// Initializes the reader, using the default <root> element. /// </summary> /// <param name="iterator">The iterator to expose as a single reader.</param> public XPathIteratorReader(XPathNodeIterator iterator) : this(iterator, "root", String.Empty) { } /// <summary> /// Initializes the reader. /// </summary> /// <param name="iterator">The iterator to expose as a single reader.</param> /// <param name="rootName">The name to use for the enclosing root element.</param> public XPathIteratorReader(XPathNodeIterator iterator, string rootName) : this(iterator, rootName, String.Empty) { } /// <summary> /// Initializes the reader. /// </summary> /// <param name="iterator">The iterator to expose as a single reader.</param> /// <param name="rootName">The name to use for the enclosing root element.</param> /// <param name="ns">The namespace URI of the root element.</param> public XPathIteratorReader(XPathNodeIterator iterator, string rootName, string ns) : base(new StringReader(String.Empty)) { _iterator = iterator.Clone(); _current = new FakedRootReader(rootName, ns, XmlNodeType.Element); _rootname = new XmlQualifiedName(rootName, ns); } #endregion Ctor #region Private Members /// <summary> /// Returns the XML representation of the current node and all its children. /// </summary> private string Serialize() { StringWriter sw = new StringWriter(System.Globalization.CultureInfo.CurrentCulture); XmlTextWriter tw = new XmlTextWriter(sw); tw.WriteNode(this, false); sw.Flush(); return sw.ToString(); } #endregion Private Members #region Properties /// <summary>See <see cref="XmlReader.AttributeCount"/></summary> public override int AttributeCount { get { return _current.AttributeCount; } } /// <summary>See <see cref="XmlReader.BaseURI"/></summary> public override string BaseURI { get { return _current.BaseURI; } } /// <summary>See <see cref="XmlReader.Depth"/></summary> public override int Depth { get { return _current.Depth + 1; } } /// <summary>See <see cref="XmlReader.EOF"/></summary> public override bool EOF { get { return _current.ReadState == ReadState.EndOfFile || _current.ReadState == ReadState.Closed; } } /// <summary>See <see cref="XmlReader.HasValue"/></summary> public override bool HasValue { get { return _current.HasValue; } } /// <summary>See <see cref="XmlReader.IsDefault"/></summary> public override bool IsDefault { get { return false; } } /// <summary>See <see cref="XmlReader.IsDefault"/></summary> public override bool IsEmptyElement { get { return _current.IsEmptyElement; } } /// <summary>See <see cref="XmlReader.this[string, string]"/></summary> public override string this[string name, string ns] { get { return _current[name, ns]; } } /// <summary>See <see cref="XmlReader.this[string]"/></summary> public override string this[string name] { get { return _current[name, String.Empty]; } } /// <summary>See <see cref="XmlReader.this[int]"/></summary> public override string this[int i] { get { return _current[i]; } } /// <summary>See <see cref="XmlReader.LocalName"/></summary> public override string LocalName { get { return _current.LocalName; } } /// <summary>See <see cref="XmlReader.Name"/></summary> public override string Name { get { return _current.Name; } } /// <summary>See <see cref="XmlReader.NamespaceURI"/></summary> public override string NamespaceURI { get { return _current.NamespaceURI; } } /// <summary>See <see cref="XmlReader.NameTable"/></summary> public override XmlNameTable NameTable { get { return _current.NameTable; } } /// <summary>See <see cref="XmlReader.NodeType"/></summary> public override XmlNodeType NodeType { get { return _current.NodeType; } } /// <summary>See <see cref="XmlReader.Prefix"/></summary> public override string Prefix { get { return _current.Prefix; } } /// <summary>See <see cref="XmlReader.QuoteChar"/></summary> public override char QuoteChar { get { return _current.QuoteChar; } } /// <summary>See <see cref="XmlReader.ReadState"/></summary> public override ReadState ReadState { get { return _current.ReadState; } } /// <summary>See <see cref="XmlReader.Value"/></summary> public override string Value { get { return _current.Value; } } /// <summary>See <see cref="XmlReader.XmlLang"/></summary> public override string XmlLang { get { return _current.XmlLang; } } /// <summary>See <see cref="XmlReader.XmlSpace"/></summary> public override XmlSpace XmlSpace { get { return XmlSpace.Default; } } #endregion Properties #region Methods /// <summary>See <see cref="XmlReader.Close"/></summary> public override void Close() { _current.Close(); } /// <summary>See <see cref="XmlReader.GetAttribute(string, string)"/></summary> public override string GetAttribute(string name, string ns) { return _current.GetAttribute(name, ns); } /// <summary>See <see cref="XmlReader.GetAttribute(string)"/></summary> public override string GetAttribute(string name) { return _current.GetAttribute(name); } /// <summary>See <see cref="XmlReader.GetAttribute(int)"/></summary> public override string GetAttribute(int i) { return _current.GetAttribute(i); } /// <summary>See <see cref="XmlReader.LookupNamespace"/></summary> public override string LookupNamespace(string prefix) { return _current.LookupNamespace(prefix); } /// <summary>See <see cref="XmlReader.MoveToAttribute(string, string)"/></summary> public override bool MoveToAttribute(string name, string ns) { return _current.MoveToAttribute(name, ns); } /// <summary>See <see cref="XmlReader.MoveToAttribute(string)"/></summary> public override bool MoveToAttribute(string name) { return _current.MoveToAttribute(name); } /// <summary>See <see cref="XmlReader.MoveToAttribute(int)"/></summary> public override void MoveToAttribute(int i) { _current.MoveToAttribute(i); } /// <summary>See <see cref="XmlReader.MoveToContent"/></summary> public override XmlNodeType MoveToContent() { return base.MoveToContent(); } /// <summary>See <see cref="XmlReader.MoveToElement"/></summary> public override bool MoveToElement() { return _current.MoveToElement(); } /// <summary>See <see cref="XmlReader.MoveToFirstAttribute"/></summary> public override bool MoveToFirstAttribute() { return _current.MoveToFirstAttribute(); } /// <summary>See <see cref="XmlReader.MoveToNextAttribute"/></summary> public override bool MoveToNextAttribute() { return _current.MoveToNextAttribute(); } /// <summary>See <see cref="XmlReader.Read"/></summary> public override bool Read() { // Return fast if state is no appropriate. if (_current.ReadState == ReadState.Closed || _current.ReadState == ReadState.EndOfFile) return false; bool read = _current.Read(); if (!read) { read = _iterator.MoveNext(); if (read) { // Just move to the next node and create the reader. _current = _iterator.Current.ReadSubtree(); return _current.Read(); } else { if (_current is FakedRootReader && _current.NodeType == XmlNodeType.EndElement) { // We're done! return false; } else { // We read all nodes in the iterator. Return to faked root end element. _current = new FakedRootReader(_rootname.Name, _rootname.Namespace, XmlNodeType.EndElement); return true; } } } return read; } /// <summary>See <see cref="XmlReader.ReadAttributeValue"/></summary> public override bool ReadAttributeValue() { return _current.ReadAttributeValue(); } /// <summary>See <see cref="XmlReader.ReadInnerXml"/></summary> public override string ReadInnerXml() { if (this.Read()) return Serialize(); return String.Empty; } /// <summary>See <see cref="XmlReader.ReadOuterXml"/></summary> public override string ReadOuterXml() { if (_current.ReadState != ReadState.Interactive) return String.Empty; return Serialize(); } /// <summary>See <see cref="XmlReader.Read"/></summary> public override void ResolveEntity() { // Not supported. } #endregion Methods #region IXmlSerializable Members /// <summary> /// See <see cref="IXmlSerializable.WriteXml"/>. /// </summary> public void WriteXml(XmlWriter writer) { writer.WriteNode(this, false); } /// <summary> /// See <see cref="IXmlSerializable.GetSchema"/>. /// </summary> public System.Xml.Schema.XmlSchema GetSchema() { return null; } /// <summary> /// See <see cref="IXmlSerializable.ReadXml"/>. /// </summary> public void ReadXml(XmlReader reader) { XPathDocument doc = new XPathDocument(reader); XPathNavigator nav = doc.CreateNavigator(); // Pull the faked root out. nav.MoveToFirstChild(); _rootname = new XmlQualifiedName(nav.LocalName, nav.NamespaceURI); // Get iterator for all child nodes. _iterator = nav.SelectChildren(XPathNodeType.All); } #endregion #region Internal Classes #region FakedRootReader private class FakedRootReader : XmlReader { public FakedRootReader(string name, string ns, XmlNodeType nodeType) { _name = name; _namespace = ns; _nodetype = nodeType; _state = nodeType == XmlNodeType.Element ? ReadState.Initial : ReadState.Interactive; } #region Properties /// <summary>See <see cref="XmlReader.AttributeCount"/></summary> public override int AttributeCount { get { return 0; } } /// <summary>See <see cref="XmlReader.BaseURI"/></summary> public override string BaseURI { get { return String.Empty; } } /// <summary>See <see cref="XmlReader.Depth"/></summary> public override int Depth { // Undo the depth increment of the outer reader. get { return -1; } } /// <summary>See <see cref="XmlReader.EOF"/></summary> public override bool EOF { get { return _state == ReadState.EndOfFile; } } /// <summary>See <see cref="XmlReader.HasValue"/></summary> public override bool HasValue { get { return false; } } /// <summary>See <see cref="XmlReader.IsDefault"/></summary> public override bool IsDefault { get { return false; } } /// <summary>See <see cref="XmlReader.IsDefault"/></summary> public override bool IsEmptyElement { get { return false; } } /// <summary>See <see cref="XmlReader.this[string, string]"/></summary> public override string this[string name, string ns] { get { return null; } } /// <summary>See <see cref="XmlReader.this[string]"/></summary> public override string this[string name] { get { return null; } } /// <summary>See <see cref="XmlReader.this[string]"/></summary> public override string this[int i] { get { return null; } } /// <summary>See <see cref="XmlReader.LocalName"/></summary> public override string LocalName { get { return _name; } } string _name; /// <summary>See <see cref="XmlReader.Name"/></summary> public override string Name { get { return _name; } } /// <summary>See <see cref="XmlReader.NamespaceURI"/></summary> public override string NamespaceURI { get { return _namespace; } } string _namespace; /// <summary>See <see cref="XmlReader.NameTable"/></summary> public override XmlNameTable NameTable { get { return null; } } /// <summary>See <see cref="XmlReader.NodeType"/></summary> public override XmlNodeType NodeType { get { return _state == ReadState.Initial ? XmlNodeType.None : _nodetype; } } XmlNodeType _nodetype; /// <summary>See <see cref="XmlReader.Prefix"/></summary> public override string Prefix { get { return String.Empty; } } /// <summary>See <see cref="XmlReader.QuoteChar"/></summary> public override char QuoteChar { get { return '"'; } } /// <summary>See <see cref="XmlReader.ReadState"/></summary> public override ReadState ReadState { get { return _state; } } ReadState _state; /// <summary>See <see cref="XmlReader.Value"/></summary> public override string Value { get { return String.Empty; } } /// <summary>See <see cref="XmlReader.XmlLang"/></summary> public override string XmlLang { get { return String.Empty; } } /// <summary>See <see cref="XmlReader.XmlSpace"/></summary> public override XmlSpace XmlSpace { get { return XmlSpace.Default; } } #endregion Properties #region Methods /// <summary>See <see cref="XmlReader.Close"/></summary> public override void Close() { _state = ReadState.Closed; } /// <summary>See <see cref="XmlReader.GetAttribute(string, string)"/></summary> public override string GetAttribute(string name, string ns) { return null; } /// <summary>See <see cref="XmlReader.GetAttribute(string)"/></summary> public override string GetAttribute(string name) { return null; } /// <summary>See <see cref="XmlReader.GetAttribute(int)"/></summary> public override string GetAttribute(int i) { return null; } /// <summary>See <see cref="XmlReader.LookupNamespace"/></summary> public override string LookupNamespace(string prefix) { return null; } /// <summary>See <see cref="XmlReader.MoveToAttribute(string, string)"/></summary> public override bool MoveToAttribute(string name, string ns) { return false; } /// <summary>See <see cref="XmlReader.MoveToAttribute(string)"/></summary> public override bool MoveToAttribute(string name) { return false; } /// <summary>See <see cref="XmlReader.MoveToAttribute(int)"/></summary> public override void MoveToAttribute(int i) { } public override XmlNodeType MoveToContent() { if (_state == ReadState.Initial) _state = ReadState.Interactive; return _nodetype; } /// <summary>See <see cref="XmlReader.MoveToElement"/></summary> public override bool MoveToElement() { return false; } /// <summary>See <see cref="XmlReader.MoveToFirstAttribute"/></summary> public override bool MoveToFirstAttribute() { return false; } /// <summary>See <see cref="XmlReader.MoveToNextAttribute"/></summary> public override bool MoveToNextAttribute() { return false; } /// <summary>See <see cref="XmlReader.Read"/></summary> public override bool Read() { if (_state == ReadState.Initial) { _state = ReadState.Interactive; return true; } if (_state == ReadState.Interactive && _nodetype == XmlNodeType.EndElement) { _state = ReadState.EndOfFile; return false; } return false; } /// <summary>See <see cref="XmlReader.ReadAttributeValue"/></summary> public override bool ReadAttributeValue() { return false; } /// <summary>See <see cref="XmlReader.ReadInnerXml"/></summary> public override string ReadInnerXml() { return String.Empty; } /// <summary>See <see cref="XmlReader.ReadOuterXml"/></summary> public override string ReadOuterXml() { return String.Empty; } /// <summary>See <see cref="XmlReader.Read"/></summary> public override void ResolveEntity() { // Not supported. } #endregion Methods } #endregion FakedRootReader #endregion Internal Classes } } --- NEW FILE: IndexingXPathNavigator.cs --- #region using using System; using System.Collections.Generic; using System.Xml; using System.Xml.XPath; using System.Xml.Xsl; using System.Reflection; #endregion using namespace Mvp.Xml.Common.XPath { /// <summary> /// IndexingXPathNavigator enables lazy or eager indexing of any XML store /// (XmlDocument, XPathDocument or any other IXPathNavigable store) thus /// providing alternative way to select nodes directly from built index table /// and not searhing the tree. This allows drastically decrease selection time /// on preindexed selections. /// </summary> /// <remarks>Author: Oleg Tkachenko, ol...@tk... /// Contributors: Daniel Cazzulino, kz...@gm... /// <para>See http://www.tkachenko.com/blog/archives/000194.html</para> /// </remarks> public class IndexingXPathNavigator : XPathNavigator { #region Fields & Ctor private XPathNavigator nav; private XPathNavigatorIndexManager manager; /// <summary> /// Creates IndexingXPathNavigator over specified XPathNavigator. /// </summary> /// <param name="navigator">Core XPathNavigator</param> public IndexingXPathNavigator(XPathNavigator navigator) { this.nav = navigator; manager = new XPathNavigatorIndexManager(); } #endregion Fields & Ctor #region Public Methods /// <summary> /// Builds indexes according to defined keys. /// </summary> public void BuildIndexes() { manager.BuildIndexes(); } /// <summary> /// Adds named key for use with key() function. /// </summary> /// <param name="keyName">The name of the key</param> /// <param name="match">XPath pattern, defining the nodes to which /// this key is applicable</param> /// <param name="use">XPath expression used to determine /// the value of the key for each matching node</param> public virtual void AddKey(string keyName, string match, string use) { KeyDef key = new KeyDef(nav, match, use); manager.AddKey(nav, keyName, key); } #endregion Public Methods #region Important Overrides /// <summary> /// Compiles XPath expressions using base XPathNavigator.Compile() /// method and set IndexingXsltContext instance to the result of /// the compilation so compiled expressions support key() extension /// function. /// </summary> /// <param name="xpath">XPath expression to complile</param> /// <returns>Compiled XPath expression with augmented context /// to support key() extension function</returns> public override XPathExpression Compile(string xpath) { XPathExpression expr = base.Compile(xpath); expr.SetContext(new IndexingXsltContext(manager, nav.NameTable)); return expr; } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> /// <param name="xpath">A string representing an XPath expression</param> /// <returns>An XPathNodeIterator pointing to the selected node set</returns> public override XPathNodeIterator Select(string xpath) { XPathExpression expr = Compile(xpath); return base.Select(expr); } /// <summary> /// Creates new cloned version of the IndexingXPathNavigator. /// </summary> /// <returns>Cloned copy of the IndexingXPathNavigator</returns> public override XPathNavigator Clone() { return new IndexingXPathNavigator(nav.Clone()); } #endregion Important Overrides #region XPathNavigator dummy overrides /// <summary> /// See <see cref="XPathNavigator.NodeType"/>. /// </summary> public override XPathNodeType NodeType { get { return nav.NodeType; } } /// <summary> /// See <see cref="XPathNavigator.LocalName"/>. /// </summary> public override string LocalName { get { return nav.LocalName; } } /// <summary> /// See <see cref="XPathNavigator.Name"/>. /// </summary> public override string Name { get { return nav.Name; } } /// <summary> /// See <see cref="XPathNavigator.NamespaceURI"/>. /// </summary> public override string NamespaceURI { get { return nav.NamespaceURI; } } /// <summary> /// See <see cref="XPathNavigator.Prefix"/>. /// </summary> public override string Prefix { get { return nav.Prefix; } } /// <summary> /// See <see cref="XPathItem.Value"/>. /// </summary> public override string Value { get { return nav.Value; } } /// <summary> /// See <see cref="XPathNavigator.BaseURI"/>. /// </summary> public override String BaseURI { get { return nav.BaseURI; } } /// <summary> /// See <see cref="XPathNavigator.IsEmptyElement"/>. /// </summary> public override bool IsEmptyElement { get { return nav.IsEmptyElement; } } /// <summary> /// See <see cref="XPathNavigator.XmlLang"/>. /// </summary> public override string XmlLang { get { return nav.XmlLang; } } /// <summary> /// See <see cref="XPathNavigator.NameTable"/>. /// </summary> public override XmlNameTable NameTable { get { return nav.NameTable; } } /// <summary> /// See <see cref="XPathNavigator.HasAttributes"/>. /// </summary> public override bool HasAttributes { get { return nav.HasAttributes; } } /// <summary> /// See <see cref="XPathNavigator.GetAttribute"/>. /// </summary> public override string GetAttribute(string localName, string namespaceURI) { return nav.GetAttribute(localName, namespaceURI); } /// <summary> /// See <see cref="XPathNavigator.MoveToAttribute"/>. /// </summary> public override bool MoveToAttribute(string localName, string namespaceURI) { return nav.MoveToAttribute(localName, namespaceURI); } /// <summary> /// See <see cref="XPathNavigator.MoveToFirstAttribute"/>. /// </summary> public override bool MoveToFirstAttribute() { return nav.MoveToFirstAttribute(); } /// <summary> /// See <see cref="XPathNavigator.MoveToNextAttribute"/>. /// </summary> public override bool MoveToNextAttribute() { return nav.MoveToNextAttribute(); } /// <summary> /// See <see cref="XPathNavigator.GetNamespace"/>. /// </summary> public override string GetNamespace(string localname) { return nav.GetNamespace(localname); } /// <summary> /// See <see cref="XPathNavigator.MoveToNamespace"/>. /// </summary> public override bool MoveToNamespace(string @namespace) { return nav.MoveToNamespace(@namespace); } /// <summary> /// See <see cref="XPathNavigator.MoveToFirstNamespace(XPathNamespaceScope)"/>. /// </summary> public override bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope) { return nav.MoveToFirstNamespace(namespaceScope); } /// <summary> /// See <see cref="XPathNavigator.MoveToNextNamespace(XPathNamespaceScope)"/>. /// </summary> public override bool MoveToNextNamespace(XPathNamespaceScope namespaceScope) { return nav.MoveToNextNamespace(namespaceScope); } /// <summary> /// See <see cref="XPathNavigator.MoveToNext()"/>. /// </summary> public override bool MoveToNext() { return nav.MoveToNext(); } /// <summary> /// See <see cref="XPathNavigator.MoveToPrevious"/>. /// </summary> public override bool MoveToPrevious() { return nav.MoveToPrevious(); } /// <summary> /// See <see cref="XPathNavigator.MoveToFirst"/>. /// </summary> public override bool MoveToFirst() { return nav.MoveToFirst(); } /// <summary> /// See <see cref="XPathNavigator.MoveToFirstChild"/>. /// </summary> public override bool MoveToFirstChild() { return nav.MoveToFirstChild(); } /// <summary> /// See <see cref="XPathNavigator.MoveToParent"/>. /// </summary> public override bool MoveToParent() { return nav.MoveToParent(); } /// <summary> /// See <see cref="XPathNavigator.MoveToRoot"/>. /// </summary> public override void MoveToRoot() { nav.MoveToRoot(); } /// <summary> /// See <see cref="XPathNavigator.MoveTo"/>. /// </summary> public override bool MoveTo(XPathNavigator other) { return nav.MoveTo(other); } /// <summary> /// See <see cref="XPathNavigator.MoveToId"/>. /// </summary> public override bool MoveToId(string id) { return nav.MoveToId(id); } /// <summary> /// See <see cref="XPathNavigator.IsSamePosition"/>. /// </summary> public override bool IsSamePosition(XPathNavigator other) { return nav.IsSamePosition(other); } /// <summary> /// See <see cref="XPathNavigator.HasChildren"/>. /// </summary> public override bool HasChildren { get { return nav.HasChildren; } } #endregion #region Internal classes #region IndexingXsltContext /// <summary> /// XsltContext providing key() extension function. /// </summary> private class IndexingXsltContext: XsltContext { private KeyExtensionFunction keyFuncImpl; /// <summary> /// Creates new IndexingXsltContext. /// </summary> /// <param name="manager">Newly created IndexingXsltContext</param> /// <param name="nt">The name table to use.</param> public IndexingXsltContext(XPathNavigatorIndexManager manager, XmlNameTable nt) : base (nt as NameTable) { keyFuncImpl = new KeyExtensionFunction(manager); } /// <summary> /// Not applicable. /// </summary> public override int CompareDocument(string baseUri, string nextbaseUri) { return 0; } /// <summary> /// Not applicable. /// </summary> public override bool PreserveWhitespace(XPathNavigator node) { return true; } /// <summary> /// Not applicable. /// </summary> public override bool Whitespace { get { return true; } } /// <summary> /// No custom variables. /// </summary> public override IXsltContextVariable ResolveVariable(string prefix, string name) { return null; } /// <summary> /// Resolves key() extension function. /// </summary> /// <param name="prefix">The prefix of the function as it appears in the XPath expression</param> /// <param name="name">The name of the function</param> /// <param name="argTypes">An array of argument types for the function being resolved</param> /// <returns>KeyExtentionFunction implementation for key() extension function and null /// for anything else.</returns> public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] argTypes) { if (prefix.Length == 0 && name == "key") { if (argTypes.Length != 2) throw new ArgumentException(SR.GetString(SR.IndexingXPathNavigator_KeyWrongArguments)); else if (argTypes[0] != XPathResultType.String) throw new ArgumentException(SR.GetString(SR.IndexingXPathNavigator_KeyArgumentNotString)); else return keyFuncImpl; } else return null; } } #endregion IndexingXsltContext #region KeyExtensionFunction /// <summary> /// key() extension function implementation. /// </summary> private class KeyExtensionFunction : IXsltContextFunction { private const int args = 2; private static readonly XPathResultType[] argTypes = new XPathResultType[] {XPathResultType.String, XPathResultType.Any}; private XPathNavigatorIndexManager manager; /// <summary> /// Creates new KeyExtentionFunction object. /// </summary> /// <param name="manager">Index manager for accessing indexes</param> public KeyExtensionFunction(XPathNavigatorIndexManager manager) { this.manager = manager; } /// <summary> /// Gets the minimum number of arguments for the function. /// </summary> public int Minargs { get { return args; } } /// <summary> /// Gets the maximum number of arguments for the function. /// </summary> public int Maxargs { get { return args; } } /// <summary> /// Gets the supplied XPath types for the function's argument list. /// </summary> public XPathResultType[] ArgTypes { get { return argTypes; } } /// <summary> /// Gets the XPathResultType representing the XPath type returned by the function. /// </summary> public XPathResultType ReturnType { get { return XPathResultType.NodeSet; } } /// <summary> /// Provides the method to invoke the function with the given arguments in the given context. /// </summary> /// <param name="xsltContext">Given XSLT context</param> /// <param name="args">Array of actual arguments</param> /// <param name="docContext">Context document</param> /// <returns></returns> public object Invoke(XsltContext xsltContext, object[] args, XPathNavigator docContext) { return manager.GetNodes((string)args[0], args[1]); } } #endregion KeyExtensionFunction #region KeyDef /// <summary> /// Compilable key definition. /// </summary> private class KeyDef { private string match, use; private XPathExpression matchExpr, useExpr; private XPathNavigator nav; /// <summary> /// Creates a key definition with specified 'match' and 'use' expressions. /// </summary> /// <param name="nav">XPathNavigator to compile XPath expressions</param> /// <param name="match">XPath pattern, defining the nodes to /// which this key is applicable</param> /// <param name="use">XPath expression expression used to /// determine the value of the key for each matching node.</param> public KeyDef(XPathNavigator nav, string match, string use) { this.nav= nav; this.match = match; this.use = use; } /// <summary> /// XPath pattern, defining the nodes to /// which this key is applicable. /// </summary> public string Match { get { return match; } set { match = value; } } /// <summary> /// XPath expression expression used to /// determine the value of the key for each matching node. /// </summary> public string Use { get { return use; } set { use = value; } } /// <summary> /// Compiled XPath pattern, defining the nodes to /// which this key is applicable. /// </summary> public XPathExpression MatchExpr { get { if (matchExpr == null) matchExpr = nav.Compile(match); return matchExpr; } } /// <summary> /// Compiled XPath expression expression used to /// determine the value of the key for each matching node. /// </summary> public XPathExpression UseExpr { get { if (useExpr == null) useExpr = nav.Compile(use); return useExpr; } } /// <summary> /// Compiles match and use expressions. /// </summary> public void Compile() { matchExpr = nav.Compile(match); useExpr = nav.Compile(use); } } #endregion KeyDef #region XPathNavigatorIndex /// <summary> /// Index table for XPathNavigator. /// </summary> private class XPathNavigatorIndex { private IList<KeyDef> keys; private IDictionary<string, List<XPathNavigator>> index; private Type arrayIteratorType; /// <summary> /// Creates index over specified XPathNavigator. /// </summary> public XPathNavigatorIndex() { keys = new List<KeyDef>(); index = new Dictionary<string, List<XPathNavigator>>(); Assembly systemXml = typeof(XPathNodeIterator).Assembly; // TODO: is there another way? arrayIteratorType = systemXml.GetType("System.Xml.XPath.XPathArrayIterator"); } /// <summary> /// Adds a key. /// </summary> /// <param name="key">Key definition</param> public void AddKey(KeyDef key) { keys.Add(key); } /// <summary> /// Returns indexed nodes by a key value. /// </summary> /// <param name="keyValue">Key value</param> public XPathNodeIterator GetNodes(object keyValue) { //As per XSLT spec: //When the second argument to the key function is of type node-set, //then the result is the union of the result of applying the key function //to the string value of each of the nodes in the argument node-set. //When the second argument to key is of any other type, the argument is //converted to a string as if by a call to the string function; it //returns a node-set containing the nodes in the same document as //the context node that have a value for the named key equal to this string. List<XPathNavigator> indexedNodes = null; if (keyValue is XPathNodeIterator) { XPathNodeIterator nodes = keyValue as XPathNodeIterator; while (nodes.MoveNext()) { IList<XPathNavigator> chunkOfIndexedNodes = index[nodes.Current.Value]; if (chunkOfIndexedNodes != null) { if (indexedNodes == null) indexedNodes = new List<XPathNavigator>(); indexedNodes.AddRange(chunkOfIndexedNodes); } } } else { indexedNodes = index[keyValue.ToString()]; } if (indexedNodes == null) indexedNodes = new List<XPathNavigator>(0); return (XPathNodeIterator) Activator.CreateInstance( arrayIteratorType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance, null, new object[]{indexedNodes}, null ); } /// <summary> /// Matches given node against "match" pattern and adds it to /// the index table if the matching succeeded. /// </summary> /// <param name="node">Node to match</param> public void MatchNode(XPathNavigator node) { foreach (KeyDef keyDef in keys) { if (node.Matches(keyDef.MatchExpr)) { //Ok, let's calculate key value(s). As per XSLT spec: //If the result is a node-set, then for each node in the node-set, //the node that matches the pattern has a key of the specified name whose //value is the string-value of the node in the node-set; otherwise, the result //is converted to a string, and the node that matches the pattern has a //key of the specified name with value equal to that string. object key = node.Evaluate(keyDef.UseExpr); if (key is XPathNodeIterator) { XPathNodeIterator ni = (XPathNodeIterator)key; while (ni.MoveNext()) AddNodeToIndex(node, ni.Current.Value); } else { AddNodeToIndex(node, key.ToString()); } } } } /// <summary> /// Adds node to the index slot according to key value. /// </summary> /// <param name="node">Node to add to index</param> /// <param name="key">String key value</param> private void AddNodeToIndex(XPathNavigator node, string key) { //Get slot List<XPathNavigator> indexedNodes = index[key]; if (indexedNodes == null) { indexedNodes = new List<XPathNavigator>(); index.Add(key, indexedNodes); } indexedNodes.Add(node.Clone()); } } #endregion XPathNavigatorIndex #region XPathNavigatorIndexManager /// <summary> /// Index manager. Manages collection of named indexes. /// </summary> private class XPathNavigatorIndexManager { private IDictionary<string, XPathNavigatorIndex> indexes; private XPathNavigator nav; private bool indexed; /// <summary> /// Adds new key to the named index. /// </summary> /// <param name="nav">XPathNavigator over XML document to be indexed</param> /// <param name="indexName">Index name</param> /// <param name="key">Key definition</param> public void AddKey(XPathNavigator nav, string indexName, KeyDef key) { this.indexed = false; this.nav = nav; //Named indexes are stored in a hashtable. if (indexes == null) indexes = new Dictionary<string, XPathNavigatorIndex>(); XPathNavigatorIndex index = indexes[indexName]; if (index == null) { index = new XPathNavigatorIndex(); indexes.Add(indexName, index); } index.AddKey(key); } /// <summary> /// Builds indexes. /// </summary> public void BuildIndexes() { XPathNavigator doc = nav.Clone(); //Walk through the all document nodes adding each one matching //'match' expression to the index. doc.MoveToRoot(); //Select all nodes but namespaces and attributes XPathNodeIterator ni = doc.SelectDescendants(XPathNodeType.All, true); while (ni.MoveNext()) { if (ni.Current.NodeType == XPathNodeType.Element) { //Processs namespace nodes if (ni.Current.MoveToFirstNamespace()) { do { foreach (XPathNavigatorIndex index in indexes.Values) index.MatchNode(ni.Current); } while (ni.Current.MoveToNextNamespace()); ni.Current.MoveToParent(); } //process attributes if (ni.Current.MoveToFirstAttribute()) { do { foreach (XPathNavigatorIndex index in indexes.Values) index.MatchNode(ni.Current); } while (ni.Current.MoveToNextAttribute()); ni.Current.MoveToParent(); } } foreach (XPathNavigatorIndex index in indexes.Values) index.MatchNode(ni.Current); } indexed = true; } /// <summary> /// Get indexed nodes by index name and key value. /// </summary> /// <param name="indexName">Index name</param> /// <param name="value">Key value</param> /// <returns>Indexed nodes</returns> public XPathNodeIterator GetNodes(string indexName, object value) { if (!indexed) BuildIndexes(); XPathNavigatorIndex index = indexes[indexName]; return index == null? null : index.GetNodes(value); } } #endregion XPathNavigatorIndexManager #endregion Internal classes } } --- NEW FILE: IHasXPathNavigator.cs --- #region usage using System.Xml.XPath; #endregion namespace Mvp.Xml.Common.XPath { /// <summary> /// Enables a class to return an XPathNavigator from the current context or position. /// </summary> public interface IHasXPathNavigator { /// <summary> /// Returns the XPathNavigator for the current context or position. /// </summary> XPathNavigator GetNavigator(); } } --- NEW FILE: XPathCache.cs --- #region using using System; using System.Collections; using System.Xml; using System.Xml.XPath; #endregion using namespace Mvp.Xml.Common.XPath { /// <summary> /// Implements a cache of XPath queries, for faster execution. /// </summary> /// <remarks> /// Discussed at http://weblogs.asp.net/cazzu/archive/2004/04/02/106667.aspx /// <para>Author: Daniel Cazzulino, kz...@gm...</para> /// </remarks> public sealed class XPathCache { #region Ctor private XPathCache() { } #endregion Ctor #region Private Members /// <summary> /// Initially a simple hashtable. In the future should /// implement sliding expiration of unused expressions. /// </summary> private static IDictionary Cache { get { return _cache; } } static IDictionary _cache = new Hashtable(); /// <summary> /// Retrieves a cached compiled expression, or a newly compiled one. /// </summary> private static XPathExpression GetCompiledExpression(string expression, XPathNavigator source) { XPathExpression expr = (XPathExpression) Cache[expression]; // No double checks. At most we will compile twice. No big deal. if (expr == null) { expr = source.Compile(expression); Cache[expression] = expr; } return expr.Clone(); } /// <summary> /// Sets up the context for expression execution. /// </summary> private static XmlNamespaceManager PrepareContext(XPathNavigator source, XmlNamespaceManager context, XmlPrefix[] prefixes, XPathVariable[] variables) { XmlNamespaceManager ctx = context; // If we have variables, we need the dynamic context. if (variables != null) { DynamicContext dyn; if (ctx != null) dyn = new DynamicContext(ctx); else dyn = new DynamicContext(); // Add the variables we received. foreach (XPathVariable var in variables) { dyn.AddVariable(var.Name, var.Value); } ctx = dyn; } // If prefixes were added, append them to context. if (prefixes != null) { if (ctx == null) ctx = new XmlNamespaceManager(source.NameTable); foreach (XmlPrefix prefix in prefixes) ctx.AddNamespace(prefix.Prefix, prefix.NamespaceURI); } return ctx; } #region PrepareSort private static void PrepareSort(XPathExpression expression, XPathNavigator source, object sortExpression, XmlSortOrder order, XmlCaseOrder caseOrder, string lang, XmlDataType dataType) { if (sortExpression is string) { expression.AddSort( GetCompiledExpression((string)sortExpression, source), order, caseOrder, lang, dataType); } else if (sortExpression is XPathExpression) { expression.AddSort(sortExpression, order, caseOrder, lang, dataType); } else { throw new XPathException(SR.XPathCache_BadSortObject, null); } } private static void PrepareSort(XPathExpression expression, XPathNavigator source, object sortExpression, XmlSortOrder order, XmlCaseOrder caseOrder, string lang, XmlDataType dataType, XmlNamespaceManager context ) { XPathExpression se; if (sortExpression is string) { se = GetCompiledExpression((string)sortExpression, source); } else if (sortExpression is XPathExpression) { se = (XPathExpression) sortExpression; } else { throw new XPathException(SR.XPathCache_BadSortObject, null); } se.SetContext( context ); expression.AddSort(se, order, caseOrder, lang, dataType); } private static void PrepareSort(XPathExpression expression, XPathNavigator source, object sortExpression, IComparer comparer) { if (sortExpression is string) { expression.AddSort( GetCompiledExpression((string)sortExpression, source), comparer); } else if (sortExpression is XPathExpression) { expression.AddSort(sortExpression, comparer); } else { throw new XPathException(SR.XPathCache_BadSortObject, null); } } private static void PrepareSort(XPathExpression expression, XPathNavigator source, object sortExpression, IComparer comparer, XmlNamespaceManager context ) { XPathExpression se; if (sortExpression is string) { se = GetCompiledExpression((string)sortExpression, source); } else if (sortExpression is XPathExpression) { se = (XPathExpression) sortExpression; } else { throw new XPathException(SR.XPathCache_BadSortObject, null); } se.SetContext( context ); expression.AddSort(se, comparer); } #endregion PrepareSort #endregion Private Members #region Evaluate Overloads /// <summary> /// Evaluates the given expression and returns the typed result. /// </summary> public static object Evaluate(string expression, XPathNavigator source) { return source.Evaluate(GetCompiledExpression(expression, source)); } /// <summary> /// Evaluates the given expression and returns the typed result. /// </summary> public static object Evaluate(string expression, XPathNavigator source, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, null, variables)); return source.Evaluate(expr); } /// <summary> /// Evaluates the given expression and returns the typed result. /// </summary> public static object Evaluate(string expression, XPathNavigator source, XmlNamespaceManager context) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(context); return source.Evaluate(expr); } /// <summary> /// Evaluates the given expression and returns the typed result. /// </summary> public static object Evaluate(string expression, XPathNavigator source, params XmlPrefix[] prefixes) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, prefixes, null)); return source.Evaluate(expr); } /// <summary> /// Evaluates the given expression and returns the typed result. /// </summary> public static object Evaluate(string expression, XPathNavigator source, XmlNamespaceManager context, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, context, null, variables)); return source.Evaluate(expr); } /// <summary> /// Evaluates the given expression and returns the typed result. /// </summary> public static object Evaluate(string expression, XPathNavigator source, XmlPrefix[] prefixes, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, prefixes, variables)); return source.Evaluate(expr); } #endregion Evaluate Overloads #region Select Overloads /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator Select(string expression, XPathNavigator source) { return source.Select(GetCompiledExpression(expression, source)); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator Select(string expression, XPathNavigator source, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, null, variables)); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator Select(string expression, XPathNavigator source, XmlNamespaceManager context) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(context); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator Select(string expression, XPathNavigator source, params XmlPrefix[] prefixes ) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, prefixes, null)); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator Select(string expression, XPathNavigator source, XmlNamespaceManager context, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, context, null, variables)); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator Select(string expression, XPathNavigator source, XmlPrefix[] prefixes, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, prefixes, variables)); return source.Select(expr); } #endregion Select Overloads #region Sorted Select Overloads /// <summary> /// Selects a node set using the specified XPath expression and sort. /// </summary> /// <remarks> /// See <see cref="XPathExpression.AddSort(object, IComparer)"/>. /// </remarks> public static XPathNodeIterator SelectSorted(string expression, XPathNavigator source, object sortExpression, IComparer comparer) { XPathExpression expr = GetCompiledExpression(expression, source); PrepareSort(expr, source, sortExpression, comparer); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression and sort. /// </summary> /// <remarks> /// See <see cref="XPathExpression.AddSort(object, IComparer)"/>. /// </remarks> public static XPathNodeIterator SelectSorted(string expression, XPathNavigator source, object sortExpression, XmlSortOrder order, XmlCaseOrder caseOrder, string lang, XmlDataType dataType ) { XPathExpression expr = GetCompiledExpression(expression, source); PrepareSort(expr, source, sortExpression, order, caseOrder, lang, dataType); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator SelectSorted(string expression, XPathNavigator source, object sortExpression, IComparer comparer, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, null, variables)); PrepareSort(expr, source, sortExpression, comparer); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator SelectSorted(string expression, XPathNavigator source, object sortExpression, XmlSortOrder order, XmlCaseOrder caseOrder, string lang, XmlDataType dataType, params XPathVariable[] variables) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(PrepareContext(source, null, null, variables)); PrepareSort(expr, source, sortExpression, order, caseOrder, lang, dataType); return source.Select(expr); } /// <summary> /// Selects a node set using the specified XPath expression. /// </summary> public static XPathNodeIterator SelectSorted(string expression, XPathNavigator source, object sortExpression, XmlSortOrder order, XmlCaseOrder caseOrder, string lang, XmlDataType dataType, XmlNamespaceManager context) { XPathExpression expr = GetCompiledExpression(expression, source); expr.SetContext(context); PrepareSort(expr, source, sortExpression, order, caseOrder, lang, dataType, contex... [truncated message content] |