How to echo an PHP SimpleXMLElement - php

I am learning SimpleXML in PHP. Then I am doing simple test with SimpleXMLElement(...), I dont get anything back. Let me explain. Here is XML file:
<?xml version="1.0" encoding="UTF-8"?>
<movies>
<movie>
<title>PHP: Behind the Parser</title>
<plot>
So, this language. It's like, a programming language. Or is it a
scripting language? All is revealed in this thrilling horror spoof
of a documentary.
</plot>
<great-lines>
<line>PHP solves all my web problems</line>
</great-lines>
<rating type="thumbs">7</rating>
<rating type="stars">5</rating>
</movie>
</movies>
And here is my php file:
<?php
$xml = simplexml_load_file('example.xml');
echo $xml->getName() . "<br>"; // prints "movies"
$movies = new SimpleXMLElement($xml);
echo $movies->getName() . "...<br>"; // doesnt print anything, not event dots
echo $movies->movie[0]->plot; // even this does not print anything
?>
Only output is:
movies
Please read the comments in php file. I am trying to print xml elements in exact same way after loading file and after doing new simpleXML object. Some how it prints only first echo command results. I searched many examples and could not make it work. Where is the mistake? It is big puzzle for me, but maybe a tiny one for you.

simplexml_load_file already returns your SimpleXMLElement object. Try this:
<?php
$xml = simplexml_load_file('example.xml');
echo $xml->getName() . "<br>";
echo $xml->movie[0]->plot . "<br>\n";
?>

change this line:
$movies = new SimpleXMLElement($xml);
to this:
$movies = new SimpleXMLElement($xml->asXML());

What you are trying to do doesn't make much sense, because you are trying to load the same XML twice:
// this loads the XML from a file, giving you a SimpleXMLElement object:
$xml = simplexml_load_file('example.xml');
// this line would do what? load the XML from the XML?
$movies = new SimpleXMLElement($xml);
There are two functions for loading XML in the SimpleXML extension, both return SimpleXMLElement objects:
simplexml_load_file - takes a filename, and loads the XML in that file; with the right PHP settings, you can also give it a URL, and it will load the XML straight from there
simplexml_load_string - takes a string of XML that you've already got from somewhere else, and loads that
The third way of getting a SimpleXMLElement is calling the class's constructor (i.e. writing new SimpleXMLElement). This can actually act like either of the above: by default, it expects a string of XML (like simplexml_load_string), but you can also set the 3rd parameter to true to say that it's a path or URL (like simplexml_load_file).
The result of all three of these methods is exactly the same, they're just different ways of getting there depending on what you currently have (and, to some extent, how you want your code to look).
As a side-note, there are two more functions which do take an object of XML you've already parsed: simplexml_import_dom and dom_import_simplexml. These are actually pretty cool, because the DOM is a standard, comprehensive, but rather fiddly and verbose way of acting on XML, whereas SimpleXML is, well, simple - and using these functions you can actually use both with very little penalty, because they just change the wrapper of the object without having to re-parse the underlying XML.

try this
<?php
$movies = simplexml_load_file('sample.xml');
foreach($movies as $key=>$val)
{
echo $val->title.'<br>';
echo $val->plot.'<br>';
echo $val->rating[0];
echo $val->rating[1];
}
?>

Related

SimpleXML parent - child issue

