如何获取指定XML元素的路径?xmllint/xml_grep能否实现?
获取XML目标节点的完整路径
问题背景
需要定位XML中指定元素的完整层级路径,使用xmllint和xml_grep仅能返回目标节点本身,无法输出其路径。示例XML:
<myroot> <my2ndlvl> <my3rdlvl foo="bar"/> </my2ndlvl> <my2ndlvl> <my3rdlvl fum="baz"/> </my2ndlvl> </myroot>
已尝试的命令:
xmllint --xpath '//my3rdlvl[@fum="baz"]'xml_grep --cond '//my3rdlvl[@fum="baz"]'
仅得到目标节点<my3rdlvl fum="baz"/>,期望输出类似myroot/my2ndlvl/my3rdlvl[@fum="baz"]的路径格式。
解决方案
1. 用xmllint生成目标路径
xmllint本身没有直接输出路径的参数,但可以通过自定义XPath表达式,递归遍历节点的所有父节点并拼接路径:
xmllint --xpath ' let $target := //my3rdlvl[@fum="baz"], $path_parts := for $node in $target/ancestor-or-self::* return if ($node/@fum = "baz") then concat(name($node), "[@fum="baz"]") else name($node), $full_path := string-join($path_parts, "/") return $full_path ' your_file.xml
执行后会直接输出:
myroot/my2ndlvl/my3rdlvl[@fum="baz"]
如果需要适配更通用的场景(比如匹配任意属性),可以用更灵活的XPath:
xmllint --xpath ' let $target := //my3rdlvl[@fum="baz"], $path_parts := for $node in $target/ancestor-or-self::* return if ($node/@*) then concat(name($node), "[", string-join(for $attr in $node/@* return concat(name($attr), "="", $attr, """), " and "), "]") else name($node), $full_path := string-join($path_parts, "/") return $full_path ' your_file.xml
2. xml_grep的局限性
xml_grep的核心功能是提取匹配节点,没有内置的路径输出机制,无法直接生成你需要的路径格式,不推荐用它实现这个需求。
3. 替代工具(可选)
如果觉得XPath编写繁琐,可以使用xmlstarlet工具,它支持直接输出节点路径:
xmlstarlet sel -t -m "//my3rdlvl[@fum='baz']" -v "concat(ancestor-or-self::*/name(), '/')" -b -n your_file.xml
注意:xmlstarlet需要额外安装,部分系统默认不包含。
内容的提问来源于stack exchange,提问作者Mike Maxwell
相关产品推荐
相关产品推荐

