PHP - how to display soap response sub children list - php

I got a response in the following xml format like below:
How can I get list->item->value in one row or container:
<list>
<item>
<Key>3</Key>
<Value>3960</Value>
</item>
<item>
<Key>5</Key>
<Value>3967</Value>
</item>
<item>
<Key>6</Key>
<Value>3968</Value>
</item>
</list>
How can I display the value like this below
<table>
<tr>
<td>3960, 3967, 3968</td>
<td>3963, 3961, 3960</td>
</tr>
</table>
and at the moment I try to use children() in foreach, but it returns error: Call to a member function children() on null, and below is my php code
foreach($items as $item){
echo '<td>';
$child_item = '';
foreach($item->list->children()->children() as $child)
{
$child_item .= $child .' ,';
}
echo rtrim($child_item,' ,');
echo '</td>';
}
Thanks experts!

This is what you need to achieve that:
<?php
$xmlstr = <<<XML
<root>
<list>
<item>
<Key>3</Key>
<Value>3960</Value>
</item>
<item>
<Key>5</Key>
<Value>3967</Value>
</item>
<item>
<Key>6</Key>
<Value>3968</Value>
</item>
</list>
<list>
<item>
<Key>3</Key>
<Value>3963</Value>
</item>
<item>
<Key>5</Key>
<Value>3961</Value>
</item>
<item>
<Key>6</Key>
<Value>3960</Value>
</item>
</list>
</root>
XML;
$items = new SimpleXMLElement($xmlstr);
echo "<table>\r\n";
echo "<tr>\r\n";
foreach($items as $list){
echo "<td>";
$itemsArr = array();
foreach($list as $item){
$itemsArr[] = $item->Value[0];
}
echo implode(", ", $itemsArr);
echo "</td>\r\n";
}
echo "</tr>\r\n";
echo "</table>";
?>

Related

PHP SimpleXML: How to access nested namespaces?

Given this XML structure:
$xml = '<rss xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<item>
<title>Title</title>
<media:group>
<media:content url="url1" />
<media:content url="url2" />
</media:group>
</item>
<item>
<title>Title2</title>
<media:group>
<media:content url="url1" />
<media:content url="url2" />
</media:group>
</item>
</channel>
</rss>';
$xml_data = new SimpleXMLElement($xml);
How do I access the attributes of the media:content nodes? I tried
foreach ($xml_data->channel->item as $key => $data) {
$urls = $data->children('media', true)->children('media', true);
print_r($urls);
}
and
foreach ($xml_data->channel->item as $key => $data) {
$ns = $xml->getNamespaces(true);
$urls = $data->children('media', true)->children($ns['media']);
print_r($urls);
}
as per other answers, but they both return empty SimpleXMLElements.
When you echo out XML with SimpleXML, you need to use asXML() to see the real content, print_r() does it's own version and doesn't show all the content...
foreach ($xml_data->channel->item as $key => $data) {
$urls = $data->children('media', true)->children('media', true);
echo $urls->asXML().PHP_EOL;
}
echos out...
<media:content url="url1"/>
<media:content url="url1"/>
It only outputs the first one of each group as you will need to add another foreach to go through all of the child nodes for each element.
foreach ($xml_data->channel->item as $key => $data) {
echo $data->title.PHP_EOL;
foreach ( $data->children('media', true)->children('media', true) as $content ) {
echo $content->asXML().PHP_EOL;
}
}
outputs..
Title
<media:content url="url1"/>
<media:content url="url2"/>
Title2
<media:content url="url1"/>
<media:content url="url2"/>
To access a particular attribute (so for example the url attribute from the second code example) you have to use the attributes() method...
echo $content->attributes()['url'];

Same variable from multiple XML

$var1 = new SimpleXMLElement('CSVXML/xvar.xml', null, true);
$var2 = new SimpleXMLElement('CSVXML/yvar.xml', null, true);
let's say I get variables from two diffrents XML files, in the first XML files
<Number>3698</Number>
<InternalNumber>1</InternalNumber>
<Name>Bob</Name>
<Number>3500</Number>
<InternalNumber>2</InternalNumber>
<Name>Mike</Name>
<Number>2775</Number>
<InternalNumber>3</InternalNumber>
<Name>Dan</Name>
in the second XML I get the followings
<player>3698</player>
<group>A</group>
I do this
$varID = $var1->Number;
$varnumber = $var2->player;
if ($varID == $varnumber ){
echo '$var1->InternalNumber';
}
is this possible ?
I simply want to put out a variable, is A for XML! = B from XML2, is there anyway possible to do that?
I found this working fine. tested link
<?php
$str = <<<XML
<items>
<item>
<Number>3698</Number>
<InternalNumber>1</InternalNumber>
<Name>Bob</Name>
</item>
<item>
<Number>3500</Number>
<InternalNumber>2</InternalNumber >
<Name>Mike</Name>
</item>
<item>
<Number>2775</Number>
<InternalNumber>3</InternalNumber>
<Name>Dan</Name>
</item>
</items>
XML;
$str2 = <<<XML
<item>
<player>3698</player>
<group>A</group>
</item>
XML;
$da = new SimpleXMLElement($str2);
$varnumber = $da->player;
$data = new SimpleXMLElement($str);
foreach ($data->item as $item)
{
$this_number = $item->Number;
//echo $this_number."-".$item->InternalNumber."-".$varnumber."\n";
if((int)$this_number == (int)$varnumber ){
$this_internalnumber = $item->InternalNumber;
echo $this_internalnumber."\n";
}
else{
echo "No Match found \n";
}
}
Hope this helps.

