在 XPathExpression 中使用 ms: xpath 函数

发布于 2024-08-22 20:47:25 字数 1739 浏览 9 评论 0原文

我正在尝试使用 Microsoft XPath 扩展函数(例如 ms:string-compare http ://msdn.microsoft.com/en-us/library/ms256114.aspx)位于 XPathExpression 对象内。

这些函数是 MSXML 库内部的扩展,如果我在 XslCompiledTransform 中使用它们(只需添加“ms”命名空间),它们就会像魅力一样工作:

var xsl =
    @"
<?xml version=""1.0"" encoding=""UTF-8""?>
<xsl:stylesheet version=""2.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"" 
        xmlns:xs=""http://www.w3.org/2001/XMLSchema"" 
        xmlns:fn=""http://www.w3.org/2005/xpath-functions"" 
        xmlns:ms=""urn:schemas-microsoft-com:xslt"">
 <xsl:output method=""xml"" version=""1.0"" encoding=""UTF-8"" indent=""yes""/>
 <xsl:template match=""/Data"">
  <xsl:element name=""Result"">
   <xsl:value-of select=""ms:string-compare(@timeout1, @timeout2)""/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>";

var xslDocument = new XmlDocument();
xslDocument.LoadXml(xsl);

var transform = new XslCompiledTransform();
transform.Load(xslDocument);

然后我尝试在 XPathExpression 中使用它们:

XPathNavigator nav = document.DocumentElement.CreateNavigator();
XPathExpression expr = nav.Compile("ms:string-compare(/Data/@timeout1, /Data/@timeout2)");

XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
manager.AddNamespace("ms", "urn:schemas-microsoft-com:xslt");
expr.SetContext(manager);

nav.Evaluate(expr);

但我得到一个异常“需要 XsltContext”由于未知功能而导致此查询”。

XsltContext 是一个特定的 XmlNamespaceManager,但我不知道是否可以在没有实际 XslCompiledTransform (它是抽象的)的情况下实例化它并将其用作我的表达式上下文。

有什么方法可以做到这一点(或任何其他方法在 XPathExpression 内使用 ms: 扩展)?

I am trying to use Microsoft XPath Extension Functions (such as ms:string-compare http://msdn.microsoft.com/en-us/library/ms256114.aspx) inside an XPathExpression object.

These functions are extensions inside the MSXML library, and if I use them in an XslCompiledTransform (simply adding the "ms" namespace) they work like a charm:

var xsl =
    @"
<?xml version=""1.0"" encoding=""UTF-8""?>
<xsl:stylesheet version=""2.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"" 
        xmlns:xs=""http://www.w3.org/2001/XMLSchema"" 
        xmlns:fn=""http://www.w3.org/2005/xpath-functions"" 
        xmlns:ms=""urn:schemas-microsoft-com:xslt"">
 <xsl:output method=""xml"" version=""1.0"" encoding=""UTF-8"" indent=""yes""/>
 <xsl:template match=""/Data"">
  <xsl:element name=""Result"">
   <xsl:value-of select=""ms:string-compare(@timeout1, @timeout2)""/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>";

var xslDocument = new XmlDocument();
xslDocument.LoadXml(xsl);

var transform = new XslCompiledTransform();
transform.Load(xslDocument);

Then I tried using them in an XPathExpression:

XPathNavigator nav = document.DocumentElement.CreateNavigator();
XPathExpression expr = nav.Compile("ms:string-compare(/Data/@timeout1, /Data/@timeout2)");

XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
manager.AddNamespace("ms", "urn:schemas-microsoft-com:xslt");
expr.SetContext(manager);

nav.Evaluate(expr);

But I get an exception "XsltContext is needed for this query because of an unknown function".

XsltContext is a specific XmlNamespaceManager, but I don't know if it's possible to instantiate it without an actual XslCompiledTransform (it's abstract) and use it as my expression context.

Is there any way to do this (or any other way to use ms: extensions inside an XPathExpression)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

影子是时光的心 2024-08-29 20:47:25

这些 ms 前缀的函数不包含在 .net 框架 dom 类中。您需要创建自定义函数来完成同样的事情。

您可以使用下面的示例代码;

string xpath = "my:string-compare('1','1)";

System.Xml.XmlNamespaceManager nsManager = new XsltContext();

nav.Select(xpath, nsManager );

或者

XPathExpression compiledXPath = XPathExpression.Compile(xpath);

compiledXPath.SetContext(nsManager);

nav.Evaluate(compiledXPath);

你将需要这些课程;

public class XsltContext : System.Xml.Xsl.XsltContext
{
    public XsltContext()
    {
        Initialize();
    }

    public XsltContext(System.Xml.NameTable nameTable)
        : base(nameTable)
    {
        Initialize();
    }

    private void Initialize()
    {
        RegisterFunction("my", "string-compare", typeof(StringCompare));
    }

    public override string LookupNamespace(string prefix)
    {
        return base.LookupNamespace(prefix);
    }

    public override int CompareDocument(string baseUri, string nextbaseUri)
    {
        return string.CompareOrdinal(baseUri, nextbaseUri);
    }

    public override bool PreserveWhitespace(System.Xml.XPath.XPathNavigator node)
    {
        return false;
    }

    public void RegisterFunction(string prefix, string name, Type function)
    {
        if (function == null)
            throw new ArgumentNullException("function");

        if (name == null)
            throw new ArgumentNullException("name");

        functions[prefix + ":" + name] = function;
    }

    Dictionary<string, Type> functions = new Dictionary<string, Type>();

    public override System.Xml.Xsl.IXsltContextFunction ResolveFunction(string prefix, string name, System.Xml.XPath.XPathResultType[] argTypes)
    {
        Type functionType = null;

        if (functions.TryGetValue(prefix + ":" + name, out functionType))
        {
            System.Xml.Xsl.IXsltContextFunction function = Activator.CreateInstance(functionType) as System.Xml.Xsl.IXsltContextFunction;

            return function;
        }

        return null;
    }

    public override System.Xml.Xsl.IXsltContextVariable ResolveVariable(string prefix, string name)
    {
        return null;
    }

    public override bool Whitespace
    {
        get
        {
            return false;
        }
    }

    internal static string GetValue(object v)
    {
        if (v == null)
            return null;

        if (v is System.Xml.XPath.XPathNodeIterator)
        {
            foreach (System.Xml.XPath.XPathNavigator n in v as System.Xml.XPath.XPathNodeIterator)
                return n.Value;
        }

        return Convert.ToString(v);
    }

}

class StringCompare : System.Xml.Xsl.IXsltContextFunction
{
    public System.Xml.XPath.XPathResultType[] ArgTypes
    {
        get
        {
            return new System.Xml.XPath.XPathResultType[]
            {
                System.Xml.XPath.XPathResultType.String,
                System.Xml.XPath.XPathResultType.String,
                System.Xml.XPath.XPathResultType.String
            };
        }
    }

    public object Invoke(System.Xml.Xsl.XsltContext xsltContext, object[] args, System.Xml.XPath.XPathNavigator docContext)
    {
        string arg1 = XsltContext.GetValue(args[0]);
        string arg2 = XsltContext.GetValue(args[1]);

        string locale = "en-US";

        if (args.Length > 2)
            locale = XsltContext.GetValue(args[2]);

        System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.GetCultureInfo(locale);

        return string.Compare(arg1, arg2, false, culture);
    }

    public int Maxargs
    {
        get
        {
            return 3;
        }
    }

    public int Minargs
    {
        get 
        {
            return 2;
        }
    }

    public System.Xml.XPath.XPathResultType ReturnType
    {
        get
        {
            return System.Xml.XPath.XPathResultType.Number;
        }
    }
}

These ms prefixed functions are not included in .net framework dom classes. you need to create your custom functions to do same thing.

you may use sample code below;

string xpath = "my:string-compare('1','1)";

System.Xml.XmlNamespaceManager nsManager = new XsltContext();

nav.Select(xpath, nsManager );

or

XPathExpression compiledXPath = XPathExpression.Compile(xpath);

compiledXPath.SetContext(nsManager);

nav.Evaluate(compiledXPath);

you will need these classes;

public class XsltContext : System.Xml.Xsl.XsltContext
{
    public XsltContext()
    {
        Initialize();
    }

    public XsltContext(System.Xml.NameTable nameTable)
        : base(nameTable)
    {
        Initialize();
    }

    private void Initialize()
    {
        RegisterFunction("my", "string-compare", typeof(StringCompare));
    }

    public override string LookupNamespace(string prefix)
    {
        return base.LookupNamespace(prefix);
    }

    public override int CompareDocument(string baseUri, string nextbaseUri)
    {
        return string.CompareOrdinal(baseUri, nextbaseUri);
    }

    public override bool PreserveWhitespace(System.Xml.XPath.XPathNavigator node)
    {
        return false;
    }

    public void RegisterFunction(string prefix, string name, Type function)
    {
        if (function == null)
            throw new ArgumentNullException("function");

        if (name == null)
            throw new ArgumentNullException("name");

        functions[prefix + ":" + name] = function;
    }

    Dictionary<string, Type> functions = new Dictionary<string, Type>();

    public override System.Xml.Xsl.IXsltContextFunction ResolveFunction(string prefix, string name, System.Xml.XPath.XPathResultType[] argTypes)
    {
        Type functionType = null;

        if (functions.TryGetValue(prefix + ":" + name, out functionType))
        {
            System.Xml.Xsl.IXsltContextFunction function = Activator.CreateInstance(functionType) as System.Xml.Xsl.IXsltContextFunction;

            return function;
        }

        return null;
    }

    public override System.Xml.Xsl.IXsltContextVariable ResolveVariable(string prefix, string name)
    {
        return null;
    }

    public override bool Whitespace
    {
        get
        {
            return false;
        }
    }

    internal static string GetValue(object v)
    {
        if (v == null)
            return null;

        if (v is System.Xml.XPath.XPathNodeIterator)
        {
            foreach (System.Xml.XPath.XPathNavigator n in v as System.Xml.XPath.XPathNodeIterator)
                return n.Value;
        }

        return Convert.ToString(v);
    }

}

class StringCompare : System.Xml.Xsl.IXsltContextFunction
{
    public System.Xml.XPath.XPathResultType[] ArgTypes
    {
        get
        {
            return new System.Xml.XPath.XPathResultType[]
            {
                System.Xml.XPath.XPathResultType.String,
                System.Xml.XPath.XPathResultType.String,
                System.Xml.XPath.XPathResultType.String
            };
        }
    }

    public object Invoke(System.Xml.Xsl.XsltContext xsltContext, object[] args, System.Xml.XPath.XPathNavigator docContext)
    {
        string arg1 = XsltContext.GetValue(args[0]);
        string arg2 = XsltContext.GetValue(args[1]);

        string locale = "en-US";

        if (args.Length > 2)
            locale = XsltContext.GetValue(args[2]);

        System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.GetCultureInfo(locale);

        return string.Compare(arg1, arg2, false, culture);
    }

    public int Maxargs
    {
        get
        {
            return 3;
        }
    }

    public int Minargs
    {
        get 
        {
            return 2;
        }
    }

    public System.Xml.XPath.XPathResultType ReturnType
    {
        get
        {
            return System.Xml.XPath.XPathResultType.Number;
        }
    }
}
因为看清所以看轻 2024-08-29 20:47:25

您可以使用已编译的 XPath,或者使用 Linqtoxml 和 XElement 动态使用:

        XPathCustomContext context = new XPathCustomContext(new NameTable());
        context.AddNamespace("windward", XPathCustomContext.Namespace);

        XmlDocument document = new XmlDocument();
        string records = @"
        <records>
            <record id=""m""/>
            <record id=""M""/>
            <record id=""l""/>
        </records>
        ";
        document.LoadXml(records);

        string xpath = @"//record[my:string-compare(@id,""m"")]";

        //solution 1
        XPathExpression compiledXPath = XPathExpression.Compile(xpath, context);
        compiledXPath.SetContext(context);
        XPathNavigator nav = document.CreateNavigator();
        object res = nav.Evaluate(compiledXPath);

        //solution 2
        XElement elm = XElement.Parse(records);
        IEnumerable<XElement> targets = elm.XPathSelectElements(xpath, context);

我的比较函数:

public class MyStringCompare : IWindwardContextFunction
{
    public System.Xml.XPath.XPathResultType[] ArgTypes
    {
        get
        {
            return new System.Xml.XPath.XPathResultType[]
        {
            System.Xml.XPath.XPathResultType.String,
            System.Xml.XPath.XPathResultType.String,
            System.Xml.XPath.XPathResultType.String
        };
        }
    }
    /// <summary>
    /// The function name.
    /// </summary>
    public string FunctionName
    {
        get { return "string-compare"; }
    }

    public object Invoke(System.Xml.Xsl.XsltContext xsltContext, object[] args, System.Xml.XPath.XPathNavigator docContext)
    {

        string arg1 = "";// Convert.ToString(args[0]);
        object arg1Obj = args[0];
        IEnumerable list = arg1Obj as IEnumerable;
        if (arg1Obj != null)
        {
            IEnumerator listit = list.GetEnumerator();
            listit.MoveNext();

            XPathNavigator nav = (XPathNavigator)listit.Current;
            arg1 = nav.Value;
        }

        string arg2 = Convert.ToString(args[1]);

        string locale = "en-US";

        if (args.Length > 2)
            locale = Convert.ToString(args[2]);

        System.Globalization.CultureInfo culture = CultureInfo.GetCultureInfo(locale);

        return string.Compare(arg1, arg2, true) == 0;
    }

    public int Maxargs
    {
        get
        {
            return 3;
        }
    }

    public int Minargs
    {
        get
        {
            return 2;
        }
    }

    public System.Xml.XPath.XPathResultType ReturnType
    {
        get
        {
            return System.Xml.XPath.XPathResultType.Number;
        }
    }
}

You can use the compiled XPath, or dynamic with Linqtoxml and XElement:

        XPathCustomContext context = new XPathCustomContext(new NameTable());
        context.AddNamespace("windward", XPathCustomContext.Namespace);

        XmlDocument document = new XmlDocument();
        string records = @"
        <records>
            <record id=""m""/>
            <record id=""M""/>
            <record id=""l""/>
        </records>
        ";
        document.LoadXml(records);

        string xpath = @"//record[my:string-compare(@id,""m"")]";

        //solution 1
        XPathExpression compiledXPath = XPathExpression.Compile(xpath, context);
        compiledXPath.SetContext(context);
        XPathNavigator nav = document.CreateNavigator();
        object res = nav.Evaluate(compiledXPath);

        //solution 2
        XElement elm = XElement.Parse(records);
        IEnumerable<XElement> targets = elm.XPathSelectElements(xpath, context);

My compare function:

public class MyStringCompare : IWindwardContextFunction
{
    public System.Xml.XPath.XPathResultType[] ArgTypes
    {
        get
        {
            return new System.Xml.XPath.XPathResultType[]
        {
            System.Xml.XPath.XPathResultType.String,
            System.Xml.XPath.XPathResultType.String,
            System.Xml.XPath.XPathResultType.String
        };
        }
    }
    /// <summary>
    /// The function name.
    /// </summary>
    public string FunctionName
    {
        get { return "string-compare"; }
    }

    public object Invoke(System.Xml.Xsl.XsltContext xsltContext, object[] args, System.Xml.XPath.XPathNavigator docContext)
    {

        string arg1 = "";// Convert.ToString(args[0]);
        object arg1Obj = args[0];
        IEnumerable list = arg1Obj as IEnumerable;
        if (arg1Obj != null)
        {
            IEnumerator listit = list.GetEnumerator();
            listit.MoveNext();

            XPathNavigator nav = (XPathNavigator)listit.Current;
            arg1 = nav.Value;
        }

        string arg2 = Convert.ToString(args[1]);

        string locale = "en-US";

        if (args.Length > 2)
            locale = Convert.ToString(args[2]);

        System.Globalization.CultureInfo culture = CultureInfo.GetCultureInfo(locale);

        return string.Compare(arg1, arg2, true) == 0;
    }

    public int Maxargs
    {
        get
        {
            return 3;
        }
    }

    public int Minargs
    {
        get
        {
            return 2;
        }
    }

    public System.Xml.XPath.XPathResultType ReturnType
    {
        get
        {
            return System.Xml.XPath.XPathResultType.Number;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文