【问题标题】:SimpleXml::xpath() after simplexml_import_dom() operates on the whole DomDocument and not just the Nodesimplexml_import_dom() 之后的 SimpleXml::xpath() 对整个 DomDocument 进行操作,而不仅仅是对 Node
【发布时间】:2019-01-07 03:25:48
【问题描述】:

我不确定这是预期的行为还是我做错了什么:

<?php

$xml = '<?xml version="1.0"?>
<foobar>
<foo>
<nested>
<img src="example1.png"/>
</nested>
</foo>
<foo>
<nested>
<img src="example2.png"/>
</nested>
</foo>
</foobar>';

$dom = new DOMDocument();
$dom->loadXML($xml);

$node = $dom->getElementsByTagName('foo')[0];

$simplexml = simplexml_import_dom($node);
echo $simplexml->asXML() . "\n";

echo " === With // ====\n";
var_dump($simplexml->xpath('//img'));


echo " === With .// ====\n";
var_dump($simplexml->xpath('.//img'));

即使我只导入了一个特定的 DomNode,并且 asXml() 只返回该部分,xpath() 似乎仍然对整个文档进行操作。

我可以通过使用 .//img 来防止这种情况发生,但这对我来说似乎很奇怪。

结果:

<foo>
<nested>
<img src="example1.png"/>
</nested>
</foo>
 === With // ====
array(2) {
  [0] =>
  class SimpleXMLElement#4 (1) {
    public $@attributes =>
    array(1) {
      'src' =>
      string(12) "example1.png"
    }
  }
  [1] =>
  class SimpleXMLElement#5 (1) {
    public $@attributes =>
    array(1) {
      'src' =>
      string(12) "example2.png"
    }
  }
}
 === With .// ====
array(1) {
  [0] =>
  class SimpleXMLElement#5 (1) {
    public $@attributes =>
    array(1) {
      'src' =>
      string(12) "example1.png"
    }
  }
}

【问题讨论】:

    标签: php xpath simplexml


    【解决方案1】:

    这是预期的行为。您正在将 DOM 元素节点导入 SimpleXMLElement。这不会在后台修改 XML 文档 - 节点保持其上下文。

    这里是上升到(parent::ancestor::)或兄弟姐妹(preceding-sibling::following-sibling::)的 Xpath 表达式。

    / 开头的位置路径始终相对于文档,而不是上下文节点。使用. 显式引用当前节点可避免该触发器。 .//imgcurrent()/descendant-or-self::img 的缩写,也可以是 descendant::img

    但是,您无需将 DOM 节点转换为 SimpleXMLElement 即可使用 Xpath。

    $document = new DOMDocument();
    $document->loadXML($xml);
    $xpath = new DOMXpath($document);
    
    foreach ($xpath->evaluate('//foo[1]') as $foo) {
      var_dump(
        $xpath->evaluate('string(.//img/@src)', $foo)
      );
    }
    

    输出:

    string(12) "example1.png"
    

    //foo[1] 获取文档中的第一个 foo 元素节点。如果文档中没有匹配的元素,它将返回一个空列表。使用foreach 可以避免这种情况下的错误。它将被迭代一次或永远不会。

    string(.//img/@src) 获取后代img 元素的src 属性并将第一个元素转换为字符串。如果这里没有匹配的节点,则返回值为空字符串。 DOMXpath::evaluate() 的第二个参数是上下文节点。

    【讨论】:

    • 谢谢,很好的回答。很高兴知道,起初不是很直观,但很有意义。我知道我也可以在 DOM 上使用 xpath,这只是从一段较大的代码中提取的一个示例 sn-p(我也在这样做)。我想我可以将它重构为仅使用 DOM,但使用 SimpleXML 对图像元素及其周围结构进行额外处理会更容易:)
    猜你喜欢
    • 2021-10-02
    • 1970-01-01
    • 2020-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-05
    • 2018-05-03
    • 1970-01-01
    相关资源
    最近更新 更多