PHP replaceChild для каждого parentNode - PullRequest
       9

PHP replaceChild для каждого parentNode

4 голосов
/ 07 декабря 2011

Я использую этот код PHP для замены ряда узлов в файле XML:

<?php
$xml = "
<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>
<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>
<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>
<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>
<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>
";
 function renameTags($xml, $old, $new)
{
$dom = new DOMDocument();
$dom->loadXML($xml);

$nodes = $dom->getElementsByTagName($old);

$toRemove = array();

foreach ($nodes as $node)
{
$newNode = $dom->createElement($new);

foreach ($node->attributes as $attribute)
{
    $newNode->setAttribute($attribute->name, $attribute->value);
}

foreach ($node->childNodes as $child)
{
    $newNode->appendChild($node->removeChild($child));
}

$node->parentNode->appendChild($newNode);
$toRemove[] = $node;
  break;

}

foreach ($toRemove as $node)
{
  $node->parentNode->removeChild($node);

}

$dom->formatOutput = TRUE;
return $dom->saveXML();
}

$xml = renameTags($xml, 'name', 'Source');
$xml = renameTags($xml, 'name', 'parentCategory');
$xml = renameTags($xml, 'name', 'Category');
$xml = renameTags($xml, 'name', 'subCategory');
$xml = renameTags($xml, 'name', 'sisterCategory');

echo $xml;
?>

Однако этот код заменяет и работает только для одного набора продуктов. Я думаю, что мне нужно вызвать оператор foreach где-нибудь в функции, состоящей из foreach parentNode ('product'), заменить имена тегов. Что мне нужно добавить, чтобы функция перебирала все наборы продуктов?

Приведенный выше код напечатает это: (обратите внимание, что первый набор именных узлов пропал и заменен указанными новыми узлами)

<?xml version="1.0"?>
<products>
<product>
<ItemId>531670</ItemId>
<modelNumber>METRA ELECTRONICS/MOBILE AUDIO</modelNumber>
<Source>Buy</Source>
<parentCategory>Car, Marine &amp; GPS</parentCategory>
<Category>Car Installation Parts</Category>
<subCategory>Deck Installation Parts</subCategory>
<sisterCategory>Antennas &amp; Adapters</sisterCategory></product>
<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>
<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>
<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>
<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>

Как видите, он заменяет только один экземпляр продукта.

1 Ответ

4 голосов
/ 07 декабря 2011

Ваша проблема заключалась в разрыве в этом foreach: он останавливался на первом узле <name>, с которым столкнулся, независимо от того, где он находился в документе.

Сначала вам нужно пройтись по продуктам, а затем по <name> узлам продукта.Примерно так:

function renameTags($xml, $old, $new) {
    $toRemove = array();
    $dom = new DOMDocument();
    $dom->loadXML($xml);
    $products = $dom->getElementsByTagName('product');

    foreach($products as $product) {
        $nodes = $product->getElementsByTagName($old);

        foreach ($nodes as $node) {
            $newNode = $dom->createElement($new);

            foreach ($node->attributes as $attribute) {
                $newNode->setAttribute($attribute->name, $attribute->value);
            }

            foreach ($node->childNodes as $child) {
                $newNode->appendChild($node->removeChild($child));
            }

            $node->parentNode->appendChild($newNode);
            $toRemove[] = $node;

            break;
        }
    }

    foreach ($toRemove as $node) {
      $node->parentNode->removeChild($node);
    }

    $dom->formatOutput = TRUE;
    return $dom->saveXML();
}
...