How to convert an XML string into a DOMDocument in PHP? - php

I got an example XML string from a customer, which I would like to transform to a DOMDocument. I can't seem to get the first node right though....
The string looks like this;
<ev:Events xmlns:ev="xsdEvents" xsi:schemaLocation="xsdEvents [url]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Node>
<OtherNode>value</OtherNode>
</Node>
</ev:Events>
How would I set this up the proper way via DOMDocument in PHP?

Well, loading a XML string to a DOMDocument object is not quite that hard -- you'll just have to use DOMDocument::loadXML().
For example, in your case, you'd use :
$string = <<<XML
<ev:Events xmlns:ev="xsdEvents" xsi:schemaLocation="xsdEvents [url]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Node>
<OtherNode>value</OtherNode>
</Node>
</ev:Events>
XML;
$dom = new DOMDocument();
$dom->loadXML($string);
Then, accessing your data is just a matter of using the relevant DOM methods.
For example, to extract the value of your <OtherNode> node, you could use :
$items = $dom->getElementsByTagName('OtherNode');
if ($items->length > 0) {
var_dump( $items->item(0)->nodeValue );
}

Related

append XML literal to DOMDocument in php without escaping

I have a string that represents nodes I'd like to append to a DOMDocument in PHP, but when I add it as a value to an element, it gets escaped. Is there a way to append a chunk of XML to a DOMDocument without it getting escaped - and with the one string addition, several nodes getting added?
Here's an example of what I'm trying to do:
$string = <<<XML
<myNode>
<OtherNode>value</OtherNode>
</myNode>
XML;
$domDoc = new DOMDocument();
$xml_id = $domDoc->createElement('mydata');
$value = $domDoc->createTextNode($string);
$xml_id->appendChild($value);
$subNode = $domDoc->appendChild($xml_id);
echo $domDoc->saveXML();
Currently, however the output looks like this:
<?xml version="1.0"?>
<mydata> <myNode>
<OtherNode>value</OtherNode>
</myNode></mydata>
Is there a way to make it look like this?
<?xml version="1.0"?>
<mydata>
<myNode>
<OtherNode>value</OtherNode>
</myNode>
</mydata>
if I'm not incorrect, you actually should create a documentFragment and append the XML literal to that. Then you should append the documentFragment to the $xml_id and then you should append $xml_id to the $domDoc
$domDoc = new DOMDocument();
$xml_id = $domDoc->createElement('mydata');
$frag = $domDoc->createDocumentFragment();
$frag->appendXML($string);
$xml_id->appendChild($frag);
$domDoc->appendChild($xml_id);

Get value from a CDATA in xml

I dont know how get a lat, lon in php values from this xml code:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Document>
<name>OpenCellID Cells</name>
<description>List of available cells</description>
<Placemark><name></name><description><![CDATA[lat: <b>3.378199</b><br/>lon: <b>-76.523528</b><br/>mcc: <b>732</b><br/>mnc: <b>123</b><br/>lac: <b>4003</b><br/>cellid: <b>26249364</b><br/>averageSignalStrength: <b>0</b><br/>samples: <b>10</b><br/>changeable: <b>1</b>]]></description><Point><coordinates>-76.523528,3.378199,0</coordinates></Point></Placemark>
</Document>
</kml>
I hope you can help me with this. Thanks
The trick is to read out the cdata as a string first, let libxml wrap it into welformatted html and then parse out the values from the nodes containing your data.
Note that this works but assumes that lon and lat are always in the first nodes in the cdata
// the xml as a variable
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Document>
<name>OpenCellID Cells</name>
<description>List of available cells</description>
<Placemark><name></name><description><![CDATA[lat: <b>3.378199</b><br/>lon: <b>-76.523528</b><br/>mcc: <b>732</b><br/>mnc: <b>123</b><br/>lac: <b>4003</b><br/>cellid: <b>26249364</b><br/>averageSignalStrength: <b>0</b><br/>samples: <b>10</b><br/>changeable: <b>1</b>]]></description><Point><coordinates>-76.523528,3.378199,0</coordinates></Point></Placemark>
</Document>
</kml>';
// read into dom
$domdoc = new DOMDocument();
$domdoc->loadXML($xml);
// the cdata as a string
$cdata = $docdom->getElementsByTagName('Placemark')->item(0)->getElementsByTagName('description')->item(0)->nodeValue;
// a dom object for the cdata
$htmldom = new DOMDocument();
// wrap in html and parse
$htmldom->loadHTML($cdata);
// get the <b> nodes
$bnodes = $htmldom->getElementsByTagName('b');
// your data :)
$lon = $bnodes->item(0)->nodeValue;
$lat = $bnodes->item(1)->nodeValue;
Last not least, this is to illustrate how loadXML and loadHTML differ and how to use that. As for googleeart kml, I am sure that is a more standard way to parse ...

