使用PHP重命名XML节点

时间:2012-09-17 16:34:31

标签: php xml

我正在试图弄清楚如何使用PHP重命名XML节点?

我到目前为止:

$dom = new DOMDocument( '1.0' );
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;

// load the xml file
$dom->loadXML( '<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
  <data>
    <invite>
      <username>jmansa</username>
      <userid>1</userid>
    </invite>
    <update>1</update>
  </data>
</library>', LIBXML_NOBLANKS );
$xpath = new DOMXPath($dom);

//find all 'data' nodes.
$node = $xpath->query("//data");

// if found
if( $node->length ) {
    foreach ($node as $n) {
       // RENAME HERE? //
    }
}

echo "<xmp>". $dom->saveXML() ."</xmp>";

现在,我想将<data>重命名为<invites>。可以这样做,如果是,怎么做?

2 个答案:

答案 0 :(得分:1)

无法通过DOM重命名节点的名称(分别为“数据”或“邀请”),因为Node::nodeName property is read-only

您可以创建一个名为“invites”的新节点,将其附加到“data”节点之前,将“data”的子节点移动到新的“invites”节点,删除“data”节点,然后输出树得到你的结果。

示例:

<?php
// Create a test document.
    $dom = new DOMDocument( '1.0' );
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;

// Load the xml file.
    $dom->loadXML('<?xml version="1.0" encoding="ISO-8859-1"?'.'>
    <library>
      <data attr1="1" attr2="2">
        <invite>
          <username>jmansa</username>
          <userid>1</userid>
        </invite>
        <update>1</update>
      </data>
    </library>', LIBXML_NOBLANKS );
    $xpath = new DOMXPath($dom);

    // Convert <data> to <invites>.
    if ($dataNode = $xpath->query("/library/data")->item(0))
    {
    // Create the <invites> node.
        $invitesNode = $dom->createElement('invites');
        $dataAttrs   = $dataNode->attributes;
        foreach ($dataAttrs as $dataAttr)
        {   $invitesNode->setAttributeNodeNS($dataAttr->cloneNode());   }
        $dom->documentElement->appendChild($invitesNode);

    // Move the <data> children over.
        if ($childNodes = $xpath->query("/library/data/*"))
        {
            foreach ($childNodes as $childNode)
            {   $invitesNode->appendChild($childNode);  }
        }

    // Remove <data>.
        $dataNode->parentNode->removeChild($dataNode);
    }

// Test the result.
    echo $dom->saveXML();
?>

答案 1 :(得分:0)

我的解决方案,扩展测试用例:

// Changes the name of element $element to $newName.
function renameElement($element, $newName) {
  $newElement = $element->ownerDocument->createElement($newName);
  $parentElement = $element->parentNode;
  $parentElement->insertBefore($newElement, $element);

  $childNodes = $element->childNodes;
  while ($childNodes->length > 0) {
    $newElement->appendChild($childNodes->item(0));
  }

  $attributes = $element->attributes;
  while ($attributes->length > 0) {
    $attribute = $attributes->item(0);
    if (!is_null($attribute->namespaceURI)) {
      $newElement->setAttributeNS('http://www.w3.org/2000/xmlns/',
                                  'xmlns:'.$attribute->prefix,
                                  $attribute->namespaceURI);
    }
    $newElement->setAttributeNode($attribute);
  }

  $parentElement->removeChild($element);
}

function prettyPrint($d) {
  $d->formatOutput = true;
  echo '<pre>'.htmlspecialchars($d->saveXML()).'</pre>';
}

$d = new DOMDocument( '1.0' );
$d->loadXML('<?xml version="1.0"?>
<library>
  <data a:foo="1" x="bar" xmlns:a="http://example.com/a">
    <invite>
      <username>jmansa</username>
      <userid>1</userid>
    </invite>
    <update>1</update>
  </data>
</library>');

$xpath = new DOMXPath($d);
$elements = $xpath->query('/library/data');
if ($elements->length == 1) {
  $element = $elements->item(0);
  renameElement($element, 'invites');
}

prettyPrint($d);

顺便说一句,我将此解决方案作为comment添加到DOMElement的PHP文档中。