2014-09-01 42 views
3

这是用于C代码检测的。我试图标记没有休息的案例陈述。当break语句之前有多行时,树的层次结构如图所示。这是C中的例子:XPath:查找以下不遵循订单模式的兄弟姐妹

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> S其中任意数量的行后存在<break>,而是先下一<case>

此代码仅可以帮助我找到那些破不立即跟随的情况下:

//case [name(following-sibling::*[1]) != 'break'] 

..但是,当我尝试使用以下同胞:: *它会找到一个突破,但不一定在下一个案件之前。

我该怎么做?

+0

你可以使用XPath 2.0还是你坚持1.0?此外,你的第一段说你正在寻找*不*休息的病例陈述;你的第三段说你正在寻找那些*做*。它可能相当于几乎相同的东西,但清晰度会有所帮助。 – LarsH 2014-09-02 03:52:16

+0

好点@LarsH,我更新了我的答案以反映这个限制。 – 2014-09-02 13:07:58

+0

对不起,困惑。我试图从找到休息开始,认为我只是在声明中添加一个NOT来找到那些没有休息的人。 – user2755941 2014-09-02 20:38:18

回答

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::*) 
     ) 
    ) 
)] 
+0

非常感谢derp,我没有想过要比较下一个案例的中断位置。这帮助我解决了我的问题! – user2755941 2014-09-02 20:44:28

1

我认为你很挣扎,因为你的XML格式并没有很好地模拟这个问题。如果其他语句嵌套在<case>元素中,而不是兄弟姐妹,那么您可以仅使用switch/case[break]

使用您当前的结构,最简单的方法是找到<break>,然后向后找到匹配的<case>。正如@LarsH指出的那样,我的原始表达式会找到一些额外的子句。它不能真正进行修改,以解决这个问题,除非你限制它找到刚才第一种情况:

switch/break/preceding-sibling::case[1] 

@ DERP的回答是好,可有或没有休息发现这两种情况。

+0

一般来说,这个XPath表达式可能会产生两个有中断的case语句,而那些没有(但后面跟另一个有中断的情况)的case语句。 – LarsH 2014-09-02 03:56:31

0

DERP的答案是正确的。但我会再添加一个。这将选择壳体元素做有一个突破:

//case[generate-id(.) = 
     generate-id(following-sibling::break[1]/preceding-sibling::case[1])] 

。换句话说,这种选择的情况下的元件指此为真: 上下文元件是相同的下破元件(仅考虑兄妹前述第一壳体元件)。

如果你有很多病例陈述,这个变种可能会比使用count()更快。但是除非您使用相关XPath处理器对相关数据进行测试,否则您永远无法确定。

顺便说一句,.generate-id(.)不是必需的,因为无论如何参数默认为.。但为了可读性,我更愿意明确说明。

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)]