How to get the value of an array based on its name?

I have some xml data formatted like so:
<ADDITIONALINFORMATION>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 1</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>123</VALUE>
</ITEM>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 2</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>abc</VALUE>
</ITEM>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 3</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>456</VALUE>
</ITEM>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 4</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>def</VALUE>
</ITEM>
</ADDITIONALINFORMATION>
I am looping through the data using:
foreach($listing->ADDITIONALINFORMATION->ITEM as $item) {
if ($item->NAME == 'Some Name Here 3') {
$val = '';
echo '';
}
}
How do I get the value of "Some Name Here 3"?
I cannot use something like $item[3] since there are various numbers of items.
This is a job for Xpath if you ask me (or kojiro), however you could do it exactly like you do it already, you only need to output your value:
...
$val = $item->VALUE;
echo $val;
...
Using xpath would you spare to iterate over all elements as the query is executed already and gives you a more specific result already:
$name = 'Some Name Here 3';
$query = sprintf('//ITEM[NAME=%s]/VALUE', xpath_string($name));
list($value) = $listing->xpath($query) + [NULL];
echo $value;
The full example:
<?php
/**
* #link http://stackoverflow.com/questions/24370072/how-to-get-the-value-of-an-array-based-on-its-name
*/
$buffer = <<<XML
<LISTING>
<ADDITIONALINFORMATION>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 1</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>123</VALUE>
</ITEM>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 2</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>abc</VALUE>
</ITEM>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 3</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>456</VALUE>
</ITEM>
<ITEM>
<MULTIPLEVALUES>0</MULTIPLEVALUES>
<NAME>Some Name Here 4</NAME>
<VALUEARRAY></VALUEARRAY>
<VALUE>def</VALUE>
</ITEM>
</ADDITIONALINFORMATION>
</LISTING>
XML;
/**
* xpath string handling xpath 1.0 "quoting"
*
* #link http://hakre.wordpress.com/2013/07/11/mitigating-xpath-injection-attacks-in-php/
*
* #param string $input
*
* #return string
*/
function xpath_string($input) {
if (false === strpos($input, "'")) {
return "'$input'";
}
if (false === strpos($input, '"')) {
return "\"$input\"";
}
return "concat('" . strtr($input, array("'" => '\', "\'", \'')) . "')";
}
$listing = simplexml_load_string($buffer);
foreach ($listing->ADDITIONALINFORMATION->ITEM as $item) {
if ($item->NAME == 'Some Name Here 3') {
$val = $item->VALUE;
echo $val;
}
}
$name = 'Some Name Here 3';
$query = sprintf('//ITEM[NAME=%s]/VALUE', xpath_string($name));
list($value) = $listing->xpath($query) + [NULL];
echo $value;
This sounds like a job for xpath:
//ITEM[NAME="Some Name Here 3"]
would fetch the desired element node. Both DOMDocument and SimpleXMLElement support xpath. I'll leave it to you to choose which one you want to use.
use string compare function and get value of that element...
foreach($listing->ADDITIONALINFORMATION->ITEM as $item) {
if (strcmp($item->NAME,'Some Name Here 3') == 0) {
$value = $item->VALUE;
}
}

How to load all xml:lang attributes with SimpleXML

