**编辑澄清**
我继承了一堆类似于以下结构的xml文档(配置文件)(为简洁起见,元素名称更改和结构化简化。
<containers>
<container id="c1">
<ports>
<port id="p2"/>
</ports>
<rules>
<!--
Within a container, a rule must refer to a port
declared within the same container.
A rule cannot refer to a port that does not
exist in the enclosing container.
-->
<rule id="r1" portId="p1"/><!-- p1 is not in c1, but in c2, bad -->
<rule id="r2" portId="p2"/><!-- this is good -->
<rule id="r3" portId="p3"/><!-- p3 is nowhere, bad -->
</rules>
</container>
<container id="c2">
<ports>
<port id="p1"/>
<port id="p2"/>
</ports>
<rules>
<rule id="r1" portId="p1"/>
</rules>
</container>
</containers>
容器可以有点和规则(点和规则ID可以在容器之间重复;它们只需要在容器中是唯一的。)
要求是如果规则引用了一个点id,那么必须在封闭容器中定义该点id。
我需要在容器中搜索规则,错误地引用不存在的点。
我有xpath表达式可以找到指向不存在点的规则(不幸的是整个xml文档。)
//*/rule/@portId[not( . = //*/port/@id)]
该规则适用于整个文档,它不包含在容器中。
也就是说,这个xpath表达式会检测到容器c1中的规则r3引用了文档中不存在的端口p3。
但是,同样的xpath表达式将不检测到容器c1中的规则r1指的是不在容器c1中的端口p2。为什么?因为此xpath表达式将与容器c2中的端口p2匹配。
我的xpath表达式无法检测到此内容。
当然,我可以使用几个xpath表达式并在它们之间粘合代码(例如,通过将xpath表达式应用于每个容器),但我希望是否可以使用从根元素开始的单个xpath表达式
有什么建议吗?
答案 0 :(得分:2)
使用ancestor::
轴的另一个选项......
//rule[not(@portId = ancestor::container//port/@id)]
答案 1 :(得分:1)
试试这个。
//rule[@portId[not(. = ./parent::rule/parent::rules/parent::container/*/port/@id)]]
这似乎对我有用。经过测试:
<containers>
<container id="c1">
<ports>
<port id="p2"/>
<port id="p4"/>
</ports>
<rules>
<!--
Within a container, a rule must refer to a port
declared within the same container.
A rule cannot refer to a port that does not
exist in the enclosing container.
-->
<rule id="r1" portId="p1"/><!-- p1 is not in c1, but in c2, bad -->
<rule id="r2" portId="p2"/><!-- this is good -->
<rule id="r3" portId="p3"/><!-- p3 is nowhere, bad -->
</rules>
</container>
<container id="c2">
<ports>
<port id="p1"/>
<port id="p2"/>
</ports>
<rules>
<rule id="r1" portId="p1"/>
<rule id="r2" portId="p4"/>
</rules>
</container>
</containers>
获得以下输出
Element='<rule id="r1" portId="p1"/>'
Element='<rule id="r3" portId="p3"/>'
Element='<rule id="r2" portId="p4"/>'