Reputation: 124
Is it possible to use xpath/xquery to query for a specific xml node, and then import/add a child node to it?
Example (code taken from http://codepad.org/gJ1Y2LjM , that was presented in similar question, but not the same):
1. I want to add an array
$book = array('isbn'=>123456789099, 'title' => 'Harry Potter 3', 'author' => 'J K. Rowling', 'edition' => '2007');
2. To an existing XML.
$doc = new DOMDocument();
$doc->loadXML('<?xml version="1.0"?>
<books>
<book>
<isbn>123456789098</isbn>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<edition>2005</edition>
</book>
<book>
<placeItHere></placeItHere>
<isbn>1</isbn>
<title>stuffs</title>
<author>DA</author>
<edition>2014</edition>
</book>
</books>');
3. To do that it is used the following fragment.
$fragment = $doc->createDocumentFragment();
$fragment->appendXML(" <book>
<isbn>{$book['isbn']}</isbn>
<title>{$book['title']}</title>
<author>{$book['author']}</author>
<edition>{$book['edition']}</edition>
</book>
");
4. But instead of appending it to the root node, has almost every example i found on internet:
$doc->documentElement->appendChild($fragment);
5. I want to append it (p.ex) to the node found in /books/book/placeItHere and not using getElementbyId or tagName, but a xpath/xquery. I tryed
$xp = new domxpath($doc);
$parent = $xp->query("books/book/placeItHere");
to reach the node, but never managed to use it as the parent.
Question: How to use that location to appendChild $fragment? Is it possible?
**YOUR BEAUTIFUL MAGIC**
In the end I will just save it.
echo $doc->saveXML();
Thank you for any help you can give to me.
Upvotes: 2
Views: 671
Reputation: 26375
A couple problems:
/books/book/placeItHere
(with the leading /
).DOMXPath::query()
returns a DOMNodeList rather than a DOMNode, so you'll need to grab your item()
from it.I rarely recommend using document fragments as playing fast and loose with raw XML regularly leads to problems. For example if your book title included an ampersand appendXML()
would crap out with a parser error.
Instead I suggest createElement()
and createTextNode()
, which will handle transforming things like &
into &
automatically.
$xml = <<<'XML'
<?xml version="1.0"?>
<books>
<book>
<isbn>123456789098</isbn>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<edition>2005</edition>
</book>
<book>
<placeItHere></placeItHere>
<isbn>1</isbn>
<title>stuffs</title>
<author>DA</author>
<edition>2014</edition>
</book>
</books>
XML;
$book = [
'isbn' => 123456789099,
'title' => 'Harry Potter 3',
'author' => 'J K. Rowling',
'edition' => '2007'
];
$dom = new DOMDocument();
$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$placeItHere = $xpath->query('/books/book/placeItHere')->item(0);
$newBook = $placeItHere->appendChild($dom->createElement('book'));
foreach ($book as $part => $value) {
$element = $newBook->appendChild($dom->createElement($part));
$element->appendChild($dom->createTextNode($value));
}
echo $dom->saveXML();
<?xml version="1.0"?>
<books>
<book>
<isbn>123456789098</isbn>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<edition>2005</edition>
</book>
<book>
<placeItHere>
<book>
<isbn>123456789099</isbn>
<title>Harry Potter 3</title>
<author>J K. Rowling</author>
<edition>2007</edition>
</book>
</placeItHere>
<isbn>1</isbn>
<title>stuffs</title>
<author>DA</author>
<edition>2014</edition>
</book>
</books>
Upvotes: 1