1

DOMノードのrootのタグ名のみを変更するにはどうすればよいですか?

documentElementDOM-Documentモデルでは、オブジェクトのプロパティを変更できないDOMElementため、ノードを「再構築」する必要があります...しかし、childNodesプロパティを使用して「再構築」するにはどうすればよいでしょうか。


注:これは、saveXMLを使用して文字列に変換し、正規表現でルートを切断することで実行できます...ただし、これは回避策であり、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-domdocument-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'
4

5 に答える 5

3

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); 
于 2013-04-04T20:15:20.730 に答える
3

これはまだ実際には答えられていないので、見つからないというエラーは、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マニュアルのユーザーノートでは概説されていませんが、最初にrenameNode()関数を提案したブログ投稿へのリンクをたどると、このソリューションを提供するコメントをその下に見つけることができます。

とにかく、ここでの私のバリアントは、わずかに異なる変数の命名を使用しており、タイプについてより明確です。PHPマニュアルの例のように、名前空間ノードを処理するバリアントがありません。たとえば、それを処理する追加関数を作成したり、ノードから名前空間を引き継いで名前を変更したり、別の関数で名前空間を明示的に変更したりするなど、何が最善かはまだ予約されていません。

于 2013-05-01T08:32:27.250 に答える
1

これは私の「Try-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;
  }    

もちろん、DOMDocument :: renameNodeの使用方法を(エラーなしで!)示すと、賞金がもらえます!

于 2013-03-29T11:26:35.383 に答える
1

アプローチでISTMを使用すると、別のノードからノードをインポートしようとするため、次の方法を使用する必要があります。 DOMDocumentimportNode()

$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();
于 2013-04-04T20:02:51.623 に答える
0

私は何も見逃していないことを願っていますが、私はたまたま同様の問題を抱えていて、useを使用してそれを解決することができました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はるかに簡単な解決策のようです。そうでない場合は、上記の解決策を実行する必要があります。あなたの質問から、同じから作成される可能性があるようです。 $newRootDomDocumentimportNode$newRoot$doc

これがうまくいったかどうか教えてください。乾杯。

編集:バージョン20031129で、設定されている場合、最終的に呼び出したときに出力がDomDocument::$formatOutputフォーマットされないことに注意してください$newRoot$doc->saveXML()

于 2014-10-03T23:24:50.097 に答える