2012-01-09 80 views
3

我用这个XPath表达式来列出所有“无试验”项目:我XPATH表达不能正常工作

/Items/Item[State!='TEST']/Name 

通常输入XML看起来是这样的,一切工作正常:

<Items> 
    <Item> 
    <Name>Item1</Name> 
    <State>ACTIVE</State> 
    </Item> 
    <Item> 
    <Name>Item2</Name> 
    <State>TEST</State> 
    </Item> 
</Items> 

但Item错过State元素时,xpath表达式不会选择任何内容:

<Items> 
    <Item> 
    <Name>Item1</Name> 
    </Item> 
    <Item> 
    <Name>Item2</Name> 
    </Item> 
</Items> 

请问我该如何更改我的xpath表达式n,以便State元素不存在时它也可以工作?如果状态元素不存在则将项目视为“不测试”项目。我没有选择更改xml结构。

回答

5

使用下面的表达式:

/Items/Item[not(State='TEST')]/Name 

的区别在于State!='TEST'选择具有任何State元件,其字符串值不等于TEST的那些项目,而not(State='TEST')选择不具有State元件,其字符串值的所有项目等于TEST(是否存在State)。这是一个微妙但显着的差异。

the spec

如果一个要比较的对象是一个节点集合,而另一个是一个字符串, 则比较为真,当且仅当存在在 节点的节点 - 设置,以便对节点的字符串值和其他字符串执行比较的结果为true。

此外,设想以下输入:

<Items> 
    <Item> 
     <Name>Item1</Name> 
     <State>blah</State> 
     <State>TEST</State> 
    </Item> 
    <Item> 
     <Name>Item2</Name> 
     <State>TEST</State> 
    </Item> 
</Items> 

该表达式:

/Items/Item[State!='TEST']/Name 

...将选择第一ItemName元件,因为它包含至少一个State元素值不为TEST

然而,这个表达式:

/Items/Item[not(State='TEST')]/Name 

...选择任何项目。第二种形式通常是你想要的。

见本说明from the spec

注:如果$x绑定到节点集,然后$x="foo"并不意味着 一样not($x!="foo"):前者为真,当且仅当一些节点 $x具有字符串值foo;后者是真实的当且仅当全部 $x中的节点具有字符串值foo

+0

+1,很好的答案。你确定关于语句“State!='TEST''选择那些其(第一)状态元素的值不等于TEST的项目”吗?我认为它选择那些具有* any *'State'子元素的整个值不等于'TEST'的项目。换句话说,我相信比较中的节点测试不会折叠为字符串值,以至于不能排除存在性比较。 – LarsH 2012-01-09 20:48:49

+0

@LarsH - 当然你是对的。更新。 – 2012-01-09 21:01:37

+0

它的工作原理!非常感谢你们的帮助! – Vojtech 2012-01-10 10:59:44