这是用于C代码检测。我试图标记不会中断的案例陈述。当break语句之前有多行时,树的层次结构如下所示。这是C:
中的一个例子switch (x) {
case 1:
if (...) {...}
int y = 0;
for (...) {...}
break;
case 2:
它以某种方式表示为:
<switch>
<case>...</case>
<if>...</if>
<expression>...</expression>
<for>...</for>
<break>...</break>
<case>...</case>
</switch>
我需要找到<case>
个<break>
后任意行数,但在下一个<case>
之前。
这段代码只能帮助我找到休息时间不会紧随案例的那些代码:
//case [name(following-sibling::*[1]) != 'break']
..但是当我尝试使用follow-sibling :: *时会发现一个中断,但不一定在下一个案例之前。
我该怎么做?
答案 0 :(得分:2)
选择具有以下case
和的任何break
,不得跟随case
或下一个break
的位置小于case
下一个count()
的位置。通过在前面的兄弟姐妹上运行//case
[
following-sibling::break and
(
not(following-sibling::case) or
(
count(following-sibling::break[1]/preceding-sibling::*) <
count(following-sibling::case[1]/preceding-sibling::*)
)
)
]
来确定职位。
not()
要抓住其他案例,那些没有休息的案例,只需在其中抛出一个旧的//case
[not(
following-sibling::break and
(
not(following-sibling::case) or
(
count(following-sibling::break[1]/preceding-sibling::*) <
count(following-sibling::case[1]/preceding-sibling::*)
)
)
)]
:
{{1}}
答案 1 :(得分:1)
我认为你正在努力,因为你的XML格式并不能很好地模拟问题。如果其他语句嵌套在<case>
元素中,而不是兄弟姐妹,则会更容易,那么您可以使用switch/case[break]
。
根据您当前的结构,最简单的方法是找到<break>
,然后向后查找匹配的<case>
。正如@LarsH指出的那样,我原来的表达式会找到一些额外的条款。除非您将其限制为仅查找第一种情况,否则无法对其进行修改以解决此问题:
switch/break/preceding-sibling::case[1]
@ derp的答案更好,可以找到有和没有休息的两种情况。
答案 2 :(得分:1)
我同意@PeterHall,最好将XML重组为更接近代表C语法的抽象语法树的东西。您可以使用XSLT分组轻松地完成此操作(对于本例):
<xsl:for-each-group select="*" group-starting-with="case">
<case>
<xsl:copy-of select="current-group()[not(self::case)]"/>
</case>
</xsl:for-each-group>
然后,您可以找到没有中断的案例switch/case[not(break)]
。
答案 3 :(得分:0)
Derp的回答是正确的。但我会添加另一个。这将选择具有中断的案例元素:
//case[generate-id(.) =
generate-id(following-sibling::break[1]/preceding-sibling::case[1])]
换句话说,这会选择这样的case元素: context元素与下一个break元素之前的第一个case元素相同(仅考虑兄弟元素)。
如果你有很多案例陈述,这个变体可能比使用count()
更快。但除非您使用相关的XPath处理器使用相关数据对其进行测试,否则您永远不会确定。
顺便说一句,.
中的generate-id(.)
不是必需的,因为参数默认为.
。但为了便于阅读,我更愿意明确这一点。