How to read ALL atribute xml:lang values?
Sometimes I do not know how many languages are defined in XMLs data.
<?xml version="1.0" encoding="UTF-8"?>
<offer>
<products>
<product>
<description>
<name xml:lang="eng">English translation</name>
<name xml:lang="lat">Latvian translation</name>
</description>
</product>
<product>
<description>
<name xml:lang="eng">The same English</name>
<name xml:lang="pol">And Polish language</name>
</description>
</product>
</products>
</offer>
I can xml:lang parse in PHP by adding exact language code in xpath
print_r($xml->xpath('products/product/description/name[#xml:lang = "eng"]'));
But I need to add all xml:lang atributes values to parsed array.
Can it be done with PHP SimpleXML?
what about this:
$nodes = $xml->xpath('products/product/description/name[#xml:lang]');
Will return an array of <name>-nodes.
If this is not it, please clarify exactly your desired result.
EDIT
try this to get the xml:lang attributes only:
$langs = $xml->xpath("products/product/description/name[#xml:lang]/#xml:lang");
// $lang is an array of simplexml-elements, transform the values to string like this:
$langs = array_map("strval", $langs);
I'm not 100% on SimpleXML sorry, but I know DomDocument can do what you are after. Hopefully this can be of use to you:
$xmlstring = '<?xml version="1.0" encoding="UTF-8"?>
<offer>
<products>
<product>
<description>
<name xml:lang="eng">English translation</name>
<name xml:lang="lat">Latvian translation</name>
</description>
</product>
<product>
<description>
<name xml:lang="eng">The same English</name>
<name xml:lang="pol">And Polish language</name>
</description>
</product>
</products>
</offer>';
$dom = new DOMDocument();
$dom->loadXML($xmlstring); //or $dom->load('filename.xml');
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//products/product/description/name');
foreach ($nodes as $node) {
echo 'Language: ' . $node->getAttribute('xml:lang') . '<br />';
echo 'Value: ' . $node->nodeValue . '<br /><br />';
}
You can assign $node->getAttribute('xml:lang') to a variable and run some checks to see if it matches 'eng' or whatever you need.
I used xpath as you had in your original post, but you can also use $dom->getElementsByTagName('name') and access values and attributes in much the same way.
I found easier way to access namespaced attributes. You could use $name->attributes("xml", true) function.
Here is working example:
<?php
$xmlString = '
<products>
<product>
<name xml:lang="eng">
Apples
</name>
<name xml:lang="fr">
Pommes
</name>
</product>
<product>
<name xml:lang="eng">
Strawberries
</name>
<name xml:lang="fr">
Fraises
</name>
</product>
</products>
';
$xml = new \SimpleXMLElement($xmlString);
foreach($xml->product as $product)
{
foreach ($product->name as $name)
{
$attributes = $name->attributes("xml", true);
// print_r($attributes);
foreach ($attributes as $attributeName => $attributeValue)
{
// echo $attributeName . PHP_EOL;
// echo $attributeValue . PHP_EOL;
if ($attributeValue == "eng" && $attributeName == "lang") {
echo "English: " . trim(((string) $name)) . PHP_EOL;
}
if ($attributeValue == "fr" && $attributeName == "lang") {
echo "French: " . trim(((string) $name)) . PHP_EOL;
}
}
}
}
Online demo: https://repl.it/repls/LovingFineDaemon

Removing an element form XML file in PHP

i tried to find it out with previous answers but i cannot do it propperly, i followed Stefan's answer Remove a child with a specific attribute, in SimpleXML for PHP
and my code is
xml:
<?xml version="1.0" encoding="utf-8"?>
<res>
<items>
<item>
<id>1</id>
<a>asdasda</a>
</item>
<item>
<id>1</id>
<a>bababba</a>
</item>
<id>2</id>
<a>sasdasda</a>
</item>
<item>
<id>3</id>
<a>sasdasda</a>
</item>
<item>
<id>4</id>
<a>sasdasda</a>
</item>
<item>
<id>5</id>
<a>sasdasda</a>
</item>
<item>
<id>6</id>
<a>sasdasda</a>
</item>
</items>
</res>
and php is
<?php
$id="1";
$xml = simplexml_load_file("filtracjaxml.xml") ;
foreach($xml->items->item->id as $id)
{
if($id == '1') {
$xml=dom_import_simplexml($id);
$xml->parentNode->removeChild($xml);
}
}
echo $xml->asXml();
?>
when i try to run it i have
Fatal error: Call to undefined method DOMElement::asXml() in filtruj.php on line 14
EDIT:
What I want is deleting the whole 'item' not only 'id' - all items with id = 1
so i changed the code :
foreach ( $xml->items->item as $id )
{
if ( $id->id == '1' ) {
$tmp = dom_import_simplexml($id);
$tmp->parentNode->removeChild($tmp);
}
}
echo $xml->asXml();
and it deletes only the first item. Could you tell me why? what is wrong in the code written above?
<?php
$id="1";
$xml = simplexml_load_file("filtracjaxml.xml") ;
foreach ( $xml->items->item->id as $id )
{
if ( $id == '1' ) {
$tmp = dom_import_simplexml($id);
$tmp->parentNode->removeChild($tmp);
}
}
echo $xml->asXml();
?>

Categories