替换孩子后,下一站停止循环的XML Dom

时间:2015-01-15 15:12:04

标签: php xml replace

然后我尝试在第一个替换循环停止后使用此代码 $Autos->length = 10

$Autos = $dom->getElementsByTagName('cars'); // Find Sections 
$NewElement = $dom->createElement('hello','hi');
for ($i = 0; $i < $Autos->length; $i++) 
{

    $Autos->item($i)->parentNode->replaceChild($NewElement, $Autos->item($i));
    echo $Autos->length . " i= " .$i;
}

所以$ i总是= 0 为什么会这样?

1 个答案:

答案 0 :(得分:3)

DOMNode :: getElementsByTagName()返回&#34; live&#34;名单。如果文档被更改,它会更改。您替换节点,因此列表也会更改。

以下是解决此问题的三种方法。

  1. 将节点列表转换为数组:

    $Autos = iterator_to_array($dom->getElementsByTagName('cars'));

  2. 将列表从最后一个节点循环到第一个节点:

    for ($i = $Autos->length - 1; $i >= 0; $i--) {

  3. 使用XPath获取节点:

    $xpath = new DOMXPath($dom);
    $Autos = $xpath->evaluate('//cars');

  4. XPath表达式比获取节点的DOM方法更灵活,更强大,结果不是“直播”。例如,您可以执行以下操作:

    $Autos = $xpath->evaluate('//cars[@manufacturer = "SomeCompanyName"]');
    

    这是您来源中的另一个问题。您只用一个创建的节点替换节点。所以它替换了第一个节点,然后同一个节点替换了第二个节点,......直到它替换了列表中的最后一个节点。

    您需要克隆已创建的节点:

    $Autos->item($i)->parentNode->replaceChild(
      $NewElement->cloneNode(TRUE), $Autos->item($i)
    );
    

    节点列表实现了Traversable接口。你可以使用foreach()。

    foreach ($xpath->evaluate('//cars') as $i => $car) {
      $car->parentNode->replaceChild($NewElement->cloneNode(TRUE), $car);
      echo " i= " .$i;
    }
    

    作为旁注。构建新的目标XML文档并将节点复制到它然后操作现有文档通常更容易。 XSLT是一种专门用于此任务的特定语言。