php只追加5个子节点中的3个

时间:2011-12-07 03:37:37

标签: php xml dom

此代码仅附加5个名称节点中的3个。这是为什么? 这是原始的XML: 它有5个名称节点。

<?xml version='1.0'?>
<products>
<product>
<itemId>531670</itemId>
<modelNumber>METRA ELECTRONICS/MOBILE AUDIO</modelNumber>
<categoryPath>
<category><name>Buy</name></category>
<category><name>Car, Marine &amp; GPS</name></category>
<category><name>Car Installation Parts</name></category>
<category><name>Deck Installation Parts</name></category>
<category><name>Antennas &amp; Adapters</name></category>
</categoryPath>
</product>

</products>  

然后运行这个PHP代码。这被假定为将所有名称节点附加到产品节点中。

<?php

// load up your XML
$xml = new DOMDocument;
$xml->load('book.xml');

// Find all elements you want to replace. Since your data is really simple,
// you can do this without much ado. Otherwise you could read up on XPath.
// See http://www.php.net/manual/en/class.domxpath.php
//$elements = $xml->getElementsByTagName('category');

// WARNING: $elements is a "live" list -- it's going to reflect the structure
// of the document even as we are modifying it! For this reason, it's
// important to write the loop in a way that makes it work correctly in the
// presence of such "live updates".


foreach ($xml->getElementsByTagName('product') as $product ) {
foreach($product->getElementsByTagName('name') as $name ) {
    $product->appendChild($name );
}
$product->removeChild($xml->getElementsByTagName('categoryPath')->item(0));
}

// final result:
$result = $xml->saveXML();
echo $result;
?>

最终结果是这个,它只附加3个名称节点:

<?xml version="1.0"?>
<products>
<product>
<itemId>531670</itemId>
<modelNumber>METRA ELECTRONICS/MOBILE AUDIO</modelNumber>
<name>Buy</name>
<name>Antennas &amp; Adapters</name>
<name>Car Installation Parts</name>
</product>
</products>

为什么只附加3个名称节点?

4 个答案:

答案 0 :(得分:1)

当您从中提取结果时,您正在修改DOM树。对树的任何修改都会覆盖先前查询操作的结果(您的getElementsByTagName)使这些结果无效,因此您将获得未定义的结果。对于添加/删除节点的操作尤其如此。

答案 1 :(得分:1)

当您迭代它们时,您正在移动节点,因此会跳过2个节点。我不是一个php人,所以我不能给你代码来做这个,但你需要做的是建立一个名称节点的集合,并反过来遍历该集合。

答案 2 :(得分:1)

您可以在附加之前临时将name元素添加到数组中,因为您实时修改了DOM。 getElementsByTagName()生成的节点列表可能会随着您移动节点而改变(实际上这似乎正在发生)。

<?php

// load up your XML
$xml = new DOMDocument;
$xml->load('book.xml');    

// Array to store them
$append = array();
foreach ($xml->getElementsByTagName('product') as $product ) {
foreach($product->getElementsByTagName('name') as $name ) {
  // Stick $name onto the array
  $append[] = $name;
}
// Now append all of them to product
foreach ($append as $a) {
    $product->appendChild($a);
}

$product->removeChild($xml->getElementsByTagName('categoryPath')->item(0));
}

// final result:
$result = $xml->saveXML();
echo $result;
?>

输出,附加所有值:

<?xml version="1.0"?>
<products>
<product>
<ItemId>531670</ItemId>
<modelNumber>METRA ELECTRONICS/MOBILE AUDIO</modelNumber>

<name>Buy</name><name>Car, Marine &amp; GPS</name><name>Car Installation Parts</name><name>Deck Installation Parts</name><name>Antennas &amp; Adapters</name></product>

</products>

答案 3 :(得分:0)

一种不太复杂的方法是使用insertBefore

操作节点
foreach($xml->getElementsByTagName('name') as $node){
    $gp = $node->parentNode->parentNode;
    $ggp = $gp->parentNode;
    // move the node above gp without removing gp or parent
    $ggp->insertBefore($node,$gp);
}
// remove the empty categoryPath node
$ggp->removeChild($gp);