【问题标题】:PHP DomXPath not selecting empty text nodesPHP DomXPath 不选择空文本节点
【发布时间】:2015-03-24 19:23:04
【问题描述】:

我正在尝试选择不包含任何文本的节点。这段 php 代码跳过了示例 xml 中的空节点。但是,当我尝试在线测试器(如http://freeformatter.com/xpath-tester.html)时,它没有任何问题。

这是 PHP 的事情吗?

我的php代码:

    $path = "//RecipeSteps/RecipeStep[not(text())]";
    $stepsQuery = $this->xpath->query($path);
    $numResults = $stepsQuery->length;

我的示例 xml:

<?xml version="1.0" encoding="utf-8"?>
<Recipes>
    <RecipeSteps>
      <RecipeStep number="1">Dummy content</RecipeStep>
      <RecipeStep number="2">Dummy content</RecipeStep>
      <RecipeStep number="3">Dummy content</RecipeStep>
      <RecipeStep number="4">Dummy content</RecipeStep>
      <RecipeStep number="5">Dummy content</RecipeStep>
      <RecipeStep number="6"></RecipeStep>
      <RecipeStep number="7">Variations</RecipeStep>
      <RecipeStep number="8">Some variation content..</RecipeStep>
    </RecipeSteps>
</Recipes>

【问题讨论】:

  • 我不知道为什么这不起作用,但这应该起作用: $emptyRecipeSteps=call_user_func(function() use (&$DOMDocument){$ret=array();foreach($DOMDocument- >getElementsByTagName("RecipeStep") as &$recipeStep){if(empty($recipeStep->textContent){$ret[]=$recipeStep;}}return $ret;});
  • PHP 和您引用的在线示例给出完全相同的结果:3v4l.org/bKuOd - 那么您在烦恼什么?

标签: php xml xpath domxpath


【解决方案1】:

如果您正在寻找 XPATH 解决方案,请使用 //RecipeSteps/(RecipeStep[string-length() = 0])。 例如

$path = "//RecipeSteps/(RecipeStep[string-length() = 0])";
$stepsQuery = $this->xpath->query($path);
$numResults = $stepsQuery->length;

【讨论】:

  • 这不是一个函数,它的目的是选择上下文节点的所有文本节点。 w3.org/TR/xpath/#location-paths。 //not(contains[text()]) 将为所有不是文本节点的节点返回 true,但不会返回节点。 videlibri.sourceforge.net/cgi-bin/xidelcgi 对您来说是一个很好的资源,您可以在其中针对 xml/html 测试 xpath 查询
  • @doub1ejack 并非如此,在这种情况下两者都返回相同的值。看我的回答。并且不要在 videlibri.sourceforge.net/cgi-bin/xidelcgi 上测试 - 它是 XPath 2.0 引擎,而 DomXPath 仅支持 XPath 1.0。
  • @MathiasMüller 似乎是对的。之前的测试有效。他对 Xpath 2.0 的观点也是正确的。我从 xpath 的角度回答。但是我不确定你为什么说我的答案不正确,我认为问题是不应该有字符串,而我提供的测试就是这样?
  • @MadsBjaerge 请仔细阅读;我没有说您的答案不正确(但是,您的评论不正确://not(contains[text()]) 不是有效的表达式)。你的回答是正确的——我是说它不能解决问题,因为路径表达式一开始就不是问题(除了 OP 的输入文档实际上不同)。
【解决方案2】:

在选择完整路径时,它工作:

$xmlString = '<?xml version="1.0" encoding="utf-8"?>
<Recipes>
    <RecipeSteps>
      <RecipeStep number="1">Dummy content</RecipeStep>
      <RecipeStep number="2">Dummy content</RecipeStep>
      <RecipeStep number="3">Dummy content</RecipeStep>
      <RecipeStep number="4">Dummy content</RecipeStep>
      <RecipeStep number="5">Dummy content</RecipeStep>
      <RecipeStep number="6"></RecipeStep>
      <RecipeStep number="7">Variations</RecipeStep>
      <RecipeStep number="8">Some variation content..</RecipeStep>
    </RecipeSteps>
</Recipes>';

$dom = new DOMDocument();
$dom->loadXML($xmlString);
$xpath = new DOMXpath($dom);
# it works also well: //RecipeSteps/RecipeStep[not(text())]
$query = $xpath->query('//Recipes/RecipeSteps/RecipeStep[not(text())]');
//returns "6"
print 'RecipeStep number: ' . $query->item(0)->getAttribute('number');

此外,选择“//RecipeSteps/RecipeStep[not(text())]”也很有效。所以很可能你做错了什么。

【讨论】:

    【解决方案3】:

    路径表达式//RecipeStep[not(text())] 和//RecipeStep[string-length() = 0] 含义不同,但是将您显示的文档作为输入,它们返回完全相同。在这两种情况下,都会选择一个RecipeStep 节点作为结果:

    <RecipeStep number="6"/>
    

    //RecipeStep[not(text())] 用简单的英语表示:

    在文档中的任意位置选择名为 RecipeStep 的元素节点,但前提是它们没有任何直接子文本节点。

    另一方面,//RecipeStep[string-length() = 0] 表示

    在文档中的任意位置选择名为RecipeStep 的元素节点,但前提是它们的字符串值(所有后代文本节点的串联)的长度等于0。

    只有在第 6 步的配方实际上看起来像这样的情况下,差异才会很明显

    <RecipeStep number="6"><child>text</child></RecipeStep>
    

    然后,//RecipeStep[not(text())] 仍会选择此节点,而//RecipeStep[string-length() = 0] 不会返回任何内容。

    (为了清楚起见:我省略的前导 //RecipeSteps 不会改变任何东西。)

    因此,您的原始 XPath 表达式是正确的 - 并且接受的答案与您的原始答案完全相同。 XPath 在这里没有错。

    【讨论】:

    • 我相信在&lt;RecipeStep number="6"&gt; &lt;child&gt;text&lt;/child&gt; &lt;/RecipeStep&gt;的情况下,根据他的帖子选择那个是不正确的?
    • @MadsBjaerge 我不确定这就是你的意思,但我的帖子中确实存在错误,&lt;RecipeStep&gt; 和 &lt;child&gt; 之间的任何空格都会导致只有空格的文本节点是RecipeStep 的孩子。
    • 你是否同意如果你提到的我的情况成立,而你的情况不成立?
    • @MadsBjaerge 没有“真正的”路径表达式 - 它始终取决于您希望得到的结果。或者,换一种说法:我们不知道选择 &lt;RecipeStep number="6"&gt;&lt;child&gt;text&lt;/child&gt;&lt;/RecipeStep&gt; 作为结果是否是预期的行为 - OP 根本没有解释他们的要求。
    猜你喜欢
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    相关资源
    最近更新 更多