I wrote a function for me to handle several insert modes (including insertAfter)
<?php
public function myInsertNode($newNode, $refNode, $insertMode=null) {
if(!$insertMode || $insertMode == "inside") {
$refNode->appendChild($newNode);
} else if($insertMode == "before") {
$refNode->parentNode->insertBefore($newNode, $refNode);
} else if($insertMode == "after") {
if($refNode->nextSibling) {
$refNode->parentNode->insertBefore($newNode, $refNode->nextSibling);
} else {
$refNode->parentNode->appendChild($newNode);
}
}
}
?>
DOMNode::insertBefore
(PHP 5)
DOMNode::insertBefore — Yeni çocuğu belirtilen çocuğun öncesine yerleştirir
Açıklama
yeni düğümü mevcut düğümün
hemen öncesine yerleştirir. Eklenen çocukta değişiklik yapmayı
düşünüyorsanız dönen düğümü kullanın.
Değiştirgeler
-
yeni -
Yeni çocuk düğüm.
-
mevcut -
Mevcut çocuk düğüm. Belirtilmediği takdirde
yenidüğüm listeye son çocuk olarak eklenir.
Dönen Değerler
Yerleştirilen düğüm.
Hatalar/İstisnalar
-
DOM_NO_MODIFICATION_ALLOWED_ERR -
Düğüm salt okunursa veya düğümün önceki ebeveyni salt okunur olarak yerleştirilmişse bu hata oluşur.
-
DOM_HIERARCHY_REQUEST_ERR -
Düğüm,
yenidüğümün türündeki çocuk düğümlere izin vermeyen türde ise veyayenidüğüm, çocuğu olacağı düğümün ebeveyni veya atalarından biri ise bu hata oluşur. -
DOM_WRONG_DOCUMENT_ERR -
Eğer
yenidüğüm, çocuğu olacağı düğümü oluşturan belgeden farklı bir belge tarafından oluşturulmuşsa bu hata oluşur. -
DOM_NOT_FOUND -
mevcutdüğüm, bir çocuk düğüm değilse bu hata oluşur.
A very usual needed function is "appendSibling" to insert a node just before another one :
<?php
/**
* @param DOMNode $newnode Node to insert next to $ref
* @param DOMNode $ref Reference node
* @requires $ref has a parent node
* @return DOMNode the real node inserted
*/
function appendSibling(DOMNode $newnode, DOMNode $ref)
{
if ($ref->nextSibling) {
// $ref has an immediate brother : insert newnode before this one
return $ref->parentNode->insertBefore($newnode, $ref->nextSibling);
} else {
// $ref has no brother next to him : insert newnode as last child of his parent
return $ref->parentNode->appendChild($newnode);
}
}
?>
Here's a usage example.
If you try this, you'll get an error message.
$refNode->insertBefore($newNode, $refNode);
Try this instead...
$refNode->parentNode->insertBefore($newNode, $refNode);
Sorry, my previous posting worked only for the top node. Here the corrected version, which will work for any node:
XML
----
<?xml version="1.0"?>
<contacts>
<person>Adam</person>
<person>Eva</person>
<person>Thomas</person>
</contacts>
PHP
---
<?php
// load XML, create XPath object
$xml = new DomDocument();
$xml->preserveWhitespace = false;
$xml->load('contacts.xml');
$xpath = new DOMXPath($xml);
// get node eva, which we will append to
$eva = $xpath->query('/contacts/person[.="Eva"]')->item(0);
// create node john
$john = $xml->createElement('person', 'John');
// insert john after eva
// "in eva's parent node (=contacts) insert
// john before eva's next node"
// this also works if eva would be the last node
$eva->parentNode->insertBefore($john, $eva->nextSibling);
// show result
header('Content-Type: text/plain');
print $xml->saveXML();
?>
Result
------
<?xml version="1.0"?>
<contacts>
<person>Adam</person>
<person>Eva</person><person>John</person>
<person>Thomas</person>
</contacts>
The previous example is incorrect, and causes a DOM_NOT_FOUND error, as the child nodes are not direct descendants of the root node.
Therefore, the line:
$parent_path = "/root";
needs to change to:
$parent_path = "/root/parent";
or
$parent_path = "//parent";
for this example to work
moving an existing node within the DomDocument:
<root>
<parent>
<child><name>Bob</name></child>
<child><name>Sue</name></child>
</parent>
</root>
$dom = new DomDocument();
$dom->load("sample.xml");
$parent_path = "/root";
$query = "//child[position() = 2]";
$query2 = "//child[position() = 1]";
$xpath = new DomXPath($dom);
$parent = $xpath->query($parent_path);
$under = $xpath->query($query);
$above = $xpath->query($query2);
$parent->item(0)->insertBefore($under->item(0), $above->item(0));
$dom->save("sample.xml");
Should produce:
<root>
<parent>
<child><name>Sue</name></child>
<child><name>Bob</name></child>
</parent>
</root>
example to insert <newnode/> between <chid1/> and <child2/>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<root>
<parent>
<child nr="1"/>
<child nr="2"/>
</parent>
</root>
<?php
$xml_src = 'test.xml';
// XPath-Querys
$parent_path = "//parent";
$next_path = "//parent/child[@nr='2']";
// Create a new DOM document
$dom = new DomDocument();
$dom->load($xml_src);
// Find the parent node
$xpath = new DomXPath($dom);
// Find parent node
$parent = $xpath->query($parent_path);
// new node will be inserted before this node
$next = $xpath->query($next_path);
// Create the new element
$element = $dom->createElement('newnode');
// Insert the new element
$parent->item(0)->insertBefore($element, $next->item(0));
echo $dom->saveXML();
?>
1st argument) a node to insert
2nd argument) a reference node - this is the node that the new node will be inserted before
The trick to using this method is that the OBJECT on which you actually CALL the insertBefore() method is actually the PARENT node of the reference node!
INCORRECT:
$DOMNode_refNode->insertBefore($DOMNode_newNode, $DOMNode_refNode);
CORRECT:
$DOMNode_refNode->parentNode->insertBefore($DOMNode_newNode, $DOMNode_refNode);
