XPath:选择具有特定子项的元素而不是另一个特定子项

时间:2015-11-18 15:24:59

标签: xml xpath openstreetmap

现在看来,总是用源标记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>

首先,我想选择包含<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" />,我不想选择带有任何标签但是源标签的节点。所以我试试

/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表达式,还是需要两个步骤,首先选择具有我需要的标记属性的元素,然后排除我不需要的那些元素。 ; t?

1 个答案:

答案 0 :(得分:2)

第一个XPath可能更简单地写为

/osm/node[tag/@v = "Microsoft Bing orbital imagery"]

然后,您可以添加第二个条件,即“除了来源之外没有其他标记”:

/osm/node[tag/@v = "Microsoft Bing orbital imagery"
          and not(tag/@k != 'source')]

问题不是优先,而是范围。你想否定tag,而不是它的属性。你的最后一个XPath试图搜索一个标签,其兄弟或自我tag的@k与“power”不同。