XPath 1.0 - 根据分布在多个节点上的文本值进行选择

时间:2015-06-13 13:29:21

标签: php xpath domxpath

<root>
  <div>
    <p>this text</p>
    <p><span>fo</span><span>ob</span><span>ar</span></p>
  </div>
  <div>
    <p>this text</p>
    <p><span>fo</span><span>b</span><span>ar</span></p>
  </div>
  <div>
    <p>this text</p>
    <p><span>fooba</span><span>r</span></p>
  </div>
  <div>
    <p><span>foo</span>this text<span>bar</span></p>
  </div>
  <div>
    <p><span>foo</span><img/><span>bar</span></p>
  </div>
  <div>
    <p><span>foo</span><span>bar</span><span>baz</span></p>
  </div>
  <div>
    <p>foobar</p>
  </div>
</root>

鉴于上述XML,XPath 1.0查询会根据<div>中出现的foobar或多个连续<span>中的<span>来选择<div>?我只想选择第一个和第三个<div>。第二个fobar包含foobar,而不是<div>。在第四个<span>中,<div>不是连续的。第五个<img><span>之间有一个foobarbaz,因此它们不再是连续的,第六个的文本是foobar,而不是<span> 。第七个文本具有正确的文本,但不在concat() s内。

我尝试使用concat(//*, //*),但这不起作用,因为我需要先知道参数的数量。另外,说concat(//*[1], //*[1])等同于http://localhost:8080/github-webhook,这不是我想要的。

这是在PHP中,所以我只有XPath 1.0。

2 个答案:

答案 0 :(得分:2)

你可以尝试这个XPath:

/root/div[contains(normalize-space(.), 'foobar')]

请注意.返回当前上下文节点中所有文本节点的连接。

xpath tester中的输出:

Element='<div>
  <p>this text</p>
  <p>
    <span>fo</span>
    <span>ob</span>
    <span>ar</span>
  </p>
</div>'
Element='<div>
  <p>this text</p>
  <p>
    <span>fooba</span>
    <span>r</span>
  </p>
</div>'

答案 1 :(得分:0)

我有一个文档,其中的段落(

)的字符串值(。)包含前缀(问题:)。我需要删除前缀和所有祖先元素,但保留段落(

)以及前缀之后的所有元素。前缀可能已经分布在XML中不同深度的多个元素上。此解决方案仅限于XSLT 1.0。我发现通过遍历子孙:: text()并跟踪文本节点字符串长度的总和,可以确定我何时在包含前缀末尾的文本节点处。请注意,应用模板选择仅选择以前缀开头的段落,因此仅允许使用文本节点长度的总和来检测在哪里停止。您也可以累积实际的字符串,并使用其他测试(包含)确定何时停止。

示例XML(请注意测试所需的复杂性)

<?xml version="1.0" encoding="utf-8" ?>
<root>
    <p><d1><d2>q<a>u<b>e<c>s</c><d>t</d>i</b><e>o</e></a><f>n</f>:</d2></d1> text</p>
</root>

样本XSL(注意用于记录功能)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/root/p[substring(.,1,9)='question:']">
      <trace info="{concat('ML descendant::text()[1]:',' name=',name(),', .=',.)}"/>
      <xsl:apply-templates select="descendant::text()[1]" mode="m1"/>
  </xsl:template>

  <xsl:template mode="m1" match="text()">
      <xsl:param name="length" select="0"/>
      <xsl:variable name="temp" select="$length+string-length()"/>

      <trace info="{concat('m1:',' name=',name(),', length=',$temp,', .=',.)}"/>
      <xsl:choose>
          <xsl:when test="$temp&lt;9">
            <xsl:apply-templates select="following::text()[1]" mode="m1">
                <xsl:with-param name="length" select="$temp"/>
            </xsl:apply-templates>
          </xsl:when>
          <xsl:otherwise>              
            <trace info="m1: prefix match"/>
          </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0" encoding="UTF-8"?>
    <trace info="ML descendant::text()[1]: name=p, .=question: text"/>
<trace info="m1: name=, length=1, .=q"/>
<trace info="m1: name=, length=2, .=u"/>
<trace info="m1: name=, length=3, .=e"/>
<trace info="m1: name=, length=4, .=s"/>
<trace info="m1: name=, length=5, .=t"/>
<trace info="m1: name=, length=6, .=i"/>
<trace info="m1: name=, length=7, .=o"/>
<trace info="m1: name=, length=8, .=n"/>
<trace info="m1: name=, length=9, .=:"/>
<trace info="m1: prefix match"/>