Parsing XML API data result from Plesk - php

I try to get domain name from Plesk API result XML data as below:
<packet version="1.6.7.0">
<site-alias>
<get>
<result>
<status>ok</status>
<info>
<name>example.com</name>
</info>
</result>
<result>
<status>ok</status>
<info>
<name>domain.net</name>
</info>
</result>
</get>
</site-alias>
</packet>
using
$xml= simplexml_load_string($response);
echo $xml['site-alias']['get']['result'][0]['name'];
if there is more better way to do so, please advice, thanks.

There are multiple ways to get the values using SimpleXMLElement.
To get only 1 value, you could for example do it like this:
// Get 1 using SimpleXMLElement
echo $xml->{"site-alias"}->get->result->info->name;
// Get 1 using xpath
echo $xml->xpath('/packet/site-alias/get/result[1]/info/name')[0];
To get multiple values you could do it like this:
// Get multiple using SimpleXMLElement
$items = $xml->{"site-alias"}->get->result;
foreach ($items as $item) {
echo $item->info->name . "<br>";
}
// Get multiple using xpath
$items = $xml->xpath('/packet/site-alias/get/result/info/name');
foreach ($items as $item) {
echo $item . "<br>";
}
The SimpleXMLElement has a method __toString so you can echo the string content.
The xpath method returns an array, so you can get the first value using index 0.
A short way to get your value could be:
echo $xml->xpath('//name')[0];
Demo

Related

PHP Converting from XML to JSON with a SimpleXML object. Array with <items> tag causing issues

We are using SimpleXML to try and convert XML to JSON, and in turn convert to a PHP object, so that we can compare out Soap API with our Rest API. We have a request that returns quite a lot of data, but the part in question is where we have a nested array.
The array is returned with the tag in XML, however we do not want this translated into the JSON.
The XML that we get is as follows:
<apns>
<item>
<apn>apn</apn>
</item>
</apns>
So when it is translated into JSON it looks like this:
{"apns":{"item":{"apn":"apn"}}
In reality, we want SimpleXML to convert to the same JSON as in our Rest API, which looks like the following:
{"apns":[{"apn":"apn"}]}
The array could contain more than one thing, for example:
<apns>
<item>
<apn>apn</apn>
</item>
<item>
<apn>apn2</apn>
</item>
</apns>
Which I'm assuming will just error in JSON or have the first one overwritten.
I'd expect SimpleXML to be able to handle this natively, but if not has anyone got a fix that doesn't involve janky string manipulation?
TIA :)
A generic conversion has no possibility to know that a single element should be an array in JSON.
SimpleXMLElement properties can be treated as an Iterable to traverse sibling with the same name. They can be treated as an list or a single value.
This allows you to build up your own array/object structure and serialize it to JSON.
$xml = <<<'XML'
<apns>
<item>
<apn>apn1</apn>
</item>
<item>
<apn>apn2</apn>
</item>
</apns>
XML;
$apns = new SimpleXMLElement($xml);
$json = [
'apns' => []
];
foreach ($apns->item as $item) {
$json['apns'][] = ['apn' => (string)$item->apn];
}
echo json_encode($json, JSON_PRETTY_PRINT);
This still allows you to read/convert parts in a general way. Take a more in deep look at the SimpleXMLElement class. Here are method to iterate over all children or to get the name of the current node.
I hope this code is useful as a template to what your after, the problem is that it's difficult to know if this is the only instance of what your trying to do...
What this does is first looks for any nodes which have a item/apn structure underneath using XPath (//*[item/apn] says any node //* with the following nodes underneath).
Then it loops through these items and adds new <apn> nodes underneath the start node (the <apns> node in this case) from each <item> with the value ($list->addChild("apn", (string)$item->apn);.
Once the nodes are copied it removes all of the <item> nodes (unset($list->item);).
$input = '<apns>
<item>
<apn>apn</apn>
</item>
<item>
<apn>apn2</apn>
</item>
</apns>';
$xml = simplexml_load_string($input);
$itemList = $xml->xpath("//*[item/apn]");
foreach ( $itemList as $list ) {
foreach ( $list->item as $item ) {
$list->addChild("apn", (string)$item->apn);
}
unset($list->item);
}
echo $xml->asXML();
gives...
<?xml version="1.0"?>
<apns>
<apn>apn</apn><apn>apn2</apn></apns>
and
echo json_encode($xml);
gives...
{"apn":["apn","apn2"]}
If you just want the last value, then you can just keep track of the last value and set the new element outside the inner loop...
$itemList = $xml->xpath("//*[item/apn]");
foreach ( $itemList as $list ) {
foreach ( $list->item as $item ) {
$apn = (string)$item->apn;
}
$list->addChild("apn", $apn);
unset($list->item);
}

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/>";
}
}
}