i am having an issue with parsing an XML file using SimpleXML and PHP.
The XML file in question is provided by a third party and includes a number of child elements (going down multiple levels) within it. I know which elements i require and can see them within the XML file, but i just can't seem to get them to print using PHP.
Example XML feed for test.xml:
<?xml version="1.0" encoding="utf-8"?>
<Element1 xmlns="" release="8.1" environment="Production" lang="en-US">
<Element2>
<Element3>
<Element4>
<Element5>it worked</Element5>
</Element4>
</Element3>
</Element2>
</Element1>
The file only includes one of each attribute so i can be very particular with the request, the code i have so far is below:
$lib=simplexml_load_file("test.xml");
$make=$lib->Element1->Element2->Element3->Element4->Element5;
print $make;
I have tried to look this up before asking, but the only solutions i can see are when the child attributes are unknown or there are multiple results for each request, which is not the case in this instance.
Any help or guidance would be greatly received.
Thanks
In your code above, $lib is Element1. So you just need to drop one of your references. This:
$make=$lib->Element1->Element2->Element3->Element4->Element5;
Should become this:
$make=$lib->Element2->Element3->Element4->Element5;
Also, SimpleXML is an awful awful awful awful interface (considering that "Simple" is in the name and there is mass confusion about how to use it). I would always recommend DOMDocument instead.
I'd strongly recommend using xpath as it will give you more flexibility e.g. Allow you to restrict results based on xml node attributes.
$xml = simplexml_load_string('<?xml version="1.0" encoding="utf-8"?>
<Element1 xmlns="" release="8.1" environment="Production" lang="en-US">
<Element2>
<Element3>
<Element4>
<Element5>it worked</Element5>
</Element4>
</Element3>
</Element2>
</Element1>');
$data=$xml->xpath('/Element1/Element2/Element3/Element4/Element5');
echo (string)$data[0]; //outputs 'it worked'
//this also works
$data=$xml->xpath('//Element5');
echo (string)$data[0]; //outputs 'it worked'

Can't access XML node via xpath() (YT channel feed)

Very stumped by this one. In PHP, I'm fetching a YouTube user's vids feed and trying to access the nodes, like so:
$url = 'http://gdata.youtube.com/feeds/api/users/HCAFCOfficial/uploads';
$xml = simplexml_load_file($url);
So far, so fine. Really basic stuff. I can see the data comes back by running:
echo '<p>Found '.count($xml->xpath('*')).' nodes.</p>'; //41
echo '<textarea>';print_r($xml);echo '</textarea>';
Both print what I would expect, and the print_r replicates the XML structure.
However, I have no idea why this is returning zero:
echo '<p>Found '.count($xml->xpath('entry')).'"entry" nodes.</p>';
There blatantly are entry nodes in the XML. This is confirmed by running:
foreach($xml->xpath('*') as $node) echo '<p>['.$node->getName().']</p>';
...which duly outputs "[entry]" 25 times. So perhaps this is a bug in SimpleXML? This is part of a wider feed caching system and I'm not having any trouble with other, non-YT feeds, only YT ones.
[UPDATE]
This question shows that it works if you do
count($xml->entry)
But I'm curious as to why count($xml->xpath('entry')) doesn't also work...
[Update 2]
I can happily traverse YT's anternate feed format just fine:
http://gdata.youtube.com/feeds/base/users/{user id}/uploads?alt=rss&v=2
This is happening because the feed is an Atom document with a defined default namespace.
<feed xmlns="http://www.w3.org/2005/Atom" ...
Since a namespace is defined, you have to define it for your xpath call too. Doing something like this works:
$url = 'http://gdata.youtube.com/feeds/api/users/HCAFCOfficial/uploads';
$xml = simplexml_load_file($url);
$xml->registerXPathNamespace('ns', 'http://www.w3.org/2005/Atom');
$results = $xml->xpath('ns:entry');
echo count($results);
The main thing to know here is that SimpleXML respects any and all defined namespaces and you need to handle them accordingly, including the default namespace. You'll notice that the second feed you listed does not define a default namespace and so the xpath call works fine as is.

XML Namespaces with PHP's xmlwriter

Firstly can you tell me whether this xml:
<adf:source xsi:schemaLocation="http://www.rightmove.co.uk/adf/rightmoveV4n.xsd rightmoveV4n.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:adf="http://www.rightmove.co.uk/adf/rightmoveV4n.xsd">
</source>
Is correct? I can't see how the document starts with: <adf: source> and closes with </source>, doesn't seem right to me?
I have replicated the structure using my own data but cannot get PHP's XMLWriter() to close the document with just </source> - it closes it with </adf:source>.
I'm doing:
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument();
$xml->startElementNS("adf", "source", "http://www.rightmove.co.uk/adf/rightmoveV4n.xsd");
$xml->writeAttributeNS ("xsi", "schemaLocation", "http://www.w3.org/2001/XMLSchema-instance", "http://www.rightmove.co.uk/adf/rightmoveV4n.xsd rightmoveV4n.xsd");
and then eventually
$xml->endElement ();
echo $xml->outputMemory();
No, your XML is not well-formed. The root node of an XML document must be opened and closed with the same element. As far as an XML parser is concerned, <adf:source> and <source> are entirely different.
The adf: in front of the source element is a so-called namespace prefix, which is like a shorthand way of saying: "This element belongs to the namespace http://www.rightmove.co.uk/adf/rightmoveV4n.xsd".
So, the behaviour of XMLWriter() is to be expected and perfectly fine. On the other hand, an application that produces the XML document you have shown is clearly in error.

How can I load POST data into SimpleXML?

I need to post XML data from a textarea input to PHP so I can parse it and output a table.
I've tried a few methods and none seem to be working.
Currently I have this:
jQuery('#btnRegistrarXML').live('click', function(){
var xml;
if (jQuery('#txtRegXML').val() == ""){
AddMsg('You must paste XML from the excel export into the textarea.', 'error');
} else {
jQuery.post('registrar-xml-to-table.php', {xml:escape(jQuery('#txtRegXML').val())}, function(data){
jQuery('#regXMLasTable').empty();
jQuery('#regXMLasTable').append(data);
});
}
displayMsgs();
});
The PHP is:
$xmlraw = urldecode($_POST['xml']);
$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xmlraw);
$dom->formatOutput = TRUE;
$xmlstr = $dom->saveXml();
$xml = simplexml_load_string($xmlstr);
echo "<p>xmlraw:</p>";
echo $xmlraw;
echo "<p>xml:</p>";
echo $xml;
foreach ($xml->document as $doc) {
echo '<p class="alert alert-error">'.$doc->title.'</p>';
}
The first echo $xmlraw is working - it outputs the XML string all on one line - the post is sending the data through properly.
The second echo $xml doesn't output anything and the foreach doesn't output anything either - something is not working in the PHP
I've also tried loading $xmlraw directly into simplexml_load_string($xmlraw) but it doesn't work - I'm assuming because it's not well formed?
The XML I'm using to test is:
<?xml version="1.0"?>
<document>
<title>
Foobar
</title>
</document>
You can paste the XML into the textarea on this ( http://tsdexter.com/webservice-testing/programs-list.php ) page and then if you inspect element underneath xmlraw: you can see that the raw xml string was echoed - however, underneath xml: there is nothing and also the foreach doesn't output anything either.
Here's a jsFiddle so you can see the HTML/JS - it doesn't actually do anything though because it can't ajax to the PHP page - so I included the PHP version above to test. http://jsfiddle.net/tsdexter/EDqQB/
Any ideas?
A few questions, which may or may not constitute an answer, but needed more space than a comment.
Why are you running urldecode on the $_POST variable? PHP should be doing that for you, unless you are double-escaping it somewhere.
Why are you loading into DOM and then SimpleXML? I know you said you tried without, but they use the same XML parser underneath, so there is no way this will help you rather than introducing more confusion.
What does var_dump(simplexml_load_string($rawxml)) give you? My guess would be FALSE, meaning an error. In which case, check you have warnings turned on (error_reporting(E_ALL); ini_set('display_errors', '1');) and detailed XML error handling turned off (libxml_use_internal_errors(false);).
In case it does give you a SimpleXMLElement object, don't spend too long looking at the var_dump output. Try one of these debugging functions instead.

Using SimpleXML to create an XML object from scratch

Is it possible to use PHP's SimpleXML functions to create an XML object from scratch? Looking through the function list, there's ways to import an existing XML string into an object that you can then manipulate, but if I just want to generate an XML object programmatically from scratch, what's the best way to do that?
I figured out that you can use simplexml_load_string() and pass in the root string that you want, and then you've got an object you can manipulate by adding children... although this seems like kind of a hack, since I have to actually hardcode some XML into the string before it can be loaded.
I've done it using the DOMDocument functions, although it's a little confusing because I'm not sure what the DOM has to do with creating a pure XML document... so maybe it's just badly named :-)
Sure you can. Eg.
<?php
$newsXML = new SimpleXMLElement("<news></news>");
$newsXML->addAttribute('newsPagePrefix', 'value goes here');
$newsIntro = $newsXML->addChild('content');
$newsIntro->addAttribute('type', 'latest');
Header('Content-type: text/xml');
echo $newsXML->asXML();
?>
Output
<?xml version="1.0"?>
<news newsPagePrefix="value goes here">
<content type="latest"/>
</news>
Have fun.
In PHP5, you should use the Document Object Model class instead.
Example:
$domDoc = new DOMDocument;
$rootElt = $domDoc->createElement('root');
$rootNode = $domDoc->appendChild($rootElt);
$subElt = $domDoc->createElement('foo');
$attr = $domDoc->createAttribute('ah');
$attrVal = $domDoc->createTextNode('OK');
$attr->appendChild($attrVal);
$subElt->appendChild($attr);
$subNode = $rootNode->appendChild($subElt);
$textNode = $domDoc->createTextNode('Wow, it works!');
$subNode->appendChild($textNode);
echo htmlentities($domDoc->saveXML());
Please see my answer here. As dreamwerx.myopenid.com points out, it is possible to do this with SimpleXML, but the DOM extension would be the better and more flexible way. Additionally there is a third way: using XMLWriter. It's much more simple to use than the DOM and therefore it's my preferred way of writing XML documents from scratch.
$w=new XMLWriter();
$w->openMemory();
$w->startDocument('1.0','UTF-8');
$w->startElement("root");
$w->writeAttribute("ah", "OK");
$w->text('Wow, it works!');
$w->endElement();
echo htmlentities($w->outputMemory(true));
By the way: DOM stands for Document Object Model; this is the standardized API into XML documents.

Categories