PHP - Importing XML Node - php

I'm trying to import one node from one document to another. This throws an 'Wrong Document Error' error:
$xml = <<<XML
<root>
<child1>foo </child1>
<child2> bar</child2>
</root>
XML;
$doc = new DOMDocument;
$new = new DOMDocument;
$doc->loadXML($xml);
$xp = new DOMXPath($doc);
foreach($xp->query('/root/node()') as $element)
{
$new->appendChild($doc->importNode($element, true));
}
echo $new->saveXML();

You want to use $new->importNode... rather than $doc->importNode... as $new is the document you're trying to add the node to.

Related

XML create node before another PHP

I have a XML file and I'm trying to insert a new node between two others with PHP script.
XML file:
<playlistLog>
<hour>
<track>
<type>take</type>
<url>URL</url>
<title>1473869236.wav</title>
<mix>0</mix>
</track>
(...)
</hour>
</playlistLog>
PHP file:
$xmldoc = new DOMDocument();
$xmldoc->load('../logs/log14-09-2016.xml');
$elem = $xmldoc->getElementsByTagName("track");
$track = $xmldoc->createElement('track');
$type = $xmldoc->createElement('type', 'take');
$track->appendChild($type);
$url = $xmldoc->createElement('url', 'url');
$track->appendChild($url);
$title = $xmldoc->createElement('title', 'title');
$track->appendChild($title);
$mix = $xmldoc->createElement('mix', 'mix');
$track->appendChild($mix);
$xmldoc->documentElement->insertBefore($track,$elem[660]);
$xmldoc->save('../logs/log14-09-2016.xml');
I'm trying to insert the new node before "track" tag number 660 but when I try to open the php file it doesn't work at all.
Can anybody tell me what I am doing wrong?
SOLUTION:
After #ThW response I change a bit what he wrotes and finally the code is doing right:
$document = new DOMDocument();
$document->preserveWhiteSpace = FALSE;
$document->load('../logs/log14-09-2016.xml');
$xpath = new DOMXpath($document);
$previousTrack = $xpath->evaluate('/playlistLog/hour/track')->item(659);
$newTrack = $previousTrack->parentNode->insertBefore($document->createElement('track'),$previousTrack);
$newTrack
->appendChild($document->createElement('type'))
->appendChild($document->createTextNode('take'));
$document->formatOutput = TRUE;
echo $document->save('../logs/log14-09-2016.xml');
$elem[660] is the 661st element node with the tag name track. But its parent node is not the document element. Here is another hour ancestor between. The node you're providing to insertBefore() has a different parent then the node you're adding the new element to.
You can use the $parentNode property to make sure that you append to that node.
Additionally I suggest using Xpath to fetch the track node.
$xml = <<<'XML'
<playlistLog>
<hour>
<track>
<type>take</type>
<url>URL</url>
<title>1473869236.wav</title>
<mix>0</mix>
</track>
</hour>
</playlistLog>
XML;
$document = new DOMDocument();
$document->preserveWhiteSpace = FALSE;
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$previousTrack = $xpath->evaluate('/playlistLog/hour/track[1]')->item(0);
$newTrack = $previousTrack
->parentNode
->insertBefore(
$document->createElement('track'),
$previousTrack
);
$newTrack
->appendChild($document->createElement('type'))
->appendChild($document->createTextNode('take'));
$document->formatOutput = TRUE;
echo $document->saveXml();

editing xml data in php

I want this code to replace in the "platform" tag with something like "newData"
$xml = new DOMDocument();
$xml->load('myhappyfarmsave.xml');
$xpath = new DOMXPath($xml);
$elements = $xpath->query('/myhappyfarmsave/platform');
$domElement = $elements->item(0);
var_dump($domElement->textContent);
$domElement->textContent = "newData";
$xml->save('myhappyfarmsavenew.xml');
I don't know what's wrong with my code. thanks for your help
<?xml version="1.0" encoding="UTF-8"?>
<myhappyfarmsave version="3">
<platform>Bazaar</platform>
<timestamp>1356876534</timestamp>
<lastlogtime>1356823542</lastlogtime>
</myhappyfarmsave>
Well, $node->textContent is a readonly value, so you cannot modify it.
Try playing with $node->nodeValue instead:
$domElement = $elements->item(0);
$domElement->nodeValue = "newData";
$xml->save('myhappyfarmsavenew.xml');

