Retrieve XML element data with PHP - php

i'm trying to allow the user to retrieve a specific XML node and print the information. My XML data is as follows:
<people>
<person id="1">
<forename>Jim</forename>
<surname>Morrison</surname>
</person>
<person id="2">
<forename>James</forename>
<surname>Frank</surname>
</person>
</people>
I want to be able to search my XML document with a name or ID, for instance I want to be able to say, 'check that james exists, and if james does, print out his information, otherwise print out an error message'.
I've figured that I first need to include the file with:
$xml=simplexml_load_file("credentials.xml") or die("Error: Cannot create object");
From this point onwards i'm unsure how to proceed, i've looked at SimpleXML and XPATH but i'm unsure on how to use these to acheive this. Thanks if you can help

Let's xpath():
$xml = simplexml_load_string($x); // assume XML in $x
$result = $xml->xpath("/people/person[forename = 'James']")[0];
The above xpath-expression will select any <person> having 'James' as a <forename> and store it as an array in $result.
With the [0] at the end of line 2, we select only the first entry in that array and store it in $result. This requires PHP >= 5.4.
We could also write to get the same result:
$result = $xml->xpath("/people/person[forename = 'James']");
$result = $result[0];
If there were more than 1 James in the XML, we would only get the first.
To get all Jameses, do as in line 1 above.
Then, let's output the <person> selected by our xpath expression:
echo $result->forename . ' ' . $result->surname .' has id ' . $result['id'] . ".";
In case $result contains several Jameses, do:
foreach ($result as $person) {
echo $person->forename . ' ' . $person->surname .' has id ' . $person['id'] . "." . PHP_EOL;
}
see it working: https://eval.in/222195

You should use the manual.
simplexml_load_file returns a SimpleXMLElement object.
From here you can use the objects children method to get the children you want, which would also be more of that SimpleXMLElement objects. Let's say you first want the children called people, and then want person. When you got the person objects, you can get the value of the attribute by the method attributes to get the names and the values etc. Because SimpleXMLElement implements Traversable, you can use a foreach loop to loop through the lists/arrays you get in return.

Figured out how to mostly solve the problem with this:
$xml=simplexml_load_file("credentials.xml") or die("Error: Cannot create object");
foreach($xml->children() as $people){
if ($people->forename == "james" ){echo $people->forename;}
}
This may be inefficient so if anyone else has a better way please do specify :)

Related

How to read xml file from url with symfony [duplicate]

It looks like there are many problems with simpleXML in PHP. I'm running the latest version of php on Windows and I just can not get the basic examples of simpleXML to work as in the documentation.
My xml file is:
<?xml version="1.0" encoding="ISO-8859-1"?>
<programme>
<title>Billy Bushwaka</title>
<episodeNumber>2</episodeNumber>
<description>Billy Bushwaka entertains</description>
<url>play.swf</url>
</programme>
My PHP program is:
<?php
$xml = simplexml_load_file("local.xml");
$result = $xml->xpath("//programme");
echo "Title: " . $result . "</br>";
?>
All I get is the following:
Title: Array
How can I get "Title: Billy Bushwaka"?
There are no repeats of XML data so I do not want to use arrays.
SimpleXML 101
First of all, always name your PHP variables after the node they represent.
// the root node is <programme/>
$programme = simplexml_load_file("local.xml");
Access to children (nodes) as if they were object properties.
echo $programme->title;
If there are multiple children using the same name, you can specify their 0-based position
// first <title/> child
echo $programme->title[0];
// create or change the value of the second <title/> child
$programme->title[1] = 'Second title';
Access to attributes as if they were array keys
// <mynode attr="attribute value" />
echo $mynode['attr'];
XPath always returns an array.
Back to your case, the best way to access that <title /> node would be
$programme = simplexml_load_file("local.xml");
echo "Title: " . $programme->title;
First of all, simplexml xpath method always returns an array of matches. Even if there is only 1 match (or even 0, in which case result is an empty array). This is why you get "Array" in the output.
Secondly, if you want just the title, then you need to change your xpath query:
$result = $xml->xpath("//programme/title");
echo "Title: " . $result[0] . "</br>";
You should probably change the xpath to //programme/title and then echo $result[0] or leave the xpath as it is and echo $result[0]->title. Remember var_dump will always help you.
I think you want:
$result = $xml->xpath("/programme/title");
echo "Title: " . $result[0] . "</br>";
$xml = simplexml_load_file("local.xml");
echo $xml->programme->title;
......
echo $xml->programme->description;

simplexml_load_string is stripping data out of soap response

