如何改变用的DomDocument方法节点的根源在哪里?(How to change root of

2019-07-23 14:31发布

如何只改变一个DOM节点的根标记的名称?

在DOM的文档模型中,我们无法更改的属性documentElement一个的DOMElement对象,所以,我们需要“重建”的节点......但如何“重建”用childNodes属性?


注:我可以做到这一点转换为字符串saveXML和正则表达式cuting根 ...但它是一种解决方法,而不是一个DOM的解决方案。


试过,但没有作品,PHP实例

PHP例子(没有作品,但为什么呢?):

尝试-1

 // DOMElement::documentElement can not be changed, so... 

 function DomElement_renameRoot1($ele,$ROOTAG='newRoot') { 
    if (gettype($ele)=='object' && $ele->nodeType==XML_ELEMENT_NODE) {
   $doc = new DOMDocument();
   $eaux = $doc->createElement($ROOTAG); // DOMElement

       foreach ($ele->childNodes as $node)  
       if ($node->nodeType == 1)  // DOMElement 
               $eaux->appendChild($node);  // error!
       elseif ($node->nodeType == 3)  // DOMText
               $eaux->appendChild($node); // error!
       return $eaux;
    } else
        die("ERROR: invalid DOM object as input");
  }

appendChild($node)导致错误:

 Fatal error: Uncaught exception 'DOMException' 
 with message 'Wrong Document Error'

尝试-2

从@can建议(只指向链接),我可怜的解释DOM-DOM文档-renamenode手册 。

 function DomElement_renameRoot2($ele,$ROOTAG='newRoot') {
$ele->ownerDocument->renameNode($ele,null,"h1");
    return $ele;
 }

所述renameNode()方法导致了错误,

Warning: DOMDocument::renameNode(): Not yet implemented

尝试-3

从PHP手册中,评论1 。

 function renameNode(DOMElement $node, $newName)
 {
     $newNode = $node->ownerDocument->createElement($newName);
     foreach ($node->attributes as $attribute)
        $newNode->setAttribute($attribute->nodeName, $attribute->nodeValue);
     while ($node->firstChild)
        $newNode->appendChild($node->firstChild); // changes firstChild to next!?
     $node->ownerDocument->replaceChild($newNode, $node); // changes $node?
     // not need return $newNode; 
 }

所述的replaceChild()方法导致了错误,

Fatal error: Uncaught exception 'DOMException' with message 'Not Found Error'

Answer 1:

由于这还没有被真正回答的是,你得到一个关于没有找到错误信息是因为一个小错误的renameNode()您复制功能。

在有关在DOM重命名不同的元素一个有点相关的问题我已经看到了这个问题,以及和使用的收养我的回答是功能不具有这样的错误:

/**
 * Renames a node in a DOM Document.
 *
 * @param DOMElement $node
 * @param string     $name
 *
 * @return DOMNode
 */
function dom_rename_element(DOMElement $node, $name) {
    $renamed = $node->ownerDocument->createElement($name);

    foreach ($node->attributes as $attribute) {
        $renamed->setAttribute($attribute->nodeName, $attribute->nodeValue);
    }

    while ($node->firstChild) {
        $renamed->appendChild($node->firstChild);
    }

    return $node->parentNode->replaceChild($renamed, $node);
}

你可能会在函数体的最后一行都看上了它:这是使用->parentNode代替->ownerDocument 。 作为$node不是文档的一个孩子,是你得到的错误。 而且这也是一个错误的假设,它应该是。 而是使用父元素来搜索孩子在那里来取代它;)

这不是在PHP手册usernotes列出了到目前为止,但是,如果你没有按照链接到博客,帖子最初建议的renameNode()你可以在下面找到它提供这种解决方案,以及评论功能。

无论如何,我的变种这里使用一个稍微不同的变量命名,更鲜明关于类型。 就像在PHP手册的例子也错过与命名空间节点交易的变种。 我没有预订什么是最好的,例如创建一个额外的功能和它打交道,接管命名空间从节点重命名或在不同的功能明确改变的命名空间。



Answer 2:

首先,你需要了解的是, DOMDocument仅是文档树的层次根源。 它的名字总是#document 。 要重命名的根元素,它是$document->documentElement

