Core.Xml - support XPathExpression
This commit is contained in:
@@ -19,7 +19,34 @@ namespace Umbraco.Core.Xml
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
return navigator.Select(expression);
|
||||
|
||||
var compiled = navigator.Compile(expression);
|
||||
// Reflector shows that the standard XPathNavigator.Compile method just does
|
||||
// return XPathExpression.Compile(xpath);
|
||||
// only difference is, XPathNavigator.Compile is virtual so it could be overriden
|
||||
// by a class inheriting from XPathNavigator... there does not seem to be any
|
||||
// doing it in the Framework, though... so we'll assume it's much cleaner to use
|
||||
// the static compile:
|
||||
var compiled = XPathExpression.Compile(expression);
|
||||
|
||||
var context = new DynamicContext();
|
||||
foreach (var variable in variables)
|
||||
context.AddVariable(variable.Name, variable.Value);
|
||||
compiled.SetContext(context);
|
||||
return navigator.Select(compiled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a node set, using the specified XPath expression.
|
||||
/// </summary>
|
||||
/// <param name="navigator">A source XPathNavigator.</param>
|
||||
/// <param name="expression">An XPath expression.</param>
|
||||
/// <param name="variables">A set of XPathVariables.</param>
|
||||
/// <returns>An iterator over the nodes matching the specified expression.</returns>
|
||||
public static XPathNodeIterator Select(this XPathNavigator navigator, XPathExpression expression, params XPathVariable[] variables)
|
||||
{
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
return navigator.Select(expression);
|
||||
|
||||
var compiled = expression.Clone(); // clone for thread-safety
|
||||
var context = new DynamicContext();
|
||||
foreach (var variable in variables)
|
||||
context.AddVariable(variable.Name, variable.Value);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.XPath;
|
||||
|
||||
// source: mvpxml.codeplex.com
|
||||
|
||||
@@ -29,6 +30,24 @@ namespace Umbraco.Core.Xml
|
||||
return SelectNodes(source, expression, av);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a list of XmlNode matching an XPath expression.
|
||||
/// </summary>
|
||||
/// <param name="source">A source XmlNode.</param>
|
||||
/// <param name="expression">An XPath expression.</param>
|
||||
/// <param name="variables">A set of XPathVariables.</param>
|
||||
/// <returns>The list of XmlNode matching the XPath expression.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If <param name="variables" /> is <c>null</c>, or is empty, or contains only one single
|
||||
/// value which itself is <c>null</c>, then variables are ignored.</para>
|
||||
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
|
||||
/// </remarks>
|
||||
public static XmlNodeList SelectNodes(this XmlNode source, XPathExpression expression, IEnumerable<XPathVariable> variables)
|
||||
{
|
||||
var av = variables == null ? null : variables.ToArray();
|
||||
return SelectNodes(source, expression, av);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a list of XmlNode matching an XPath expression.
|
||||
/// </summary>
|
||||
@@ -50,6 +69,27 @@ namespace Umbraco.Core.Xml
|
||||
return XmlNodeListFactory.CreateNodeList(iterator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a list of XmlNode matching an XPath expression.
|
||||
/// </summary>
|
||||
/// <param name="source">A source XmlNode.</param>
|
||||
/// <param name="expression">An XPath expression.</param>
|
||||
/// <param name="variables">A set of XPathVariables.</param>
|
||||
/// <returns>The list of XmlNode matching the XPath expression.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If <param name="variables" /> is <c>null</c>, or is empty, or contains only one single
|
||||
/// value which itself is <c>null</c>, then variables are ignored.</para>
|
||||
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
|
||||
/// </remarks>
|
||||
public static XmlNodeList SelectNodes(this XmlNode source, XPathExpression expression, params XPathVariable[] variables)
|
||||
{
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
return source.SelectNodes(expression);
|
||||
|
||||
var iterator = source.CreateNavigator().Select(expression, variables);
|
||||
return XmlNodeListFactory.CreateNodeList(iterator);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the first XmlNode that matches an XPath expression.
|
||||
/// </summary>
|
||||
@@ -67,7 +107,25 @@ namespace Umbraco.Core.Xml
|
||||
var av = variables == null ? null : variables.ToArray();
|
||||
return SelectSingleNode(source, expression, av);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Selects the first XmlNode that matches an XPath expression.
|
||||
/// </summary>
|
||||
/// <param name="source">A source XmlNode.</param>
|
||||
/// <param name="expression">An XPath expression.</param>
|
||||
/// <param name="variables">A set of XPathVariables.</param>
|
||||
/// <returns>The first XmlNode that matches the XPath expression.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If <param name="variables" /> is <c>null</c>, or is empty, or contains only one single
|
||||
/// value which itself is <c>null</c>, then variables are ignored.</para>
|
||||
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
|
||||
/// </remarks>
|
||||
public static XmlNode SelectSingleNode(this XmlNode source, XPathExpression expression, IEnumerable<XPathVariable> variables)
|
||||
{
|
||||
var av = variables == null ? null : variables.ToArray();
|
||||
return SelectSingleNode(source, expression, av);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the first XmlNode that matches an XPath expression.
|
||||
/// </summary>
|
||||
@@ -87,5 +145,25 @@ namespace Umbraco.Core.Xml
|
||||
|
||||
return SelectNodes(source, expression, variables).Cast<XmlNode>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects the first XmlNode that matches an XPath expression.
|
||||
/// </summary>
|
||||
/// <param name="source">A source XmlNode.</param>
|
||||
/// <param name="expression">An XPath expression.</param>
|
||||
/// <param name="variables">A set of XPathVariables.</param>
|
||||
/// <returns>The first XmlNode that matches the XPath expression.</returns>
|
||||
/// <remarks>
|
||||
/// <para>If <param name="variables" /> is <c>null</c>, or is empty, or contains only one single
|
||||
/// value which itself is <c>null</c>, then variables are ignored.</para>
|
||||
/// <para>The XPath expression should reference variables as <c>$var</c>.</para>
|
||||
/// </remarks>
|
||||
public static XmlNode SelectSingleNode(this XmlNode source, XPathExpression expression, params XPathVariable[] variables)
|
||||
{
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
return source.SelectSingleNode(expression);
|
||||
|
||||
return SelectNodes(source, expression, variables).Cast<XmlNode>().FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,5 +213,27 @@ namespace Umbraco.Tests.CoreXml
|
||||
|
||||
Assert.AreEqual(5, count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void OldFrameworkXPathBugIsFixed()
|
||||
{
|
||||
// see http://bytes.com/topic/net/answers/177129-reusing-xpathexpression-multiple-iterations
|
||||
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml("<root><a><a1/><a2/></a><b/></root>");
|
||||
|
||||
var nav = doc.CreateNavigator();
|
||||
var expr = nav.Compile("*");
|
||||
|
||||
nav.MoveToFirstChild(); //root
|
||||
var iter1 = nav.Select(expr);
|
||||
iter1.MoveNext(); //root/a
|
||||
var iter2 = iter1.Current.Select(expr);
|
||||
iter2.MoveNext(); // /root/a/a1
|
||||
iter2.MoveNext(); // /root/a/a2
|
||||
|
||||
// used to fail because iter1 and iter2 would conflict
|
||||
Assert.IsTrue(iter1.MoveNext()); //root/b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Xml;
|
||||
using Umbraco.Web.Models;
|
||||
@@ -36,6 +37,19 @@ namespace Umbraco.Web
|
||||
return content == null ? new DynamicNull() : new DynamicPublishedContent(content).AsDynamic();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dynamic content resulting from an XPath query.
|
||||
/// </summary>
|
||||
/// <param name="cache">The contextual cache.</param>
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables</param>
|
||||
/// <returns>The dynamic content, or null.</returns>
|
||||
public static dynamic GetDynamicSingleByXPath(this ContextualPublishedContentCache cache, XPathExpression xpath, params XPathVariable[] vars)
|
||||
{
|
||||
var content = cache.GetSingleByXPath(xpath, vars);
|
||||
return content == null ? new DynamicNull() : new DynamicPublishedContent(content).AsDynamic();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets dynamic contents resulting from an XPath query.
|
||||
/// </summary>
|
||||
@@ -49,6 +63,19 @@ namespace Umbraco.Web
|
||||
return new DynamicPublishedContentList(content.Select(c => new DynamicPublishedContent(c)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets dynamic contents resulting from an XPath query.
|
||||
/// </summary>
|
||||
/// <param name="cache">The contextual cache.</param>
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables</param>
|
||||
/// <returns>The dynamic contents.</returns>
|
||||
public static dynamic GetDynamicByXPath(this ContextualPublishedContentCache cache, XPathExpression xpath, params XPathVariable[] vars)
|
||||
{
|
||||
var content = cache.GetByXPath(xpath, vars);
|
||||
return new DynamicPublishedContentList(content.Select(c => new DynamicPublishedContent(c)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets dynamic contents at root.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user