XPath:select 具有特定子元素而不是另一个特定子元素的元素
XPath: select element with specific child and not another specific child
看来,现在总是用源标记 Openstreetmap 节点是一个坏习惯 - 只有当源是特定的并且与标记到变更集的源不同时,才应指定源标记。当节点没有其他标签时,尤其不受欢迎。并非总是如此——曾经有一段时间,变更集标记不是标准做法。因此,在我进行了大量编辑的一些地方,我需要做一些清理工作,我打算为自己构建一个工具。
例如,让我们从这个示例数据集开始:
<?xml version='1.0' encoding='UTF-8'?>
<osm version='0.6' upload='true' generator='JOSM'>
<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
</node>
<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="power" v="tower" />
</node>
<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>
</osm>
首先我想 select 所有包含 <tag k="source" v="Microsoft Bing orbital imagery" />
的 Openstreetmap 节点 - 使用起来非常简单
/osm/node/tag[@v = "Microsoft Bing orbital imagery"]/..
结果如预期:
Element='<node id="3736237027" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771207" lon="-16.3332326">
<tag k="source" v="Microsoft Bing orbital imagery" />
</node>'
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
但是第二个元素也有一个 <tag k="power" v="tower" />
,我不希望 select 节点带有任何标签,但带有源标签。所以我尝试
/osm/node/tag[@v = "Microsoft Bing orbital imagery" and ../tag[not(@k != "source")]]/..
结果:这让我得到与上面完全相同的结果。关于 xpath 中的运算符优先级,肯定有一些我不明白的地方。
只是为了检查,我试试
/osm/node/tag[not(@k = "source")]/..
结果如预期:
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="power" v="tower" />
</node>'
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
进一步试验我尝试将表达式组合成
/osm/node/tag[@v = "Microsoft Bing orbital imagery" and ../tag[@k = "power"]]/..
结果如预期:
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
很好...所以以下应该有效:
/osm/node/tag[@v = "Microsoft Bing orbital imagery" and ../tag[not(@k = "power")]]/..
结果,与我预期的不同:
Element='<node id="3736237027" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771207" lon="-16.3332326">
<tag k="source" v="Microsoft Bing orbital imagery" />
</node>'
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
我是不是误解了 not() 的工作方式?
顺便说一句,所有这些测试都是使用 http://www.freeformatter.com/xpath-tester.html 执行的 - 我不知道它是否是测试 XPath 的正确工具。
我尝试将多种组合条件作为单个 XPath 表达式来实现,还是需要两步过程,首先 select 具有我需要的标签属性的元素,然后不包括那些我不喜欢的?
第一个 XPath 可以更简单地写成
/osm/node[tag/@v = "Microsoft Bing orbital imagery"]
然后您可以添加第二个条件 "and there's no tag other than source":
/osm/node[tag/@v = "Microsoft Bing orbital imagery"
and not(tag/@k != 'source')]
问题不在于优先级,而在于范围。你想否定 tag
,而不是它的属性。您的最后一个 XPath 试图搜索一个标记,其兄弟或自身 tag
具有不同于 "power".
的 @k
看来,现在总是用源标记 Openstreetmap 节点是一个坏习惯 - 只有当源是特定的并且与标记到变更集的源不同时,才应指定源标记。当节点没有其他标签时,尤其不受欢迎。并非总是如此——曾经有一段时间,变更集标记不是标准做法。因此,在我进行了大量编辑的一些地方,我需要做一些清理工作,我打算为自己构建一个工具。
例如,让我们从这个示例数据集开始:
<?xml version='1.0' encoding='UTF-8'?>
<osm version='0.6' upload='true' generator='JOSM'>
<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
</node>
<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="power" v="tower" />
</node>
<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>
</osm>
首先我想 select 所有包含 <tag k="source" v="Microsoft Bing orbital imagery" />
的 Openstreetmap 节点 - 使用起来非常简单
/osm/node/tag[@v = "Microsoft Bing orbital imagery"]/..
结果如预期:
Element='<node id="3736237027" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771207" lon="-16.3332326">
<tag k="source" v="Microsoft Bing orbital imagery" />
</node>'
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
但是第二个元素也有一个 <tag k="power" v="tower" />
,我不希望 select 节点带有任何标签,但带有源标签。所以我尝试
/osm/node/tag[@v = "Microsoft Bing orbital imagery" and ../tag[not(@k != "source")]]/..
结果:这让我得到与上面完全相同的结果。关于 xpath 中的运算符优先级,肯定有一些我不明白的地方。
只是为了检查,我试试
/osm/node/tag[not(@k = "source")]/..
结果如预期:
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="power" v="tower" />
</node>'
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
进一步试验我尝试将表达式组合成
/osm/node/tag[@v = "Microsoft Bing orbital imagery" and ../tag[@k = "power"]]/..
结果如预期:
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
很好...所以以下应该有效:
/osm/node/tag[@v = "Microsoft Bing orbital imagery" and ../tag[not(@k = "power")]]/..
结果,与我预期的不同:
Element='<node id="3736237027" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771207" lon="-16.3332326">
<tag k="source" v="Microsoft Bing orbital imagery" />
</node>'
Element='<node id="3736237028" timestamp="2015-09-09T15:27:34Z" uid="160042" user="Jean-Marc Liotier" visible="true" version="1" changeset="33912319" lat="15.4771238" lon="-16.3349496">
<tag k="source" v="Microsoft Bing orbital imagery" />
<tag k="power" v="tower" />
</node>'
我是不是误解了 not() 的工作方式?
顺便说一句,所有这些测试都是使用 http://www.freeformatter.com/xpath-tester.html 执行的 - 我不知道它是否是测试 XPath 的正确工具。
我尝试将多种组合条件作为单个 XPath 表达式来实现,还是需要两步过程,首先 select 具有我需要的标签属性的元素,然后不包括那些我不喜欢的?
第一个 XPath 可以更简单地写成
/osm/node[tag/@v = "Microsoft Bing orbital imagery"]
然后您可以添加第二个条件 "and there's no tag other than source":
/osm/node[tag/@v = "Microsoft Bing orbital imagery"
and not(tag/@k != 'source')]
问题不在于优先级,而在于范围。你想否定 tag
,而不是它的属性。您的最后一个 XPath 试图搜索一个标记,其兄弟或自身 tag
具有不同于 "power".