在 System.Xml.XPath 中启用 XPath2 查询(XPathException:无效令牌)

2024-06-20

Microsoft 的 System.Xml.XPath nuget-package 可用于 .NET 4.6,声称支持 XPath 1.0 和 2.0。德文档 https://msdn.microsoft.com/en-us/library/system.xml.xpath(v=vs.110).aspx说描述了命名空间:

System.Xml.XPath 命名空间包含的类定义了用于导航和编辑 XML 信息项的游标模型,作为 XQuery 1.0 和 XPath 2.0 数据模型的实例。

升级 Visual Studio、将我的所有项目升级到框架版本 4.6 后,我仍然无法让最简单的 XPath-2.0 for 表达式工作。根据规格 https://www.w3.org/TR/xpath20/#id-for-expressions,他们应该工作。

我无法想象微软声称支持它实际上并不支持的东西,所以显然我做错了。如何正确使用 XPath2 查询?

[TestMethod]
public void TestXPath2()
{
    // The System.Xml.XPath namespace contains the classes that define a cursor model for navigating and editing XML information items as instances of the 
    // XQuery 1.0 and XPath 2.0 Data Model.

    var expression = "for $x in /Root/Foo/Bar return $x";
    var compiledExpression = System.Xml.XPath.XPathExpression.Compile(expression); 
    // throws XPathException: "for ... has an invalid token"
}

附: 我真正想要的是让这样的事情发挥作用:

    [TestMethod]
    public void TestLibraryForCustomer1()
    {
        string xmlFromMessage = @"<Library>
            <Writer ID=""writer1""><Name>Shakespeare</Name></Writer>
            <Writer ID=""writer2""><Name>Tolkien</Name></Writer>
            <Book><WriterRef REFID=""writer1"" /><Title>King Lear</Title></Book>
            <Book><WriterRef REFID=""writer2"" /><Title>The Hobbit</Title></Book>
            <Book><WriterRef REFID=""writer2"" /><Title>Lord of the Rings</Title></Book>
             </Library>"; 

        var titleXPathFromConfigurationFile = "./Title"; 
        var writerXPathFromConfigurationFile = "for $curr in . return /Library/Writer[@ID=$curr/WriterRef/@REFID]/Name";

        var library = ExtractBooks(xmlFromMessage, titleXPathFromConfigurationFile, writerXPathFromConfigurationFile).ToDictionary(b => b.Key, b => b.Value);

        Assert.AreEqual("Shakespeare", library["King Lear"]);
        Assert.AreEqual("Tolkien", library["The Hobbit"]);
        Assert.AreEqual("Tolkien", library["Lord of the Rings"]);
    }

    [TestMethod]
    public void TestLibraryForCustomer2()
    {
        string xmlFromMessage = @"<Library>
                <Writer ID=""writer1"">
                    <Name>Shakespeare</Name>
                    <Book><Title>Sonnet 18</Title></Book>
                </Writer>
                <Writer ID=""writer2"">
                    <Name>Tolkien</Name>
                    <Book><Title>The Hobbit</Title></Book>
                    <Book><Title>Lord of the Rings</Title></Book>
                </Writer>
            </Library>";

        var titleXPathFromConfigurationFile = "./Title";
        var writerXPathFromConfigurationFile = "../Name";

        var library = ExtractBooks(xmlFromMessage, titleXPathFromConfigurationFile, writerXPathFromConfigurationFile).ToDictionary(b => b.Key, b => b.Value);

        Assert.AreEqual("Shakespeare", library["Sonnet 18"]);
        Assert.AreEqual("Tolkien", library["The Hobbit"]);
        Assert.AreEqual("Tolkien", library["Lord of the Rings"]);
    }


    public IEnumerable<KeyValuePair<string,string>> ExtractBooks(string xml, string titleXPath,  string writerXPath)
    {
        var library = XDocument.Parse(xml);
        foreach(var book in library.Descendants().Where(d => d.Name == "Book"))
        {
            var title = book.XPathSelectElement(titleXPath).Value;
            var writer = book.XPathSelectElement(writerXPath).Value;
            yield return new KeyValuePair<string, string>(title, writer);
        }
    }

托马利克正确地指出:

  • .NET(在 System.Xml.XPath 中)不支持 XPath 2.0,期间
  • 数据模型和查询语言是不同的东西。

所以我通过使用第三方 XPath 2 库解决了这个问题XPath2 nuget 包 https://www.nuget.org/packages/XPath2/。这允许像这样的表达式

for $c in . return ../Writer[@ID=$c/WriterRef/@REFID]/Name

请注意,我需要使用从书到作者的相对路径。这确实not work:

