XPath包含(text(),'some string')与具有多个Text子节点的节点一起使用时不起作用

时间:2010-09-07 03:26:39

标签: xpath dom4j

我有一个小问题,Xpath包含dom4j ...

让我说我的XML是

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

假设我想在给定根元素的文本中找到所有具有ABC的节点...

所以我需要写的xpath是

//*[contains(text(),'ABC')]

然而,这不是Dom4j返回的......这是一个dom4j问题还是我对xpath如何工作的理解。因为该查询仅返回Street元素而不返回Comment元素。

DOM使Comment元素成为具有四个标记2

的复合元素
[Text = 'XYZ'][BR][BR][Text = 'ABC'] 

我认为查询应该仍然返回元素,因为它应该找到元素并在其上运行contains但它不会... ...

以下查询返回元素,但它返回的远远多于元素,它还返回父元素...这对于问题是不可取的...

//*[contains(text(),'ABC')]

是否有人知道仅返回元素<Street/><Comment/>的xpath查询?

7 个答案:

答案 0 :(得分:604)

<Comment>标记包含两个文本节点和两个<br>个节点作为子节点。

你的xpath表达式是

//*[contains(text(),'ABC')]

要打破这种局面,

  1. *是一个匹配任何元素(即标记)的选择器 - 它返回一个节点集。
  2. []是对该节点集中的每个单独节点进行操作的条件。如果它操作的任何单个节点与括号内的条件匹配,则匹配。
  3. text()是一个选择器,它匹配作为上下文节点的子节点的所有文本节点 - 它返回一个节点集。
  4. contains是一个对字符串进行操作的函数。如果传递了节点集,则节点集为converted into a string by returning the string-value of the node in the node-set that is first in document order。因此,它只能匹配<Comment>元素中的第一个文本节点 - 即BLAH BLAH BLAH。由于这不匹配,您的结果中不会得到<Comment>
  5. 您需要将其更改为

    //*[text()[contains(.,'ABC')]]
    
    1. *是一个匹配任何元素(即标记)的选择器 - 它返回一个节点集。
    2. 外部[]是对该节点集中的每个单独节点进行操作的条件 - 此处它对文档中的每个元素进行操作。
    3. text()是一个选择器,它匹配作为上下文节点的子节点的所有文本节点 - 它返回一个节点集。
    4. 内部[]是一个条件,对该节点集中的每个节点进行操作 - 这里是每个单独的文本节点。每个单独的文本节点是括号中任何路径的起点,也可以在括号内明确表示为.。如果它操作的任何单个节点与括号内的条件匹配,则匹配。
    5. contains是一个对字符串进行操作的函数。这里传递一个单独的文本节点(.)。由于它会单独传递<Comment>标记中的第二个文本节点,因此会看到'ABC'字符串并且能够匹配它。

答案 1 :(得分:6)

[contains(text(),'')]仅返回true或false。它不会返回任何元素结果。

答案 2 :(得分:0)

我花了一段时间,但终于想通了。包含下面一些文本的自定义xpath对我来说非常合适。

//a[contains(text(),'JB-')]

答案 3 :(得分:0)

XML文档:

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

XPath表达式:

//*[contains(text(), 'ABC')]

//*descendant element中的任何root node相匹配。也就是说,除了根节点之外的任何元素。

[...]predicate,它过滤节点集。它返回...true的节点:

  

谓词过滤节点集以产生新的节点集。对于节点集中要过滤的每个节点,都会对PredicateExpr进行评估。如果PredicateExpr对该节点的评估为true,则该节点包括在新的节点集中;否则,不包括在内。

contains('haystack', 'needle')如果true contains haystack返回needle

  

功能:布尔包含(字符串,字符串)

     

如果第一个参数字符串包含第二个参数字符串,则contains函数返回true,否则返回false。

但是contains()将字符串作为其第一个参数。它已通过节点。为了处理通过string()函数将作为第一个参数传递的每个节点或节点集converted传递给字符串:

  

将参数转换为字符串类型,就像通过调用字符串函数一样。

string()函数返回the first node中的string-value

  

通过返回节点集中按文档顺序排在第一位的节点的字符串值,将节点集转换为字符串。如果节点集为空,则返回一个空字符串。

element node中的string-value

  

元素节点的字符串值是元素节点按文档顺序排列的所有文本节点后代的字符串值的串联。

text node中的string-value

  

文本节点的字符串值是字符数据。

因此,基本上string-value是节点中包含的所有文本(所有后代文本节点的串联)。

text()是与任何文本节点匹配的节点测试:

  

任何文本节点的节点测试text()为true。例如,child :: text()将选择上下文节点的文本节点子级。

话虽如此,//*[contains(text(), 'ABC')]匹配任何元素(但根节点除外),该元素的第一个文本节点包含ABC。由于text()返回的节点集包含上下文节点的所有子文本节点(相对于表达式求值)。但是contains()仅采用第一个。因此,对于上方的文档,路径匹配Street元素。

以下表达式//*[text()[contains(., 'ABC')]]与具有至少一个包含ABC的子文本节点的任何元素(但根节点除外)匹配。 .代表上下文节点。在这种情况下,它是除根节点以外的任何元素的子文本节点。因此,对于上方的文档,路径匹配StreetComment元素。

现在,//*[contains(., 'ABC')]与包含ABC的任何元素(但根节点除外)匹配(在后代文本节点的串联中)。对于上面的文档,它与HomeAddrStreetComment元素匹配。因此,//*[contains(., 'BLAH ABC')]HomeAddrComment元素匹配。

答案 4 :(得分:0)

接受的答案也将返回所有父节点。即使字符串在
之后,也仅使用ABC获得实际节点:

//*[text()[contains(.,'ABC')]]/text()[contains(.,"ABC")]

答案 5 :(得分:0)

//*[text()='ABC'] 

返回

<street>ABC</street>
<comment>BLAH BLAH BLAH <br><br>ABC</comment>

答案 6 :(得分:0)

这是匹配包含给定文本字符串的节点的另一种方法。首先查询文本节点本身,然后获取父节点:

//text()[contains(., "ABC")]/..

对我来说,这很容易阅读和理解。