|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2006-11-22 17:54 UTC] dave dot lane at gmx dot net
Description:
------------
The following code does not work. When the nodes in a NodeList that is the result of an XPath query are copied into an array and returned from a function. When the nodes in the array are used a warning results: "Couldn't fetch DOMElement. Node no longer exists..."
Reproduce code:
---------------
bug.php:
<?
$DOMMain =& OpenXMLDoc('main.xml');
$aArray =& GetArray($DOMMain);
echo 'After return: '.$aArray[0]->localName->localName."<br>\n";
function &OpenXMLDoc($sFileName) {
$DOM = new DOMDocument();
$DOM->preserveWhiteSpace = false;
$DOM->load($sFileName);
return $DOM;
}
function &ExecuteXPath($sXPath, DOMDocument &$DOMDocument, DOMNode &$DOMNode) {
$objXPath = new DOMXPath($DOMDocument);
return $objXPath->query($sXPath, $DOMNode);
}
function &GetArray(&$DOMMain) {
$DOMInclude =& OpenXMLDoc('include.xml');
$NodeImported = $DOMMain->importNode($DOMInclude->documentElement, true);
$NodeListImported =& ExecuteXPath('./include1', $DOMMain, $NodeImported);
$NodeListImported = $NodeListImported->item(0)->childNodes;
echo 'In NodeList: '.$NodeListImported->item(0)->localName."<br>\n";
$aArray = array();
foreach($NodeListImported as $Node) {
$aArray[] = $Node;
}
echo 'In Array: '.$aArray[0]->localName."<br>\n";
return $aArray;
}
?>
main.xml:
<?xml version = "1.0" encoding="ISO-8859-1"?>
<root>
</root>
include.xml:
<?xml version = "1.0" encoding="ISO-8859-1"?>
<include>
<include1>
<div>
<span>test</span>
</div>
</include1>
</include>
Expected result:
----------------
In NodeList: div
In Array: div
After return: div
Actual result:
--------------
In NodeList: div
In Array: div
Warning: Couldn't fetch DOMElement. Node no longer exists in /var/www/html/usr/dla/csc/V2/bug/bug.php on line 5
After return:
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 16:00:02 2025 UTC |
Can this be turned into an exception instead of a Warning (still a warning in PHP 7.1.0-x64)? So far, I rely on a patch that boils up the parentNode of the element, untill either reaching a DOMDocument (meaning node is still there) or a null (meaning node has already been removed). Could this be part of DOMElement's static methods, like a DOMElement::nodeExists(DOMElement $element) ? <?php $xml = '<?xml version="1.0" encoding="utf-8"?><block>I have <list><num>0A</num> orange and <list><num>0B</num></list> apple</list>.</block>'; $doc = new DOMDocument(); $doc->loadXml($xml); $xpath = new DOMXpath($doc); $nodes = $xpath->query('//num', $doc->documentElement); foreach ($nodes as $num) { if ($num->textContent{0} == '0') { // Node might be part of a removed DocumentFragment // If so, ignore it: node has already been removed by removing one of its ancestor for ($n = $num; !($n instanceof DOMDocument); $n = $n->parentNode) { if ($n === null) { // Node already removed (see PHP bug #39593) so skip it continue 2; } } // Will remove the first "list" ancestor of the "num" node $a = $xpath->query('ancestor::list[1]', $num); if ($a->length === 1) { $p = $a->item(0); // removed the "list" element $p->parentNode->removeChild($p); } } } var_dump($doc->C14N()); ?> Sample: I remove the 1st "list" ancestor element of every "num" element that starts with a "0". Since "list" are nested, the outer one is removed first when "foreaching" the 0A node. Then the OB node is foreached, and its list ancestor is removed. But that ancestor was already removed from document (because it's a descendant of a removed node). In real production system, I don't know what the XML is, and these nested case may occur (actually, it's not "list" be nested "table" element, and "table" ancestor is removed if a "td" contains a "0"; "table"s can be nested, so removals can be nested at Runtime)