Merge
This commit is contained in:
@@ -19,12 +19,36 @@ namespace Umbraco.Core.Xml
|
||||
return source.Select(expr);
|
||||
}
|
||||
|
||||
/// <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, string 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>
|
||||
/// <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, string expression, params XPathVariable[] variables)
|
||||
{
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
@@ -34,12 +58,36 @@ namespace Umbraco.Core.Xml
|
||||
return XmlNodeListFactory.CreateNodeList(iterator);
|
||||
}
|
||||
|
||||
/// <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, string 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>
|
||||
/// <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, string expression, params XPathVariable[] variables)
|
||||
{
|
||||
if (variables == null || variables.Length == 0 || variables[0] == null)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
@@ -45,7 +46,12 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
public virtual IPublishedContent GetSingleByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
/// <remarks>
|
||||
/// <para>If <param name="vars" /> 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 virtual IPublishedContent GetSingleByXPath(string xpath, params XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetSingleByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
@@ -56,7 +62,12 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <param name="xpath">The XPath query.</param>
|
||||
/// <param name="vars">Optional XPath variables.</param>
|
||||
/// <returns>The contents.</returns>
|
||||
public virtual IEnumerable<IPublishedContent> GetByXPath(string xpath, Core.Xml.XPathVariable[] vars)
|
||||
/// <remarks>
|
||||
/// <para>If <param name="vars" /> 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 virtual IEnumerable<IPublishedContent> GetByXPath(string xpath, params XPathVariable[] vars)
|
||||
{
|
||||
return _cache.GetByXPath(UmbracoContext, xpath, vars);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// Gets content identified by a route.
|
||||
/// </summary>
|
||||
/// <param name="route">The route</param>
|
||||
/// <param name="hideTopLevelNode">FIXME</param>
|
||||
/// <param name="hideTopLevelNode">A value forcing the HideTopLevelNode setting.</param>
|
||||
/// <returns>The content, or null.</returns>
|
||||
/// <remarks>A valid route is either a simple path eg <c>/foo/bar/nil</c> or a root node id and a path, eg <c>123/foo/bar/nil</c>.</remarks>
|
||||
public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null)
|
||||
@@ -51,11 +51,5 @@ namespace Umbraco.Web.PublishedCache
|
||||
{
|
||||
return _cache.GetRouteById(UmbracoContext, contentId);
|
||||
}
|
||||
|
||||
// FIXME do we want that one here?
|
||||
public IPublishedContent GetByUrlAlias(int rootNodeId, string alias)
|
||||
{
|
||||
return _cache.GetByUrlAlias(UmbracoContext, rootNodeId, alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,5 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// <param name="contentId">The content unique identifier.</param>
|
||||
/// <returns>The route.</returns>
|
||||
string GetRouteById(UmbracoContext umbracoContext, int contentId);
|
||||
|
||||
// FIXME do we want that one?
|
||||
IPublishedContent GetByUrlAlias(UmbracoContext umbracoContext, int rootNodeId, string alias);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,6 @@ namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
public static string Root { get { return "/root"; } }
|
||||
public string RootDocuments { get; private set; }
|
||||
public string DescendantDocumentById { get; private set; }
|
||||
public string DescendantDocumentByAlias { get; private set; }
|
||||
public string ChildDocumentByUrlName { get; private set; }
|
||||
public string ChildDocumentByUrlNameVar { get; private set; }
|
||||
public string RootDocumentWithLowestSortOrder { get; private set; }
|
||||
@@ -211,10 +210,6 @@ namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
case 0:
|
||||
RootDocuments = "/root/node";
|
||||
DescendantDocumentById = "//node [@id={0}]";
|
||||
DescendantDocumentByAlias = "//node[("
|
||||
+ "contains(concat(',',translate(data [@alias='umbracoUrlAlias'], ' ', ''),','),',{0},')"
|
||||
+ " or contains(concat(',',translate(data [@alias='umbracoUrlAlias'], ' ', ''),','),',/{0},')"
|
||||
+ ")]";
|
||||
ChildDocumentByUrlName = "/node [@urlName='{0}']";
|
||||
ChildDocumentByUrlNameVar = "/node [@urlName=${0}]";
|
||||
RootDocumentWithLowestSortOrder = "/root/node [not(@sortOrder > ../node/@sortOrder)][1]";
|
||||
@@ -224,10 +219,6 @@ namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
case 1:
|
||||
RootDocuments = "/root/* [@isDoc]";
|
||||
DescendantDocumentById = "//* [@isDoc and @id={0}]";
|
||||
DescendantDocumentByAlias = "//* [@isDoc and ("
|
||||
+ "contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',{0},')"
|
||||
+ " or contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',/{0},')"
|
||||
+ ")]";
|
||||
ChildDocumentByUrlName = "/* [@isDoc and @urlName='{0}']";
|
||||
ChildDocumentByUrlNameVar = "/* [@isDoc and @urlName=${0}]";
|
||||
RootDocumentWithLowestSortOrder = "/root/* [@isDoc and not(@sortOrder > ../* [@isDoc]/@sortOrder)][1]";
|
||||
@@ -307,36 +298,6 @@ namespace Umbraco.Web.PublishedCache.LegacyXmlCache
|
||||
: xml.SelectNodes(xpath, vars);
|
||||
return ConvertToDocuments(nodes);
|
||||
}
|
||||
|
||||
// FIXME MOVE THAT ONE OUT OF HERE?
|
||||
public IPublishedContent GetByUrlAlias(UmbracoContext umbracoContext, int rootNodeId, string alias)
|
||||
{
|
||||
if (alias == null) throw new ArgumentNullException("alias");
|
||||
|
||||
// the alias may be "foo/bar" or "/foo/bar"
|
||||
// there may be spaces as in "/foo/bar, /foo/nil"
|
||||
// these should probably be taken care of earlier on
|
||||
|
||||
alias = alias.TrimStart('/');
|
||||
var xpathBuilder = new StringBuilder();
|
||||
xpathBuilder.Append(XPathStringsDefinition.Root);
|
||||
|
||||
if (rootNodeId > 0)
|
||||
xpathBuilder.AppendFormat(XPathStrings.DescendantDocumentById, rootNodeId);
|
||||
|
||||
XPathVariable var = null;
|
||||
if (alias.Contains('\'') || alias.Contains('"'))
|
||||
{
|
||||
// use a var, escaping gets ugly pretty quickly
|
||||
var = new XPathVariable("alias", alias);
|
||||
alias = "$alias";
|
||||
}
|
||||
xpathBuilder.AppendFormat(XPathStrings.DescendantDocumentByAlias, alias);
|
||||
|
||||
var xpath = xpathBuilder.ToString();
|
||||
|
||||
return GetSingleByXPath(umbracoContext, xpath, var);
|
||||
}
|
||||
|
||||
public bool HasContent()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Xml;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
{
|
||||
@@ -24,7 +29,7 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
if (docRequest.Uri.AbsolutePath != "/") // no alias if "/"
|
||||
{
|
||||
node = docRequest.RoutingContext.UmbracoContext.ContentCache.GetByUrlAlias(
|
||||
node = FindContentByAlias(docRequest.RoutingContext.UmbracoContext.ContentCache,
|
||||
docRequest.HasDomain ? docRequest.Domain.RootNodeId : 0,
|
||||
docRequest.Uri.GetAbsolutePathDecoded());
|
||||
|
||||
@@ -37,5 +42,94 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
return node != null;
|
||||
}
|
||||
|
||||
private static IPublishedContent FindContentByAlias(ContextualPublishedContentCache cache, int rootNodeId, string alias)
|
||||
{
|
||||
if (alias == null) throw new ArgumentNullException("alias");
|
||||
|
||||
// the alias may be "foo/bar" or "/foo/bar"
|
||||
// there may be spaces as in "/foo/bar, /foo/nil"
|
||||
// these should probably be taken care of earlier on
|
||||
|
||||
alias = alias.TrimStart('/');
|
||||
var xpathBuilder = new StringBuilder();
|
||||
xpathBuilder.Append(XPathStringsDefinition.Root);
|
||||
|
||||
if (rootNodeId > 0)
|
||||
xpathBuilder.AppendFormat(XPathStrings.DescendantDocumentById, rootNodeId);
|
||||
|
||||
XPathVariable var = null;
|
||||
if (alias.Contains('\'') || alias.Contains('"'))
|
||||
{
|
||||
// use a var, as escaping gets ugly pretty quickly
|
||||
var = new XPathVariable("alias", alias);
|
||||
alias = "$alias";
|
||||
}
|
||||
xpathBuilder.AppendFormat(XPathStrings.DescendantDocumentByAlias, alias);
|
||||
|
||||
var xpath = xpathBuilder.ToString();
|
||||
|
||||
// note: it's OK if var is null, will be ignored
|
||||
return cache.GetSingleByXPath(xpath, var);
|
||||
}
|
||||
|
||||
#region XPath Strings
|
||||
|
||||
class XPathStringsDefinition
|
||||
{
|
||||
public int Version { get; private set; }
|
||||
|
||||
public static string Root { get { return "/root"; } }
|
||||
public string DescendantDocumentById { get; private set; }
|
||||
public string DescendantDocumentByAlias { get; private set; }
|
||||
|
||||
public XPathStringsDefinition(int version)
|
||||
{
|
||||
Version = version;
|
||||
|
||||
switch (version)
|
||||
{
|
||||
// legacy XML schema
|
||||
case 0:
|
||||
DescendantDocumentById = "//node [@id={0}]";
|
||||
DescendantDocumentByAlias = "//node[("
|
||||
+ "contains(concat(',',translate(data [@alias='umbracoUrlAlias'], ' ', ''),','),',{0},')"
|
||||
+ " or contains(concat(',',translate(data [@alias='umbracoUrlAlias'], ' ', ''),','),',/{0},')"
|
||||
+ ")]";
|
||||
break;
|
||||
|
||||
// default XML schema as of 4.10
|
||||
case 1:
|
||||
DescendantDocumentById = "//* [@isDoc and @id={0}]";
|
||||
DescendantDocumentByAlias = "//* [@isDoc and ("
|
||||
+ "contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',{0},')"
|
||||
+ " or contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',/{0},')"
|
||||
+ ")]";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception(string.Format("Unsupported Xml schema version '{0}').", version));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static XPathStringsDefinition _xPathStringsValue;
|
||||
static XPathStringsDefinition XPathStrings
|
||||
{
|
||||
get
|
||||
{
|
||||
// in theory XPathStrings should be a static variable that
|
||||
// we should initialize in a static ctor - but then test cases
|
||||
// that switch schemas fail - so cache and refresh when needed,
|
||||
// ie never when running the actual site
|
||||
|
||||
var version = global::umbraco.UmbracoSettings.UseLegacyXmlSchema ? 0 : 1;
|
||||
if (_xPathStringsValue == null || _xPathStringsValue.Version != version)
|
||||
_xPathStringsValue = new XPathStringsDefinition(version);
|
||||
return _xPathStringsValue;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user