如果要复制节点形成一个文档到另一个文档,你需要使用importNode()函数: $document->importNode($nodeInAnotherDocument)

编辑:

renameNode()还没有实现,所以你应该让另一根,并简单地用旧替换它。 如果你使用DOMDocument->createElement()你不需要使用importNode()以后就可以了。

$oldRoot = $doc->documentElement;
$newRoot = $doc->createElement('new-root');

foreach ($oldRoot->attributes as $attr) {
  $newRoot->setAttribute($attr->nodeName, $attr->nodeValue);
}

while ($oldRoot->firstChild) {
  $newRoot->appendChild($oldRoot->firstChild);
}

$doc->replaceChild($newRoot, $oldRoot); 


Answer 3:

这是我的“尝试-3”(见问题)的变化,并能正常工作

  function xml_renameNode(DOMElement $node, $newName, $cpAttr=true) {
      $newNode = $node->ownerDocument->createElement($newName);
      if ($cpAttr && is_array($cpAttr)) {
        foreach ($cpAttr as $k=>$v)
             $newNode->setAttribute($k, $v);
      } elseif ($cpAttr)
        foreach ($node->attributes as $attribute)
             $newNode->setAttribute($attribute->nodeName, $attribute->nodeValue);

      while ($node->firstChild)
          $newNode->appendChild($node->firstChild);
      return $newNode;
  }    

当然,如果您展示如何使用DOM文档:: renameNode (没有错误!), 赏金去为您服务!



Answer 4:

ISTM在你的方法,你尝试从另一个 节点导入 DOMDocument ,所以你需要使用importNode()方法:

$d = new DOMDocument();

/* Make a `foo` element the root element of $d */
$root = $d->createElement("foo");
$d->appendChild($root);

/* Append a `bar` element as the child element of the root of $d */
$child = $d->createElement("bar");
$root->appendChild($child);

/* New document */
$d2 = new DOMDocument();

/* Make a `baz` element the root element of $d2 */
$root2 = $d2->createElement("baz");
$d2->appendChild($root2);

/* 
 * Import a clone of $child (from $d) into $d2,
 * with its child nodes imported recursively
 */
$child2 = $d2->importNode($child, true);

/* Add the clone as the child node of the root of $d2 */
$root2->appendChild($child2);

但是,它要容易得多子节点附加到新的父元素(从而使它们),并更换旧的根与父元素:

$d = new DOMDocument();

/* Make a `foo` element the root element of $d */
$root = $d->createElement("foo");
$d->appendChild($root);

/* Append a `bar` element as the child element of the root of $d */
$child = $d->createElement("bar");
$root->appendChild($child);

/* <?xml version="1.0"?>
   <foo><bar/></foo> */
echo $d->saveXML();

$root2 = $d->createElement("baz");

/* Make the `bar` element the child element of `baz` */
$root2->appendChild($child);

/* Replace `foo` with `baz` */
$d->replaceChild($root2, $root);

/* <?xml version="1.0"?>
   <baz><bar/></baz> */
echo $d->saveXML();


Answer 5:

我希望我不缺什么,但我碰巧有类似的问题,并能够通过使用来解决它DomDocument::replaceChild(...)

   /* @var $doc DOMDocument */
   $doc = DOMImplementation::createDocument(NULL, 'oldRoot');

   /* @var $newRoot DomElement */
   $newRoot = $doc->createElement('newRoot');
   /* all the code to create the elements under $newRoot */

   $doc->replaceChild($newRoot, $doc->documentElement);

   $doc->documentElement->isSameNode($newRoot) === true;

什么扔我最初是$doc->documentElement是只读的,但上面的工作,似乎是IF的更简单的解决$newRoot用同样创建DomDocument ,否则你需要做的importNode解决方案如上所述。 从你的问题是似乎是$newRoot可以从同一创建$doc

让我们知道,如果这个摸索出适合你。 干杯。

编辑:在20031129版本注意到DomDocument::$formatOutput ,如果设置,不格式化$newRoot当你终于打电话输出$doc->saveXML()



文章来源: How to change root of a node with DomDocument methods?