php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #31089 incomplete deep copy with importNode()
Submitted: 2004-12-14 14:38 UTC Modified: 2004-12-14 15:36 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: jon at mysql dot com Assigned:
Status: Wont fix Package: DOM XML related
PHP Version: 5.0.2 OS: Windows2000
Private report: No CVE-ID: None
 [2004-12-14 14:38 UTC] jon at mysql dot com
Description:
------------
When importing a DOM node from one document into another using DOMDocument->importNode(), the optional second argument with a value of TRUE should produce a deep copy of the imported node; that is, all child nodes of the imported node should be duplicated. (Similar to the effects of using the optional second argument with cloneNode().) Instead, only the first child of the imported node is included with the copy.

Notes: 

1. This problem is related to the new DOM extension, and not to the old DOMXML extension.

2. The same problem occurs regardless how the DOMDocument is instantiated: using LoadHTML(), LoadXML(), LoadHTMLFile(), or LoadXMLFile() to do so all produce the same (incorrect) result.

3. Per http://www.w3.org/TR/DOM-Level-2-Core/core.html#Core-Document-importNode -- "... deep of type boolean ... If true, recursively import the subtree under the specified node..."; the specific problem here is that the copy is not done recursively.

Reproduce code:
---------------
<?php
  $old_doc = DOMDocument::LoadXML("<html><head><title>OLD DOCUMENT</title></head><body><p>First paragraph.</p><p>Second paragraph.</p></body></html>");

  $new_doc = DOMDocument::LoadXML("<html><head><title>NEW DOCUMENT</title></head><body></body></html>");

  $old_body = $old_doc->getElementsByTagName("body")->item(0);
  $new_body = $new_doc->getElementsByTagName("body")->item(0);

  $div = $new_doc->createElement("div");
  $div->setAttribute("class", "page");

  $new_content = $new_doc->importNode($old_body, TRUE);

  foreach($new_content->childNodes as $child)
    $div->appendChild($child);

  $new_body->appendChild($div);
  print "<pre>" . htmlentities( $new_doc->saveXML() ) . "</pre>";
?>

Expected result:
----------------
<?xml version="1.0"?>
<html><head><title>NEW DOCUMENT</title></head><body><div class="page"><p>First paragraph.</p><p>Second paragraph.</p></div></body></html>

Actual result:
--------------
<?xml version="1.0"?>
<html><head><title>NEW DOCUMENT</title></head><body><div class="page"><p>First paragraph.</p></div></body></html>

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-12-14 15:36 UTC] rrichards@php.net
deep copy works fine, its the modifications to the DOMNodeList causing the problem.

You will need to do something like:
while ($child = $new_content->childNodes->item(0)) {
    $div->appendChild($child);
}

The DOMNodeList returns live (modifyable data), unlike the old 4.x extension which would return a static array of nodes. This means that nodes can be added, removed, etc.. from the list using other objects outside of the DOMNodeList (such as the appendChild method). foreach should not be used when adding/appending/removing any of the top level nodes in the nodelist.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 12:01:31 2024 UTC