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。 []
是缩小结果集的筛选谓词。
我有一个 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。 []
是缩小结果集的筛选谓词。