为什么 //NODE 找不到任何元素,但 //*[name() = 'NODE'] 却找到?

Why does //NODE not find any elements, but //*[name() = 'NODE'] does?

提问人:MichaelChirico 提问时间:6/23/2023 更新时间:6/23/2023 访问量:40

问:

我正在尝试解析旧金山公交运营商 API 的 XML(或者可能是 HTML?)输出(需要免费的 API 密钥):

https://511.org/open-data/transit

将完整的 XML 字符串粘贴到这个 Gist 中,因为它太长了,而且我没有费心最小化示例:https://gist.github.com/MichaelChirico/7a3a5bb95d577d8d83ebea37c44320d0

我正在使用 R 的包来处理它,它使用 libxml2 作为后端:xml2

https://github.com/r-lib/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 ...

这是一个错误,还是我做错了什么?

r xml libxml2

评论

0赞 zx485 6/23/2023
您没有考虑默认命名空间。这是元素的命名空间。通过引用这些元素的 with ,您可以规避这个“未知”问题。xmlns="http://www.netex.org.uk/netex"<Operator>name()//*[name() = "Operator"]
0赞 zx485 6/23/2023
此处介绍了如何在 R 中处理此问题。

答:

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/netexd1:Operator
0赞 Yitzhak Khabinsky 6/23/2023
它可以是默认命名空间的任何合理别名。