So i am hitting a soap service, when i get the data and parse it through simplexml_load_string in order to access the data as an object (or just basically access the data) simplexml_load_string seems to strip it out.
A Raw response from soap service looks like:
A result parsed through simplexml_load_string
using the following code:
$result = simplexml_load_string((string)$result->DisplayCategoriesResult->any);
i get a result of:
this looks correct but at a closer look you will notice its just id's and the names of the categories are left behing simplexml_load_string
how can i manage to get the proper result? if there is another way of getting the raw data into a "usable" form or object that solution is also welcome
The text content of XML nodes doesn't show up when using print_r or var_dump, etc. They aren't "traditional" PHP objects, so you can't use the standard debugging options.
To access the text content (whether embedded as CDATA or otherwise), you need to step down into the child elements, and then cast them to strings:
<?php
$xml = <<<XML
<randgo xmlns="">
<status>0</status>
<message>Success</message>
<categories>
<category id="53"><![CDATA[go eat]]></category>
<category id="54"><![CDATA[go do]]></category>
<category id="55"><![CDATA[go out]]></category>
</categories>
</randgo>
XML;
$sxml = simplexml_load_string($xml);
foreach ($sxml->categories->category as $category)
{
echo $category['id'] . ": " . (string) $category, PHP_EOL;
}
=
$ php simplexml_categories.php
53: go eat
54: go do
55: go out
See: https://eval.in/590975
(Sorry if there are any typos in the XML, I think I copied from the screenshot correctly...)
The category names are CDATA. Try something like this to read it.
$doc = new DOMDocument();
$doc->load((string)$result->DisplayCategoriesResult->any);
$categories = $doc->getElementsByTagName("categories");
foreach ($categories as $categorie) {
foreach($categorie->childNodes as $child) {
if ($child->nodeType == XML_CDATA_SECTION_NODE) {
echo $child->textContent . "<br/>";
}
}
}

How to iterate through an XML element node with dynamic children

