PHP заменяет только 1 узел серии - PullRequest
1 голос
/ 07 декабря 2011

У меня есть XML-файл, который в настоящее время имеет 4 узла с одинаковым именем: Файл выглядит следующим образом: (data.xml)

<?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>

Имеется 4 узла с одинаковым именем.(узел имени).

Затем я использую этот код PHP для замены имен узлов

 <?php 
/**
 * @param $xml string Your XML
 * @param $old string Name of the old tag
 * @param $new string Name of the new tag
 * @return string New XML
 */
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;
}

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

return $dom->saveXML();
}

  // Load XML from file data.xml
$xml = file_get_contents('data.xml');

$xml = renameTags($xml, 'name', 'newName');

echo $xml;
?> 

Эта функция заменяет все узлы имени на newName;однако я хочу заменить только один экземпляр тега name, потому что хочу переименовать каждый из тегов name.Если я назову другой $ xml = renameTags ($ xml, 'name', 'newName2');

Это не будет работать, он будет использовать только первый экземпляр $ xml.

Любая идеякак я могу изменить свой код, чтобы позволить мне заменять каждый узел имени отдельно?

1 Ответ

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

Если вы просто хотите переименовать первый встреченный узел, добавьте оператор break; в конце вашего первого цикла foreach, как в этом первом примере. Однако это ужасно неэффективно, и лучший способ сделать это продемонстрирован во втором (ПРАВИЛЬНОМ) примере внизу.

НЕПРАВИЛЬНЫЙ ПУТЬ Каждый раз, когда вы заменяете XML таким образом, ангел проливает слезу ...

$src = "
<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>
";

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($src, 'name', 'newName');
echo $xml;

ПРАВИЛЬНЫЙ ПУТЬ

function renameTags($xml, $old, $new)
{
  $dom = new DOMDocument();
  $dom->loadXML($xml);

  // find the first node with the specified tag name
  $oldNode = $dom->getElementsByTagName($old)->item(0);

  // clone the node (deep copy)
  $doppelganger = $oldNode->cloneNode(TRUE);

  // import our cloned node to this dom document
  $doppelganger = $dom->importNode($doppelganger, true);

  // Create new node with the value from the copied node
  $newNode = $dom->createElement($new, $doppelganger->nodeValue);

  // update all the attributes of the new node with those from the copy
  foreach ($doppelganger->attributes as $attrName => $attrNode) {
    $newNode->setAttribute($attrName, $attrNode);
  }

  // append the newNode copy to the dom
  $oldNode->parentNode->appendChild($newNode);

  // remove the old node
  $oldNode->parentNode->removeChild($oldNode);

  $dom->formatOutput = TRUE;
  return $dom->saveXML();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...