# does not work due to the absolute path
for $c in . return /Library/Writer[@ID=$c/WriterRef/@REFID]/Name

供将来参考:此代码在安装 nuget 包后有效:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Wmhelp.XPath2;

namespace My.Library
{
    [TestClass]
    public class WmhelpTests
    {
        [TestMethod]
        public void LibraryTest()
        {
            string xmlFromMessage = @"<Library>
                <Writer ID=""writer1""><Name>Shakespeare</Name></Writer>
                <Writer ID=""writer2""><Name>Tolkien</Name></Writer>
                <Book><WriterRef REFID=""writer1"" /><Title>King Lear</Title></Book>
                <Book><WriterRef REFID=""writer2"" /><Title>The Hobbit</Title></Book>
                <Book><WriterRef REFID=""writer2"" /><Title>Lord of the Rings</Title></Book>
            </Library>";

            var titleXPathFromConfigurationFile = "./Title";
            var writerXPathFromConfigurationFile = "for $curr in . return ../Writer[@ID=$curr/WriterRef/@REFID]/Name";

            var library = ExtractBooks(xmlFromMessage, titleXPathFromConfigurationFile, writerXPathFromConfigurationFile).ToDictionary(b => b.Key, b => b.Value);

            Assert.AreEqual("Shakespeare", library["King Lear"]);
            Assert.AreEqual("Tolkien", library["The Hobbit"]);
            Assert.AreEqual("Tolkien", library["Lord of the Rings"]);
        }


        [TestMethod]
        public void TestLibraryForCustomer2()
        {
            string xmlFromMessage = @"<Library>
                <Writer ID=""writer1"">
                    <Name>Shakespeare</Name>
                    <Book><Title>Sonnet 18</Title></Book>
                </Writer>
                <Writer ID=""writer2"">
                    <Name>Tolkien</Name>
                    <Book><Title>The Hobbit</Title></Book>
                    <Book><Title>Lord of the Rings</Title></Book>
                </Writer>
            </Library>";

            var titleXPathFromConfigurationFile = "./Title";
            var writerXPathFromConfigurationFile = "../Name";

            var library = ExtractBooks(xmlFromMessage, titleXPathFromConfigurationFile, writerXPathFromConfigurationFile).ToDictionary(b => b.Key, b => b.Value);

            Assert.AreEqual("Shakespeare", library["Sonnet 18"]);
            Assert.AreEqual("Tolkien", library["The Hobbit"]);
            Assert.AreEqual("Tolkien", library["Lord of the Rings"]);
        }


