【问题标题】:php only appending 3 out of 5 child nodesphp 仅附加 5 个子节点中的 3 个
【发布时间】:2011-12-07 03:37:36
【问题描述】:

此代码仅附加 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 个名称节点?

【问题讨论】:

    标签: php xml dom


    【解决方案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>
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • @Ben,正如我在回答中所说,您需要反向遍历名称节点。
      • 我建议在单独的 dom 文档中构建您的 &lt;name&gt; 集合,然后您可以在完成迭代/删除所需的节点后使用 -&gt;importNode() 将它们插入到原始文档中处理。
      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        一种不太复杂的方法是使用 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);
        

        【讨论】:

          猜你喜欢
          • 2019-12-07
          • 2010-11-25
          • 2014-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-19
          • 2014-02-11
          相关资源
          最近更新 更多