each node attribute value of xml in php - php

Im trying to get the catId value. But i can see only the category value.
My xml file looks below:
<sample>
<Item ItemNumber="00000088" FormattedItemNumber="00000-088">
<CompatibleModels />
<Category CatId="160" > test 123 </Category>
<Images />
<Documents />
<RequiredItems />
</Item>
</sample>
$xml = simplexml_load_file("test.xml");
print_r($xml);
[sample] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[ItemNumber] => 00000088
[FormattedItemNumber] => 00000-088
)
[Category] => Bags/Luggage 123
)
how can get the CatId value? Why the cateId value is missing?

You can do it by many ways. Let's try-
foreach ($xml as $items) {
echo $items->Category['CatId'];
}
WORKING DEMO: https://3v4l.org/Onqe2

print_r doesn't really work with SimpleXML objects. But from the sample data you have provided you can simply access the CatId attribute using
echo $xml->Item->Category['CatId'];

You can loop and get it by using following snippet, please refer inline documentation for explanation
$xml1 = simplexml_load_file("test.xml") or die("Error: Cannot create object");
foreach ($xml1->children() as $items1) { // children mean item
echo ($items1->category['catid']); // for category tag get catid attribute
}

Related

Parsing very simple XML with PHP

Very simple request (I think) that I have had no luck with.
Here is the contents of the xml file:
<?xml version="1.0" encoding="utf-8"?>
<status USER_ID="xxxxx">OK</status>
Current php:
$xml=simplexml_load_file($file) or die("Error: Cannot create object");
print_r($xml);
Outputs:
SimpleXMLElement Object ( [#attributes] => Array ( [USER_ID] => xxxxx ) [0] => OK )
And now I'm stuck
How can I get the value of USER_ID and that the status was "OK" into my php script.
Thanks.
Try this one below
echo "Display the user id: " . $xml['USER_ID'];
echo "Display the status: " . $xml[0];
Hope this will help you.
If you don't like SimpleXml (like me), you can also use the XMLReader Class like:
$XMLReader = new XMLReader;
$XMLReader->XML(file_get_contents($file)); //you can use $XMLReader->open('file://'.$file); too
//move to first node
$XMLReader->read();
//get an attribute
echo "USER_ID:".$XMLReader->getAttribute('USER_ID')."\n";
//get the contents of the tag as a string
echo "Status:" .$XMLReader->readString();
Output:
USER_ID:xxxxx
Status:OK
Sandbox

Namespaces and XPath

I'm exploring XML and PHP, mostly XPath and other parsers.
Here be the xml:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org">
<actors>
<actor id="1">Christian Bale</actor>
<actor id="2">Liam Neeson</actor>
<actor id="3">Michael Caine</actor>
</actors>
<foo:singers>
<foo:singer id="4">Tom Waits</foo:singer>
<foo:singer id="5">B.B. King</foo:singer>
<foo:singer id="6">Ray Charles</foo:singer>
</foo:singers>
<items>
<item id="7">Pizza</item>
<item id="8">Cheese</item>
<item id="9">Cane</item>
</items>
</root>
Here be my path & code:
$xml = simplexml_load_file('xpath.xml');
$result = $xml -> xpath('/root/actors');
echo '<pre>'.print_r($result,1).'</pre>';
Now, said path returns:
Array
(
[0] => SimpleXMLElement Object
(
[actor] => Array
(
[0] => Christian Bale
[1] => Liam Neeson
[2] => Michael Caine
)
)
)
Whereas a seemingly similar line of code, which I would have though would result in the singers, doesnt. Meaning:
$result = $xml -> xpath('/root/foo:singers');
Results in:
Array
(
[0] => SimpleXMLElement Object
(
)
)
Now I would've thought the foo: namespace in this case is a non-issue and both paths should result in the same sort of array of singers/actors respectively? How come that is not the case?
Thank-you!
Note: As you can probably gather I'm quite new to xml so please be gentle.
Edit: When I go /root/foo:singers/foo:singer I get results, but not before. Also with just /root I only get actors and items as results, foo:singers are completely omitted.
SimpleXML is, for a number of reasons, simply a bad API.
For most purposes I suggest PHP's DOM extension. (Or for very large documents a combination of it along with XMLReader.)
For using namespaces in xpath you'll want to register those you'd like to use, and the prefix you want to use them with, with your xpath processor.
Example:
$dom = new DOMDocument();
$dom->load('xpath.xml');
$xpath = new DOMXPath($dom);
// The prefix *can* match that used in the document, but it's not necessary.
$xpath->registerNamespace("ns", "http://www.foo.org/");
foreach ($xpath->query("/root/ns:singers") as $node) {
echo $dom->saveXML($node);
}
Output:
<foo:singers>
<foo:singer id="4">Tom Waits</foo:singer>
<foo:singer id="5">B.B. King</foo:singer>
<foo:singer id="6">Ray Charles</foo:singer>
</foo:singers>
DOMXPath::query returns a DOMNodeList containing matched nodes. You can work with it essentially the same way you would in any other language with a DOM implementation.
You can use // expression like:
$xml -> xpath( '//foo:singer' );
to select all foo:singer elements no matter where they are.
EDIT:
SimpleXMLElement is selected, you just can't see the child nodes with print_r(). Use SimpleXMLElement methods like SimpleXMLElement::children to access them.
// example 1
$result = $xml->xpath( '/root/foo:singers' );
foreach( $result as $value ) {
print_r( $value->children( 'foo', TRUE ) );
}
// example 2
print_r( $result[0]->children( 'foo', TRUE )->singer );

Json Encode or Serialize an XML

I have some xml, this is a simple version of it.
<xml>
<items>
<item abc="123">item one</item>
<item abc="456">item two</item>
</items>
</xml>
Using SimpleXML on the content,
$obj = simplexml_load_string( $xml );
I can use $obj->xpath( '//items/item' ); and get access to the #attributes.
I need an array result, so I have tried the json_decode(json_encode($obj),true) trick, but that looks to be removing access to the #attributes (ie. abc="123").
Is there another way of doing this, that provides access to the attributes and leaves me with an array?
You need to call attributes() function.
Sample code:
$xmlString = '<xml>
<items>
<item abc="123">item one</item>
<item abc="456">item two</item>
</items>
</xml>';
$xml = new SimpleXMLElement($xmlString);
foreach( $xml->items->item as $value){
$my_array[] = strval($value->attributes());
}
print_r($my_array);
Eval
You can go the route with json_encode and json_decode and you can add the stuff you're missing because that json_encode-ing follows some specific rules with SimpleXMLElement.
If you're interested into the rules and their details, I have written two blog-posts about it:
SimpleXML and JSON Encode in PHP – Part I
SimpleXML and JSON Encode in PHP – Part II
For you perhaps more interesing is the third part which shows how you can modify the json serialization and provide your own format (e.g. to preserve the attributes):
SimpleXML and JSON Encode in PHP – Part III and End
It ships with a full blown example, here is an excerpt in code:
$xml = '<xml>
<items>
<item abc="123">item one</item>
<item abc="456">item two</item>
</items>
</xml>';
$obj = simplexml_load_string($xml, 'JsonXMLElement');
echo $json = json_encode($obj, JSON_PRETTY_PRINT), "\n";
print_r(json_decode($json, TRUE));
Output of JSON and the array is as following, note that the attributes are part of it:
{
"items": {
"item": [
{
"#attributes": {
"abc": "123"
},
"#text": "item one"
},
{
"#attributes": {
"abc": "456"
},
"#text": "item two"
}
]
}
}
Array
(
[items] => Array
(
[item] => Array
(
[0] => Array
(
[#attributes] => Array
(
[abc] => 123
)
[#text] => item one
)
[1] => Array
(
[#attributes] => Array
(
[abc] => 456
)
[#text] => item two
)
)
)
)
$xml = new SimpleXMLElement($xmlString);
$xml is now an object. To get the value of an attribute:
$xml->something['id'];
Where 'id' is the name of the attribute.
While it's theoretically possible to write a generic conversion from XML to PHP or JSON structures, it is very hard to capture all the subtleties that might be present - the distinction between child elements and attributes, text content alongside attributes (as you have here) or even alongside child elements, multiple child nodes with the same name, whether order of child elements and text nodes is important (e.g. in XHTML or DocBook), etc, etc.
If you have a specific format you need to produce, it will generally be much easier to use an API - like SimpleXML - to loop over the XML and produce the structure you need.
You don't specify the structure you want to achieve, but the general approach given your input would be to loop over each item, and either access known attributes, or loop over each attribute:
$sxml = simplexml_load_string( $xml );
$final_array = array();
foreach ( $sxml->items->item as $xml_item )
{
$formatted_item = array();
// Text content of item
$formatted_item['content'] = (string)$xml_item;
// Specifically get 'abc' attribute
$formatted_item['abc'] = (string)$xml_item['abc'];
// Maybe one of the attributes is an integer
$formatted_item['foo_id'] = (int)$xml_item['foo_id'];
// Or maybe you want to loop over lots of possible attributes
foreach ( $xml_item->attributes() as $attr_name => $attr_value )
{
$formatted_item['attrib:' . $attr_name] = (string)$attr_value;
}
// Add it to a final list
$final_array[] = $formatted_item;
// Or maybe you want that array to be keyed on one of the attributes
$final_array[ (string)$xml_item['key'] ] = $formatted_item;
}
Here is a class I've found that is able to process XML into array very nicely: http://outlandish.com/blog/xml-to-json/ (backup). Converting to json is a matter of a json_encode() call.

dynamcially retrieve xml data

I am working with simplexml to retrieve data.
The data I am having trouble with looks like this:
SimpleXMLElement Object
(
[listing_pics_array] => SimpleXMLElement Object
(
[pic0] => http://imagepath.com_1.jpg
[pic1] => http://imagepath.com_2.jpg
[pic2] => http://imagepath.com_3.jpg
[pic3] => http://imagepath.com_4.jpg
[pic4] => http://imagepath.com_5.jpg
[pic5] => http://imagepath.com_6.jpg
[pic6] => http://imagepath.com_7.jpg
)
)
I am able to retrieve the url like this:
(string)$listing->listing_pics_array->pic0[0]
I want to dynamically loop over the listing_pic_array because I have no idea how many pics will be returned.
I want to do something like this:
foreach ($listing->listing_pics_array as $key => $value) {
echo '<img src="'.$value .'" alt="" />';
}
but I am getting nothing returned.
Thanks.
Try casting the SimpleXMLElement into an Array. This one works fine for me:
$sXml = <<<XML
<?xml version='1.0'?>
<root>
<listing_pics_array>
<pic0>pic0 foo</pic0>
<pic1>pic1 bar</pic1>
</listing_pics_array>
</root>
XML;
$oXml = simplexml_load_string($sXml);
foreach ((array)$oXml->listing_pics_array as $sCurrentValue) {
echo $sCurrentValue . PHP_EOL;
}
Yielded
pic0 foo
pic1 bar
HTH

XPath and PHP troubleshooting

I get this error:
Notice: Trying to get property of non-object in
Applies to:
echo $result->Data;
And this output:
Array ()
Background Informations
A function returns a string which contains an XML file.
I want to get some data from two tags and deal with them on their own.
String Data
$data="
<SyncML xmlns='SYNCML:SYNCML1.0'>
<SyncHdr>
</SyncHdr>
<SyncBody>
<betameta>
WANT 1
</betameta>
<Add>
<Data>
WANT 2
</Data>
</Add>
</SyncBody>
</SyncML>";
In the above data, I want values "WANT 1" and "WANT 2"
Code so far
$xml = simplexml_load_string($data);
$result = $xml->xpath("/SyncML/SyncBody");
print_r($result);
echo $result->Data;
$xml->registerXPathNamespace('default','SYNCML:SYNCML1.0');
$result = $xml->xpath("/default:SyncML/default:SyncBody");
Remove the trailing slash.
The only solution I can find is the following:
<?php
$data= <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<SyncML>
<SyncHdr>
</SyncHdr>
<SyncBody>
<betameta>
WANT 1
</betameta>
<Add>
<Data>
WANT 2
</Data>
</Add>
</SyncBody>
</SyncML>
XML;
$xml = simplexml_load_string($data);
$result = $xml->xpath("/SyncML/SyncBody");
print_r($result);
echo $result;
is there anyway you can loose the xmlns?
This will output:
Array
(
[0] => SimpleXMLElement Object
(
[betameta] =>
WANT 1
[Add] => SimpleXMLElement Object
(
[Data] =>
WANT 2
)
)
)

Categories