        public IEnumerable<KeyValuePair<string, string>> ExtractBooks(string xml, string titleXPath, string writerXPath)
        {
            var library = XDocument.Parse(xml);
            foreach (var book in library.Descendants().Where(d => d.Name == "Book"))
            {
                var title = book.XPath2SelectElement(titleXPath).Value;
                var writer = book.XPath2SelectElement(writerXPath).Value;
                yield return new KeyValuePair<string, string>(title, writer);
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 System.Xml.XPath 中启用 XPath2 查询(XPathException:无效令牌) 的相关文章

随机推荐

  • 如何从数组中提取特定元素?

    如果我有一个数组a 1 2 3 4 5 6 7 8 9 10 我想要这个数组的一个子集 第 1 个 第 5 个和第 7 个元素 是否可以通过简单的方式从该数组中提取这些内容 我在想这样的事情 a 0 4 6 1 5 7 但这行不通 还有一种
  • 在 Backbone.js 和 Underscore.js 中绑定回调

    我有以下代码 initialize function bindAll this var callBack function res window item new Item res this render bind callBack thi
  • Linq to SQL 和大型数据库模型

    首先 我是 Linq to Sql 新手 所以请温柔点 我现有的 ASP Net 应用程序是在过去 3 5 年里开发的 它下面有相当大的数据模型 大约有 350 个表 我正在尝试使用 Linq to SQL 做一些新的事情 第一印象是 li
  • Glassfish 4、JSF 2.2 和 PrimeFaces FileUploadEvent 无法协同工作

    升级到 GlassFish 4 和 JSF 2 2 Primefaces 后 FileUploadEvent 停止工作 对于 JSF 2 1 它可以正常工作 除了文件上传之外 一切正常 我有什么遗漏的吗 GlassFish 4 JSF 2
  • 将 Web 应用程序从 Eclipse 部署到 JBoss,并具有依赖项

    我有一个在 Eclipse 下开发的项目 安装了 JBoss 工具 当我将应用程序部署到 Jboss 服务器时 一些通过 Maven 提供给项目的帮助程序 jar 文件不会复制到 WEB INF lib 文件夹中 因此 我得到一个Class
  • 为什么performSegueWithIdentifier在viewDidLoad中不起作用?

    我试图在视图控制器上调用 viewDidLoad 后立即触发故事板转场 Segue 附加了一个标识符 当从链接到按钮或其他控件的方法内部调用时 它可以正常工作 但它在 viewDidLoad 内部不起作用 它只是默默地失败了 viewDid
  • 如何在iOS中处理1到3个手指的滑动手势

    我使用以下代码来处理代码中的 1 根手指滑动 UISwipeGestureRecognizer swipe UISwipeGestureRecognizer alloc initWithTarget self action selector
  • 检查 Android 麦克风是否被其他应用程序使用

    我想使用 Android 麦克风检查噪音水平 然而 在访问麦克风之前 我想知道麦克风是否正在被另一个应用程序访问 如何检查麦克风是否正在被其他应用程序访问 有关活动输入流及其路由位置的信息由AudioFlinger AudioPolicyM
  • 如何使用国家宝石

    我正在尝试使用国家宝石 https github com hexorx countries 但是在我捆绑安装这个 gem 后 有一些关于如何合并它的基本问题 我是否需要创建新的控制器 模型才能访问这些国家 地区 如何创建一个简单的选择下拉列
  • 如何在视频在后台播放时在android中加载活动布局

    当视频在 Android 模拟器后台播放时 如何在 Android 中加载活动布局 您可以在此处观看视频演示示例视频 http youtu be XTE6Yln4yAQ 到目前为止 我只对布局进行了动画处理 但我无法像视频中的那样进行操作
  • Git:忽略版本控制文件

    gitignore 文件对于忽略一些我们不想控制的文件非常有用 不幸的是 当文件已处于版本控制之下时 它无法使用 例如 我的 gitignore 已添加到 git 中 文件可能与我的同事想要的不同 例如我想忽略 Vim 文件 每当我对此文件
  • 当与浏览器进行精简通信时,我在 FitNesse 中遇到错误_无法使用 SUT 发送/接收数据

    我得到的错误是Fitnesse testsystems slim SlimCommunicationException 无法使用 SUT 发送 接收数据 健身代码 define TEST SYSTEM slim 路径 C FitNesseU
  • 在 ASP.Net 网站中使用 VBScript 中的变量

    我花了一天的大部分时间来研究这个问题 但找不到答案 我对 stackoverflow 比较陌生 询问多个问题是否有一定的礼仪 过去几天我问了三个问题 Anyways 这是代码隐藏文件中的代码 它执行脚本 systeminfo vbs 并且工
  • Swift 协议扩展实现另一个具有共享关联类型的协议

    考虑以下 protocol Foo typealias A func hello gt A protocol FooBar Foo func hi gt A extension FooBar func hello gt A return h
  • 如何(从 Google 电子表格)获取链接表单的 ID

    我有一个 Google 电子表格 其中链接了一个表单 并且存储了所有表单响应 我想要查找的是表单本身的 ID 我尝试过这个 但这不起作用 我正在表单链接到的电子表格中的脚本编辑器中运行以下代码 function getID var form
  • 正则表达式,提取不在两个括号之间的字符串

    好的正则表达式问题 如何提取不在两个字符之间的字符 在本例中是括号 我有一个字符串 例如 字1 字2 字3 字 4 我只想获取第一个和最后一个 管道 而不是括号之间的第二个 管道 我已经尝试了无数次负克拉和负分组的尝试 但似乎无法使其发挥作
  • 在 Yosemite 上安装 Ruby 1.9.2 时出错

    我在 Yosemite 上使用 rvm 安装 ruby 1 9 2 时遇到错误 有人可以帮助我吗 我更新了自制程序和rvm 我正在与其他人合作处理这个项目 所以我无法升级 ruby 我在下面放置了我的输出的链接 提前致谢 Kanyons M
  • 如何以编程方式更改 iPhone APN(接入点名称)?

    如何以编程方式更改 iPhone APN 接入点名称 或者强制 3G GPRS 连接以编程方式使用特定的 APN 无法通过 SDK 完成 第三方应用程序无法对硬件进行这种级别的控制 尤其是蜂窝调制解调器
  • 函数内开玩笑模拟函数

    我不知道如何在笑话中模拟内部函数的返回值 我尝试了不同的方法 最后我找到了这个answer https stackoverflow com questions 51269431 jest mock inner function但由于某种原因
  • 在 System.Xml.XPath 中启用 XPath2 查询(XPathException:无效令牌)

    Microsoft 的 System Xml XPath nuget package 可用于 NET 4 6 声称支持 XPath 1 0 和 2 0 德文档 https msdn microsoft com en us library s