I currently have the following XML structure:
<root>
<maininfo>
<node>
<tournament_id>3100423</tournament_id>
<games>
<a_0>
<id>23523636</id>
<type>
<choice_4>
<choice_id>345</choice_id>
<choice_4>
<choice_9>
<choice_id>345</choice_id>
<choice_9>
... etc
</type>
</a_0>
<a_1></a_1>
<a_2></a_2>
...etc
</games>
</info>
</node>
</root>
I can easily get the id of the first node element "a_0" by just doing:
maininfo[0]->a_3130432[0]->games[0]->a_1[0]->id;
My issue is:
How do I automatically iterate (with a foreach) through all a_0, a_1, a_2 and get the values of each of these node elements and all of their children like "345" in <choice_id>345</choice_id>?
The ending numbers of a_0, a_1 + the children of choice_4, choice_9, are dynamically created and there are no logic in the _[number] counting up with +1 for each next element.
As it has been outlined previously on Stackoverflow (for example in Read XML dynamic PHP) and as well generally in the PHP manual (for example in Basic SimpleXML usage), you can iterate over all child elements by using foreach.
For example to go over all a_* elements, it's just
foreach ($xml->maininfo->node->games[0] as $name => $a) {
echo $name, "\n";
}
Output:
a_0
a_1
a_2
You then want to iterate over these their ->type children again. This is possible in pure PHP by putting one foreach into a another:
foreach ($xml->maininfo->node->games[0] as $name => $a) {
echo $name, "\n";
if (!$a->type[0]) {
continue;
}
foreach ($a->type[0] as $name => $choice) {
echo ' +- ', $name, "\n";
}
}
This now outputs:
a_0
+- choice_4
+- choice_9
a_1
a_2
This starts to get a bit complicated. As you can imagine since XML is famous for it's tree structures, you're not the first one running into this problem. Therefore a query-language to get elements from an XML document has been invented: Xpath.
With Xpath you can access XML data as if it was a file-system. As I know that each a_* element is a child of games and each choice_* element a child of type, it's pretty straight forward:
/*/maininfo/node/games/*/type/*
^ ^ ^
| | choice_*
root |
a_*
In PHP Simplexml this looks like:
$choices = $xml->xpath('/*/maininfo/node/games/*/type/*');
foreach ($choices as $choice) {
echo $choice->getName(), ': ', $choice->choice_id, "\n";
}
Output:
choice_4: 345
choice_9: 345
As this example shows, the data is now retrieved with a single foreach.
If you as well need access to the <a_*> elements, you need to have multiple foreach's or your own iteration but that is even a more advanced topic which I'd say would extend over the limits of your question.
I hope this is helpful so far. See as well SimpleXMLElement::children() which also gives all children (like ->games[0] in the first example). All example codes are as well available as a working, interactive online-demo.
If I understand it well, you can do something like:
for($i = 0; $i < $max; ++$i){
$a = $parentNode->{'a_'.$i};
}
You can do this very easily using SimpleXML :
<?php
$xmlStr = "<?xml version='1.0' standalone='yes'?>
<root>
<maininfo>
<node>
<tournament_id>3100423</tournament_id>
<games>
<a_0>
<id>23523636</id>
<type>
<choice_4>
<choice_id>345</choice_id>
</choice_4>
<choice_9>
<choice_id>345</choice_id>
</choice_9>
</type>
</a_0>
<a_1></a_1>
<a_2></a_2>
</games>
</node>
</maininfo>
</root>";
$xmlRoot = new SimpleXMLElement($xmlStr);
$i = 0;
foreach($xmlRoot->maininfo[0]->node[0]->games[0] as $a_x)
{
echo $i++ . " - " . htmlentities($a_x->asXML()) . "<br/>";
}
?>
I have modified some parts of your XML string to make it syntactically correct. You can view the results at http://phpfiddle.org/main/code/56q-san

I'm confused about parsing XML in PHP

How can I parse XML data using PHP? I want to get the contents of just the element named
<profile xmlns="mysite.com">
<confirmationNumber>128686132</confirmationNumber>
<merchantRefNum>123456</merchantRefNum>
<customerEmail>test#test.com</customerEmail>
</profile>
I was trying to use this code
$sxe = new SimpleXMLElement($decodedMessage);
echo $sxe->getName() . "\n";
foreach ($sxe->children() as $child)
{
echo $child->getName() . "\n";
}
But I don't know how to select a specific element.
You don't need the traversal methods of SimpleXML. Just use simplexml_load_string() if you already have it in one:
$xml = simplexml_load_string($decodedMessage);
Then accessing the content is as simple as:
print $xml->customerEmail;
You can try the function simplexml_load_file(), and use the XML as object. Or convert to array with cast.
You should look at xpath.
One of the easiest ways to deal with it is look for a function on google called xml2array, since associative arrays are much easier to deal with in PHP than XML.
you can try this.
$xml = simplexml_load_file($filePath) or die ("Unable to load XML file!");
//Access XML Data
echo "confirmation Number: " . $xml->confirmationNumber;
echo "merchant Ref Num: " . $xml->confirmationNumber;
echo "customer Email: " . $xml->customerEmail;
If you want to find that one element within a larger document, you could use XPath.
For example, for the XML
<some>
<hierarchy>
<profile>
<etc>et cetera</etc>
</profile>
</hierarchy>
</some>
you can simply do $sxe->xpath('//profile'), which will return an array of all the profile elements everywhere in the document (as SXEs, which you can then process). If there is only one profile element, then you're done, but if there are many you will need a more specific XPath.

Basic simpleXML working example?

It looks like there are many problems with simpleXML in PHP. I'm running the latest version of php on Windows and I just can not get the basic examples of simpleXML to work as in the documentation.
My xml file is:
<?xml version="1.0" encoding="ISO-8859-1"?>
<programme>
<title>Billy Bushwaka</title>
<episodeNumber>2</episodeNumber>
<description>Billy Bushwaka entertains</description>
<url>play.swf</url>
</programme>
My PHP program is:
<?php
$xml = simplexml_load_file("local.xml");
$result = $xml->xpath("//programme");
echo "Title: " . $result . "</br>";
?>
All I get is the following:
Title: Array
How can I get "Title: Billy Bushwaka"?
There are no repeats of XML data so I do not want to use arrays.
SimpleXML 101
First of all, always name your PHP variables after the node they represent.
// the root node is <programme/>
$programme = simplexml_load_file("local.xml");
Access to children (nodes) as if they were object properties.
echo $programme->title;
If there are multiple children using the same name, you can specify their 0-based position
// first <title/> child
echo $programme->title[0];
// create or change the value of the second <title/> child
$programme->title[1] = 'Second title';
Access to attributes as if they were array keys
// <mynode attr="attribute value" />
echo $mynode['attr'];
XPath always returns an array.
Back to your case, the best way to access that <title /> node would be
$programme = simplexml_load_file("local.xml");
echo "Title: " . $programme->title;
First of all, simplexml xpath method always returns an array of matches. Even if there is only 1 match (or even 0, in which case result is an empty array). This is why you get "Array" in the output.
Secondly, if you want just the title, then you need to change your xpath query:
$result = $xml->xpath("//programme/title");
echo "Title: " . $result[0] . "</br>";
You should probably change the xpath to //programme/title and then echo $result[0] or leave the xpath as it is and echo $result[0]->title. Remember var_dump will always help you.
I think you want:
$result = $xml->xpath("/programme/title");
echo "Title: " . $result[0] . "</br>";
$xml = simplexml_load_file("local.xml");
echo $xml->programme->title;
......
echo $xml->programme->description;

Categories