用于在 ReplaceChild 之后下一个停止循环的 XML Dom

Dmi*_*kin -1 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;
}
Run Code Online (Sandbox Code Playgroud)

所以 $i 总是 = 0 为什么会发生这种情况?

ThW*_*ThW 5

DOMNode::getElementsByTagName() 返回一个“实时”列表。如果文档更改,它也会更改。您替换了节点,因此列表也会发生变化。

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

  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');

XPath 表达式比用于获取节点的 DOM 方法更加灵活和强大,并且结果不是“实时”的。例如,您可以执行以下操作:

$Autos = $xpath->evaluate('//cars[@manufacturer = "SomeCompanyName"]');
Run Code Online (Sandbox Code Playgroud)

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

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

$Autos->item($i)->parentNode->replaceChild(
  $NewElement->cloneNode(TRUE), $Autos->item($i)
);
Run Code Online (Sandbox Code Playgroud)

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

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

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