| File: XmlLocator.cs | Web Access |
| Project: src\xdt\src\Microsoft.Web.XmlTransform\Microsoft.Web.XmlTransform.csproj (Microsoft.Web.XmlTransform) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.Diagnostics; using Microsoft.Web.XmlTransform.Properties; namespace Microsoft.Web.XmlTransform { public enum XPathAxis { Child, Descendant, Parent, Ancestor, FollowingSibling, PrecedingSibling, Following, Preceding, Self, DescendantOrSelf, AncestorOrSelf, } public abstract class Locator { #region private data members private string argumentString = null; private IList<string> arguments = null; private string parentPath = null; private XmlElementContext context = null; private XmlTransformationLogger logger = null; #endregion protected virtual string ParentPath { get { return parentPath; } } protected XmlNode CurrentElement { get { return context.Element; } } virtual protected string NextStepNodeTest { get { if (!String.IsNullOrEmpty(CurrentElement.NamespaceURI) && String.IsNullOrEmpty(CurrentElement.Prefix)) { return String.Concat("_defaultNamespace:", CurrentElement.LocalName); } else { return CurrentElement.Name; } } } virtual protected XPathAxis NextStepAxis { get { return XPathAxis.Child; } } protected virtual string ConstructPath() { return AppendStep(ParentPath, NextStepAxis, NextStepNodeTest, ConstructPredicate()); } protected string AppendStep(string basePath, string stepNodeTest) { return AppendStep(basePath, XPathAxis.Child, stepNodeTest, String.Empty); } protected string AppendStep(string basePath, XPathAxis stepAxis, string stepNodeTest) { return AppendStep(basePath, stepAxis, stepNodeTest, String.Empty); } protected string AppendStep(string basePath, string stepNodeTest, string predicate) { return AppendStep(basePath, XPathAxis.Child, stepNodeTest, predicate); } protected string AppendStep(string basePath, XPathAxis stepAxis, string stepNodeTest, string predicate) { return String.Concat( EnsureTrailingSlash(basePath), GetAxisString(stepAxis), stepNodeTest, EnsureBracketedPredicate(predicate)); } protected virtual string ConstructPredicate() { return String.Empty; } protected XmlTransformationLogger Log { get { if (logger == null) { logger = context.GetService<XmlTransformationLogger>(); if (logger != null) { logger.CurrentReferenceNode = context.LocatorAttribute; } } return logger; } } protected string ArgumentString { get { return argumentString; } } protected IList<string> Arguments { get { if (arguments == null && argumentString != null) { arguments = XmlArgumentUtility.SplitArguments(argumentString); } return arguments; } } protected void EnsureArguments() { EnsureArguments(1); } protected void EnsureArguments(int min) { if (Arguments == null || Arguments.Count < min) { throw new XmlTransformationException(string.Format(System.Globalization.CultureInfo.CurrentCulture,Resources.XMLTRANSFORMATION_RequiresMinimumArguments, GetType().Name, min)); } } protected void EnsureArguments(int min, int max) { Debug.Assert(min <= max); if (min == max) { if (Arguments == null || Arguments.Count != min) { throw new XmlTransformationException(string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.XMLTRANSFORMATION_RequiresExactArguments, GetType().Name, min)); } } EnsureArguments(min); if (Arguments.Count > max) { throw new XmlTransformationException(string.Format(System.Globalization.CultureInfo.CurrentCulture, Resources.XMLTRANSFORMATION_TooManyArguments, GetType().Name)); } } internal string ConstructPath(string parentPath, XmlElementContext context, string argumentString) { Debug.Assert(this.parentPath == null && this.context == null && this.argumentString == null, "Do not call ConstructPath recursively"); string resultPath = String.Empty; if (this.parentPath == null && this.context == null && this.argumentString == null) { try { this.parentPath = parentPath; this.context = context; this.argumentString = argumentString; resultPath = ConstructPath(); } finally { this.parentPath = null; this.context = null; this.argumentString = null; this.arguments = null; ReleaseLogger(); } } return resultPath; } internal string ConstructParentPath(string parentPath, XmlElementContext context, string argumentString) { Debug.Assert(this.parentPath == null && this.context == null && this.argumentString == null, "Do not call ConstructPath recursively"); string resultPath = String.Empty; if (this.parentPath == null && this.context == null && this.argumentString == null) { try { this.parentPath = parentPath; this.context = context; this.argumentString = argumentString; resultPath = ParentPath; } finally { this.parentPath = null; this.context = null; this.argumentString = null; this.arguments = null; ReleaseLogger(); } } return resultPath; } private void ReleaseLogger() { if (logger != null) { logger.CurrentReferenceNode = null; logger = null; } } private string GetAxisString(XPathAxis stepAxis) { switch (stepAxis) { case XPathAxis.Child: return String.Empty; case XPathAxis.Descendant: return "descendant::"; case XPathAxis.Parent: return "parent::"; case XPathAxis.Ancestor: return "ancestor::"; case XPathAxis.FollowingSibling: return "following-sibling::"; case XPathAxis.PrecedingSibling: return "preceding-sibling::"; case XPathAxis.Following: return "following::"; case XPathAxis.Preceding: return "preceding::"; case XPathAxis.Self: return "self::"; case XPathAxis.DescendantOrSelf: return "/"; case XPathAxis.AncestorOrSelf: return "ancestor-or-self::"; default: Debug.Fail("There should be no XPathAxis enum value that isn't handled in this switch statement"); return String.Empty; } } private string EnsureTrailingSlash(string basePath) { if (!basePath.EndsWith("/", StringComparison.Ordinal)) { basePath = String.Concat(basePath, "/"); } return basePath; } private string EnsureBracketedPredicate(string predicate) { if (String.IsNullOrEmpty(predicate)) { return String.Empty; } else { if (!predicate.StartsWith("[", StringComparison.Ordinal)) { predicate = String.Concat("[", predicate); } if (!predicate.EndsWith("]", StringComparison.Ordinal)) { predicate = String.Concat(predicate, "]"); } return predicate; } } } }