C# XML Select 字典节点按键值

C# XML Select dictionary node by key value

我有一个 XML 文件(它是一个 iTunes 文件),内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Major Version</key><integer>1</integer>
        <key>Minor Version</key><integer>1</integer>
        <key>Application Version</key><string>12.3.3.17</string>

    ...

        <key>Music Folder</key><string>file://localhost/C:/Users/username/longpath/</string>
    </dict>
</plist>

如何获取最后一个字符串的值,其中 <key> 是 'Music Folder'?

这是一个非常大的文件,所以我不想遍历所有节点。

我尝试了以下一些方法:

XmlNode location = xmlDocument.SelectSingleNode("descendant::dict[key='Music Folder']");
location = xmlDocument.SelectSingleNode("//text()[.='Music Folder']");
location = xmlDocument.SelectSingleNode("string[last()]");
location = xmlDocument.SelectSingleNode("dict::string[last()]");
location = xmlDocument.SelectSingleNode("descendant::dict[string[last()]]");

我对 XPath 表达式不是很熟悉,无法正确表达。

我也对 LINQ 解决方案持开放态度。

获取文档中最后一个节点的值用了 17 毫秒。为了测试速度,我创建了一个文档,其中包含 Music Folder 节点作为最后一个 key 节点,并且在您的示例中列出了大约 11000 次的前 3 个节点。

string ReadValue(XDocument xDoc, string key)
{
    var node = xDoc.Element("plist")
        .Element("dict")
        .Elements("key")
        .Single(e => e.Value == key)
        .NextNode as XElement;
    return node.Value;
}

您的文档的 XPath 表达式是在文档根目录的上下文中计算的,因此您需要理想地指定 plist 节点,我假设您需要字符串值,因此您需要导航到该节点节点。

XmlNode location = xmlDocument.SelectSingleNode("plist/dict/key[.='Music Folder']/following-sibling::string[1]")

请注意,该值未嵌套在键元素内,而是以下同级元素。鉴于这出现在最后你可能会逃脱:

XmlNode location = xmlDocument.SelectSingleNode("plist/dict/string[last()]")

我会在 XPath 中明确指定 plist 节点,因为它将可能的匹配项保持在最低限度。另一点需要注意的是,你的 XPath 可能最终会以底层技术迭代每个节点,这取决于你如何构造你的表达式,因为一些实现可能能够应用优化。

你很接近,但我看到你混淆了运算符并使用 ::[],其中 / 更合适。 :: 将轴与节点名称分开,因此 descendants::dict 获取名为 dict 的上下文节点 (xmlDocument) 的所有后代。对于 child::/ 运算符实际上是 shorthand。 [] 是缩小结果集的筛选谓词。