Hide XML declaration in files generated using PHP

I was tesing with a simple example of how to display XML in browser using PHP and found this example which works good
<?php
$xml = new DOMDocument("1.0");
$root = $xml->createElement("data");
$xml->appendChild($root);
$id = $xml->createElement("id");
$idText = $xml->createTextNode('1');
$id->appendChild($idText);
$title = $xml->createElement("title");
$titleText = $xml->createTextNode('Valid');
$title->appendChild($titleText);
$book = $xml->createElement("book");
$book->appendChild($id);
$book->appendChild($title);
$root->appendChild($book);
$xml->formatOutput = true;
echo "<xmp>". $xml->saveXML() ."</xmp>";
$xml->save("mybooks.xml") or die("Error");
?>
It produces the following output:
<?xml version="1.0"?>
<data>
<book>
<id>1</id>
<title>Valid</title>
</book>
</data>
Now I have got two questions regarding how the output should look like.
The first line in the xml file '', should not be displayed, that is it should be hidden
How can I display the TextNode in the next line. In total I am exepecting an output in this fashion
<data>
<book>
<id>1</id>
<title>
Valid
</title>
</book>
</data>
Is that possible to get the desired output, if so how can I accomplish that.
Thanks
To skip the XML declaration you can use the result of saveXML on the root node:
$xml_content = $xml->saveXML($root);
file_put_contents("mybooks.xml", $xml_content) or die("cannot save XML");
Please note that saveXML(node) has a different output from saveXML().
First question:
here is my post where all usable threads with answers are listed: How do you exclude the XML prolog from output?
Second question:
I don't know of any PHP function that outputs text nodes like that.
You could:
read xml using DomDocument and save each node as string
iterate trough nodes
detect text nodes and add new lines to xml string manually
At the end you would have the same XML with text node values in new line:
<node>
some text data
</node>

How do I parse an individual entry from XML using PHP?

I am trying to parse an individual element from an XML string using PHP. The issue is that this individual element occurs before the entries start. The XML is below:
<?xml version="1.0" encoding="UTF-8"?>
<feed gd:kind="shopping#products" gd:etag=""lm_25heFT8yiumci9EH1kItJBpg/Sj5O9aXZ82PKpx3N2C3uQYMhNYE"" xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:s="http://www.google.com/shopping/api/schemas/2010">
<openSearch:totalResults>64</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>25</openSearch:itemsPerPage>
<entry >...</entry>
<entry >...</entry>
</feed>
I am trying to parse out the "64" in the opensearch:totalResults tag. How do I this and assign it to a variable in php? I tried:
$url = 'url of xml feed';
$xml = simplexml_load_file($url);
$entries =$xml->entry[0]->openSearch:totalResults;
// also tried $entries =$xml->openSearch:totalResults;
echo $entries;
but it's not working. Any advice?
You need to register namespace in order to access these nodes:
$xml = simplexml_load_file('file.xml');
$xml->registerXPathNamespace('os', 'http://a9.com/-/spec/opensearchrss/1.0/');
$nodes = $xml->xpath('os:totalResults');
$totalResults = (string)$nodes[0];
You can also use http://it1.php.net/manual/en/simplexmlelement.children.php (using the $ns parameter)
that is less resource intensive.

Insert an xml element from an xml doc to an other xml document

Let's say I have to xml documents:
<first_root>
<element1/>
<element2>
<embedded_element/>
</element2>
</first_root>
and
<foo>
<bar/>
</foo>
How can I put this second xml doc into the first one, using php and DomDocument or SimpleXML?
I want it to look like something like this:
<first_root>
<element1/>
<element2>
<foo>
<bar/>
</foo>
<embedded_element/>
</element2>
</first_root>
You can do it using DOMDocument:
<?php
$aDoc = DOMDocument::loadXML('<?xml version="1.0" encoding="UTF-8" ?>
<first_root>
<element1/>
<element2>
<embedded_element/>
</element2>
</first_root>');
$bDoc = DOMDocument::loadXML('<?xml version="1.0" encoding="UTF-8" ?>
<foo>
<bar/>
</foo>');
$aEmbeddedElement = $aDoc->getElementsByTagName('embedded_element')->item(0);
$bFoo = $bDoc->documentElement;
$aImportedFoo = $aDoc->importNode($bFoo,true);
$aEmbeddedElement->insertBefore($aImportedFoo);
echo $aDoc->saveXML();
?>
Here I imported the XML into DOMDocuments, then I picked up the first embedded_element occurrence and foo node. After you have to import deeply foo into the first document. Now you can insert foo before embedded_element.
Obviously this is only the happy case...
Documentation: DOM
With SimpleXML you can accomplish this by building a third document based on the first two because you can't append SimpleXMLElements into others. (Or maybe you can but there's something I didn't get)

Categories