Need to extract Sub-Tree of XML, before processing with XSLT Processor

I'm processing a XML with XSL with PHP to a HTML output. So far, so good. Here's my code.
<?php
$xslDoc = new DOMDocument();
$xslDoc->load("content.xsl");
$xmlDoc = new DOMDocument();
$xmlDoc->load("content.xml");
// some xpath/dom-query filtering to get
// subtree of loaded xml-file
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($xmlDoc);
?>
Like you can see, this is a simple XSLT Processor. The output works well. For example I have in the given XML three sibling nodes "node":
<root>
<node>
<subnode>..</subnode>
</node>
<node>
<subnode>..</subnode>
</node>
<node>
<subnode>..</subnode>
</node>
</root>
Now I want just pass the second node through the XML Processor.
How can I do this?
chris
According to http://www.php.net/manual/en/xsltprocessor.transformtodoc.php, the transformToDoc method takes any DOM node as its argument so you could access $xmlDoc->getElementsByTagName('node')->item(1) and pass that to transformToDoc and then use saveXML or saveHTML to get a string of XML or HTML, depending on what kind of result you are looking for.
I solved my task by my own - but thank you for your application.
Here is my code:
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->load("content.xml");
$xpath = new DOMXPath($xmlDoc);
$query = '//ContentData/Content[1]/Headline';
$nodeList = $xpath->query($query);
$newDom = new DOMDocument('1.0','UTF-8');
$root = $newDom->createElement('root');
$root = $newDom->appendChild($root);
foreach ($nodeList as $domElement){
$domNode = $newDom->importNode($domElement, true);
$root->appendChild($domNode);
}
$newDom->saveXML();
$xslDoc = new DOMDocument();
$xslDoc->load("content.xsl");
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($newDom);

Delete node from XML according to attribute

from this xml file i want to delete picture node according to attribute id.
i have written php code but it does not work.
<gallery>
<organizate>
<organization w="3" h="1" space="17"/>
<organization w="4" h="2" space="17"/>
<organization w="6" h="3" space="7"/>
</organizate>
<pictures>
<picture target="events/preview/10picture1.jpg" title="test1" movie="" text="test1" link="events_calender.php" id="38"/>
<picture target="events/preview/8picture7.jpg" title="test2" movie="" text="cxvxc" link="events_calender.php" id="39"/>
<picture target="events/preview/5picture10.jpg" title="test3" movie="" text="test3" link="events_calender.php" id="40"/>
</pictures>
</gallery>
PHP code
$doc = new DOMDocument();
$doc->formatOutput = TRUE;
$doc->preserveWhiteSpace = FALSE;
$xPath = new DOMXPath($doc);
$doc->load('../Event_gallery.xml');
$query = sprintf('//pictures[./picture[#id="%s"]]', 38);
foreach ($xPath->query($query) as $node) {
$node->parentNode->removeChild($node);
}
$doc->save('../Event_gallery.xml');
I think xpath is not working properly. control is not going in foreach
The problem is you are loading the document after you pass the document to DOMXPath.
Change
$xPath = new DOMXPath($doc);
$doc->load('../Event_gallery.xml');
to
$doc->load('../Event_gallery.xml');
$xPath = new DOMXPath($doc);
Then it should work.
To remove just the picture element with the given id instead of the whole parent, change the XPath to
//pictures/picture[#id="38"]

How do I remove a specific node using its attribute value in PHP XML Dom?

