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