xml xpath does not return node value

I have a test file where I'm trying to parse an xml string using SimpleXML's xpath method.
When I try to access a nodes values directly using xpath I get empty output, but when I use xpath to grab the elements and then loop through them it works fine.
When I look at the documentation, it seems like my syntax should work. Is there something I'm missing?
<?php
$xmlstring = '<?xml version="1.0" encoding="iso-8859-1"?>
<users>
<user>
<firstname>Sheila</firstname>
<surname>Green</surname>
<address>2 Good St</address>
<city>Campbelltown</city>
<country>Australia</country>
<contact>
<phone type="mobile">1234 1234</phone>
<url>http://example.com</url>
<email>pamela#example.com</email>
</contact>
</user>
<user>
<firstname>Bruce</firstname>
<surname>Smith</surname>
<address>1 Yakka St</address>
<city>Meekatharra</city>
<country>Australia</country>
<contact>
<phone type="landline">4444 4444</phone>
<url>http://yakka.example.com</url>
<email>bruce#yakka.example.com</email>
</contact>
</user>
</users>';
// Start parsing
if(!$xml = simplexml_load_string($xmlstring)){
echo "Error loading string ";
} else {
echo "<pre>";
// Print all firstname values directly from xpath
// This outputs the elements, but the values are blank
print_r($xml->xpath("/users/user/firstname"));
// Set a variable with all of the user elements and then loop through and print firstname values
// This DOES output the values
$users = $xml->xpath("/users/user");
foreach($users as $user){
echo $user->firstname;
}
// Find all firstname values by tag
// This does not output the values
print_r($xml->xpath("//firstname"));
echo "</pre>";
}
As per the manual http://uk1.php.net/manual/en/simplexmlelement.xpath.php
The xpath method searches the SimpleXML node for children matching the XPath path.
In your first and third examples, you are being returned objects containing an array of the node's value, rather than the node itself. So you aren't going to be able to do e.g.
$results = $xml->xpath("//firstname");
foreach ($results as $result) {
echo $result->firstname;
}
Instead you can just echo out the value directly. Well, almost directly (they are still simplexml objects after all)...
$results = $xml->xpath("//firstname");
foreach ($results as $result) {
echo $result->__toString();
}

Correctly outputting JSON with php?

New to working with JSON. I have the following XML results. I'd like to offer the same results but in JSON format when requested. My data is coming from a mySQL array.
My problem comes in when I try to have multiple nodes of the same name. Take my XML result for instance:
<results>
<result>
<item_id>1</item_id>
</result>
<result>
<item_id>50</item_id>
</result>
<result>
<item_id>50433</item_id>
</result>
<result>
<item_id>3</item_id>
</result>
</results>
If I simply do something like the following in PHP, my data keeps overwriting eachother.
foreach($result as $key => $value) {
$json["results"]["result"]["item_id"] = $value;
}
It gives me only one line of result which is the last item_id of 3.
What am I overlooking?
You're overwriting your value in your loop because you're not putting it into an array.
$json["results"]["result"]["item_id"] = $value;
should be
$json["results"]["result"]["item_id"][] = $value;

SimpleXMLElement and getting attribute value?

I am having trouble getting all the data from my XML. Can any one shed some light please.
My XML is as follows
<storeitems>
<PRODUCT ITEM="3002074730">
<SPECIALS_ID>14713</SPECIALS_ID>
<FULL_PRICE>27.00</FULL_PRICE>
<SPECIALS_NEW_PRODUCTS_PRICE>25.65</SPECIALS_NEW_PRODUCTS_PRICE>
</PRODUCT>
<PRODUCT ITEM="SE-0088-10-3">
<SPECIALS_ID>29555</SPECIALS_ID>
<FULL_PRICE>53.99</FULL_PRICE>
<SPECIALS_NEW_PRODUCTS_PRICE>51.29</SPECIALS_NEW_PRODUCTS_PRICE>
</PRODUCT>
<storeitems>
My code is as follows
$xml = new SimpleXMLElement($data);
foreach($xml->PRODUCT as $post) {
echo $post->SPECIALS_ID .'<BR>';
echo $post->FULL_PRICE . '<BR>';
echo $post->SPECIALS_NEW_PRODUCTS_PRICE . '<BR>';
}
This does what I expect but can you assist me in getting this part of the XML to echo please
<PRODUCT ITEM="3002074730">
echo $post->attributes();
will print the value of your item (first) attribute (it's an object that does that when it's called in a string-context).
If you add more attributes and you want to get them all, you can iterate over $post->attributes():
foreach($post->attributes() as $name => $value){
...
}

Categories