My question is best phrase as:
Remove a child with a specific attribute, in SimpleXML for PHP
except I'm not using simpleXML.
I'm new to XML for PHP so I may not be doing the best way
I have a xml created using the $dom->save($xml) for each individual user. (not placing all in one xml due to undisclosed reasons)
It gives me that xml declaration <?xml version="1.0"?> (no idea how to make it to others, but that's not the point, hopefully)
<?xml version="1.0"?>
<details>
<person>name</person>
<data1>some data</data1>
<data2>some data</data2>
<data3>some data</data3>
<category id="0">
<categoryName>Cat 1</categoryName>
<categorydata1>some data</categorydata1>
</category>
<category id="1">
<categoryName>Cat 2</categoryName>
<categorydata1>some data</categorydata1>
<categorydata2>some data</categorydata2>
<categorydata3>some data</categorydata3>
<categorydata4>some data</categorydata4>
</category>
</details>
And I want to remove a category that has a specific attribute named id with the DOM class in php when i run a function activated from using a remove button.
the following is the debug of the function im trying to get to work. Can i know what I'm doing wrong?
function CatRemove($myXML){
$xmlDoc = new DOMDocument();
$xmlDoc->load( $myXML );
$categoryArray = array();
$main = $xmlDoc->getElementsByTagName( "details" )->item(0);
$mainElement = $xmlDoc->getElementsByTagName( "details" );
foreach($mainElement as $details){
$currentCategory = $details->getElementsByTagName( "category" );
foreach($currentCategory as $category){
$categoryID = $category->getAttribute('id');
array_push($categoryArray, $categoryID);
if($categoryID == $_POST['categorytoremoveValue']) {
return $categoryArray;
}
}
}
$xmlDoc->save( $myXML );
}
Well the above prints me an array of [0]->0 all the time when i slot the return outside the if.
is there a better way? I've tried using getElementbyId as well but I've no idea how to work that.
I would prefer not to use an attribute though if that would make things easier.
Ok, let’s try this complete example of use:
function CatRemove($myXML, $id) {
$xmlDoc = new DOMDocument();
$xmlDoc->load($myXML);
$xpath = new DOMXpath($xmlDoc);
$nodeList = $xpath->query('//category[#id="'.(int)$id.'"]');
if ($nodeList->length) {
$node = $nodeList->item(0);
$node->parentNode->removeChild($node);
}
$xmlDoc->save($myXML);
}
// test data
$xml = <<<XML
<?xml version="1.0"?>
<details>
<person>name</person>
<data1>some data</data1>
<data2>some data</data2>
<data3>some data</data3>
<category id="0">
<categoryName>Cat 1</categoryName>
<categorydata1>some data</categorydata1>
</category>
<category id="1">
<categoryName>Cat 2</categoryName>
<categorydata1>some data</categorydata1>
<categorydata2>some data</categorydata2>
<categorydata3>some data</categorydata3>
<categorydata4>some data</categorydata4>
</category>
</details>
XML;
// write test data into file
file_put_contents('untitled.xml', $xml);
// remove category node with the id=1
CatRemove('untitled.xml', 1);
// dump file content
echo '<pre>', htmlspecialchars(file_get_contents('untitled.xml')), '</pre>';
So you want to remove the category node with a specific id?
$node = $xmlDoc->getElementById("12345");
if ($node) {
$node->parentNode->removeChild($node);
}
You could also use XPath to get the node, for example:
$xpath = new DOMXpath($xmlDoc);
$nodeList = $xpath->query('//category[#id="12345"]');
if ($nodeList->length) {
$node = $nodeList->item(0);
$node->parentNode->removeChild($node);
}
I haven’t tested it but it should work.
Can you try with this modified version:
function CatRemove($myXML, $id){
$doc = new DOMDocument();
$doc->loadXML($myXML);
$xpath = new DOMXpath($doc);
$nodeList = $xpath->query("//category[#id='$id']");
foreach ($nodeList as $element) {
$element->parentNode->removeChild($element);
}
echo htmlentities($doc->saveXML());
}
It's working for me. Just adapt it to your needs. It's not intended to use as-is, but just a proof of concept.
You also have to remove the xml declaration from the string.
the above funciton modified to remove an email from a mailing list
function CatRemove($myXML, $id) {
$xmlDoc = new DOMDocument();
$xmlDoc->load($myXML);
$xpath = new DOMXpath($xmlDoc);
$nodeList = $xpath->query('//subscriber[#email="'.$id.'"]');
if ($nodeList->length) {
$node = $nodeList->item(0);
$node->parentNode->removeChild($node);
}
$xmlDoc->save($myXML);
}
$xml = 'list.xml';
$to = $_POST['email'];//user already submitted they email using a form
CatRemove($xml,$to);

Categories