提问人:MichaelChirico 提问时间:6/23/2023 更新时间:6/23/2023 访问量:40
为什么 //NODE 找不到任何元素,但 //*[name() = 'NODE'] 却找到?
Why does //NODE not find any elements, but //*[name() = 'NODE'] does?
问:
我正在尝试解析旧金山公交运营商 API 的 XML(或者可能是 HTML?)输出(需要免费的 API 密钥):
https://511.org/open-data/transit
将完整的 XML 字符串粘贴到这个 Gist 中,因为它太长了,而且我没有费心最小化示例:https://gist.github.com/MichaelChirico/7a3a5bb95d577d8d83ebea37c44320d0
我正在使用 R 的包来处理它,它使用 libxml2 作为后端:xml2
出于某种原因,我无法以正常方式找到节点:Operator
library(xml2)
s = ' <xml string here> '
xml = read_xml(s)
xml_find_all(xml, "//Operator")
# {xml_nodeset (0)}
但是,找到正确的节点名称:name()
Operator
# Using '*' because some intermediate nodes have the same issue,
# basically anything nested beyond a `siri:` node.
xml_find_chr(xml, 'name(*/*/*/*/*/*)')
# [1] "Operator"
这种复杂的方法有效:
xml_find_all(xml, '//*[name() = "Operator"]') |> head()
# {xml_nodeset (6)}
# [1] <Operator id="5E" version="any">\n <Extensions>\n <Monitored>false</Monitored>\n <OtherM ...
# [2] <Operator id="5F" version="any">\n <Extensions>\n <Monitored>false</Monitored>\n <OtherM ...
# [3] <Operator id="5O" version="any">\n <Extensions>\n <Monitored>false</Monitored>\n <OtherM ...
# [4] <Operator id="5S" version="any">\n <Extensions>\n <Monitored>false</Monitored>\n <OtherM ...
# [5] <Operator id="AC" version="any">\n <Extensions>\n <Monitored>true</Monitored>\n <OtherMo ...
# [6] <Operator id="CE" version="any">\n <Extensions>\n <Monitored>false</Monitored>\n <OtherM ...
这是一个错误,还是我做错了什么?
答:
3赞
Yitzhak Khabinsky
6/23/2023
#1
有问题的 XML 具有多个命名空间。
<?xml version="1.0" encoding="iso-8859-1"?>
<siri:Siri xsi:schemaLocation="http://www.siri.org.uk/siri http://www.kizoom.com/standards/netex/schema/0.99.1/xsd/NeTEx_siri.xsd"
xmlns:siri="http://www.siri.org.uk/siri"
xmlns="http://www.netex.org.uk/netex"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gml="http://www.opengis.net/gml" version="1.0">
<siri:ServiceDelivery>
<siri:ResponseTimestamp>2023-06-21T23:27:30-07:00</siri:ResponseTimestamp>
<DataObjectDelivery>
<siri:ResponseTimestamp>2023-06-21T23:27:30-07:00</siri:ResponseTimestamp>
<dataObjects>
<ResourceFrame id="SF" version="any">
<organisations>
<Operator id="5E" version="any">
其中两个与 XML 元素相关:<Operator>
- xmlns:siri=“http://www.siri.org.uk/siri”
- xmlns=“http://www.netex.org.uk/netex” ,即默认命名空间。
因此,完全限定的 XPath 表达式如下所示:
/siri:Siri/siri:ServiceDelivery/ns1:DataObjectDelivery/ns1:dataObjects/ns1:ResourceFrame/ns1:organisations/ns1:Operator
其中 ns1 是默认命名空间的别名。
最终结果,您需要向代码添加命名空间处理,并使用正确的 XPath 表达式。
评论
1赞
user20650
6/23/2023
剥离命名空间似乎允许找到节点,例如xml = xml_ns_strip( xml ) ; xml_find_all(xml, "//Operator")
0赞
Yitzhak Khabinsky
6/23/2023
出于性能原因,最好使用命名空间。此外,它可能是绑定到不同命名空间的多个 XML 元素。<Operator>
0赞
MichaelChirico
6/23/2023
ns1
不起作用。但是在输出中返回,并且确实有效xml_ns(xml)
d1 <-> http://www.netex.org.uk/netex
d1:Operator
0赞
Yitzhak Khabinsky
6/23/2023
它可以是默认命名空间的任何合理别名。
评论
xmlns="http://www.netex.org.uk/netex"
<Operator>
name()
//*[name() = "Operator"]