PHP simplexml reading child tag attribute - php

I have a xml like below,
<y>
<n>
<n id='test1'></n>
<n id='test2'></n>
</n>
</y>
and want to read each "id" of child "n" tag .
I use this php code;
$xml = simplexml_load_file("my.xml");
echo $xml->n[0]->n;
but getting error,
Trying to get property of non-object

It should be : $xml->n->n[0] which is an array. If you print_r($xml) you might see like this:
SimpleXMLElement Object
(
[n] => SimpleXMLElement Object
(
[n] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => test1
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => test2
)
)
)
)
)

Related

How to Get Values Of [#attributes] Element Using SimpleXML In PHP

I have problem accessing this attribue , $xml is my xml output using simpleXML .... here is the part of xml :
[component] => Array
(
[0] => SimpleXMLElement Object
(
[observationMedia] => SimpleXMLElement Object
(
[#attributes] => Array
(
[ID] => L30b39868-2c02-4f22-817f-3fc8ff059193
)
[text] => image description
[value] => SimpleXMLElement Object
(
[#attributes] => Array
(
[mediaType] => image/jpeg
)
[reference] => SimpleXMLElement Object
(
[#attributes] => Array
(
[value] => Label2.jpg
)
)
)
)
)
)
)
I am able to access the [text] element using this :
$xml->component->observationMedia->text
But Unable to access the attribute value , I tried this but didnot work :
$xml->component->observationMedia->value->reference->attributes()->value
If I use #attributes , then its gives error in php ...
Here is the xml data :
<component>
<observationMedia ID="L30b39868-2c02-4f22-817f-3fc8ff059193">
<text>image description</text>
<value mediaType="image/jpeg" xsi:type="ED">
<reference value="Label2.jpg" />
</value>
</observationMedia>
</component>
After looking at the xml data , I have solved my problem ..
Here is how I have got the attribute value :
echo (string) $component ->observationMedia ->value->reference['value']
Looking at the xml value has helped me ....

Accessing elements in Simplexml with complex structure

I'm new to woking with XML with PHP. I have a fairly complex XML structure and am using simplexml in laravel and am having trouble accessing all the elements I need to get. I am able to loop through the large XML file but simpleXML is returning two objects per record and I only seem to be able to access the elements in 'header', the first object returned...
here is part of the xml object
SimpleXMLElement Object
(
[identifier] => RCM0635
[datestamp] => 2015-06-09
)
SimpleXMLElement Object
(
[lidoWrap] => SimpleXMLElement Object
(
[lido] => SimpleXMLElement Object
(
[lidoRecID] => RCM:1748
[descriptiveMetadata] => SimpleXMLElement Object
(
[objectClassificationWrap] => SimpleXMLElement Object
(
[objectWorkTypeWrap] => SimpleXMLElement Object
(
[objectWorkType] => SimpleXMLElement Object
(
[term] => musical instruments
)
)
[classificationWrap] => SimpleXMLElement Object
(
[classification] => Array
(
[0] => SimpleXMLElement Object
(
[term] => Cornet
)
[1] => SimpleXMLElement Object
(
[conceptID] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => SH_Class
)
)
)
)
)
)
With the code below I can get the elements in the header but I can't figure out how to get the other elements?
$streamer = \Prewk\XmlStringStreamer::createStringWalkerParser(public_path().'/xml/many_mimo_records.xml');
while ($node = $streamer->getNode()) {
$simpleXmlNode = simplexml_load_string($node);
echo (string)$simpleXmlNode->identifier;
echo (string)$simpleXmlNode->datestamp;
}
I'd be very grateful for any advice...
I'm not sure if I understand You but in major:
You act on while ($node = $streamer->getNode()) loop what means that after first iteration You'll get this object:
SimpleXMLElement Object
(
[identifier] => RCM0635
[datestamp] => 2015-06-09
)
so for the first time it's ok to read it like:
`
$simpleXmlNode = simplexml_load_string($node);
echo (string)$simpleXmlNode->identifier;
echo (string)$simpleXmlNode->datestamp;
`
but in the second iteration You have:
`
SimpleXMLElement Object
(
[lidoWrap] => SimpleXMLElement Object
(
[lido] => SimpleXMLElement Object
(
[lidoRecID] => RCM:1748
[descriptiveMetadata] => SimpleXMLElement Object
(
[objectClassificationWrap] => SimpleXMLElement Object
(
[objectWorkTypeWrap] => SimpleXMLElement Object
(
[objectWorkType] => SimpleXMLElement Object
(
[term] => musical instruments
)
)
[classificationWrap] => SimpleXMLElement Object
(
[classification] => Array
(
[0] => SimpleXMLElement Object
(
[term] => Cornet
)
[1] => SimpleXMLElement Object
(
[conceptID] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => SH_Class
)
)
)
)
)
)
`
so the code inside while is wrong.
i sugest to try something like this:
`
while ($node = $streamer->getNode()) {
$simpleXmlNode = simplexml_load_string($node);
if (!empty($simpleXmlNode->identifier))
echo (string)$simpleXmlNode->identifier;
if (!empty($simpleXmlNode->datestamp))
echo (string)$simpleXmlNode->datestamp;
if (!empty($simpleXmlNode->lidoWrap)) {
$lido = $simpleXmlNode->lidoWrap->lido;
echo (string)$lido->lidoRecID;
// and so on as the recursive XML node objects
}
}
`

How to display a value from a SimpleXML object (the array notation is confusing me)

I have a PHP file that uses cURL to retrieve some XML. I now want to retrieve a value from the XML but I cannot traverse to it as I am confused with the notation.
Here's my retrieved XML:
SimpleXMLElement Object
(
[#attributes] => Array
(
[uri] => /fruit/apple/xml/green/pipType
)
[result] => SimpleXMLElement Object
(
[JobOpenings] => SimpleXMLElement Object
(
[row] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[no] => 1
)
[FL] => Array
(
[0] => 308343000000092052
[1] => ZR_6_JOB
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[no] => 2
)
[FL] => Array
(
[0] => 308343000000091031
[1] => ZR_5_JOB
)
)
)
)
)
)
I have this XML stored in a variable called $xml using:
$xml = new SimpleXmlElement($data, LIBXML_NOCDATA);
Any help for how I can select the ZR_5_JOB element please?
I have tried countless times, the last effort I had was:
print_r($xml->result->JobOpenings->row[0]->FL[0]);
Could anybody please help?
(I know I will then need to do some iteration, but I'll deal with that later!)
First loop the JobOpenings rows to get each row separately and then you can access the childrens of that element in an easy way.
foreach($xml->result->JobOpenings->row as $item) {
echo $item->FL[0] . '<br>';
}

simplexml_load_string isn't creating attribute array if XML node is a value node

I am loading an XML string using simplexml_load_string and if the node doesn't have any child nodes of it's own then the attributes of that node don't seem to be mapped to the array correctly. Is there any way around this? Please see the CUSTOM_PROPERTY sections below:
Suppose I have the following XML:
<WEBSITE NAME="www.example.co.uk">
<CATEGORY ID="35702" NAME="CatName" FILE_NAME="" LONG_DESC="" SHORT_DESC="">
<CUSTOM>
<CUSTOM_PROPERTY NAME="CATTYPE_INDEX">6</CUSTOM_PROPERTY>
<CUSTOM_PROPERTY NAME="TEMPLATE_ID">0</CUSTOM_PROPERTY>
<CUSTOM_PROPERTY NAME="DISPLAY_LIMIT">10</CUSTOM_PROPERTY>
<CUSTOM_PROPERTY NAME="HIDE_ON_MENU">0</CUSTOM_PROPERTY>
<CUSTOM_PROPERTY NAME="CAT_COLOUR">#01b2a8</CUSTOM_PROPERTY>
</CUSTOM>
</CATEGORY>
When I use the following code:
$Xml = simplexml_load_string($Str);
print_r($Xml);
It returns this:
SimpleXMLElement Object
(
[#attributes] => Array
(
[NAME] => www.example.co.uk
)
[CATEGORY] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[ID] => 35702
[NAME] => CatName
[FILE_NAME] =>
[LONG_DESC] =>
[SHORT_DESC] =>
)
[CUSTOM] => SimpleXMLElement Object
(
[CUSTOM_PROPERTY] => Array
(
[0] => 6
[1] => 0
[2] => 10
[3] => 0
[4] => #01b2a8
)
)
)
)
)
CUSTOM_PROPERTY should have an attribute NAME mapped but it doesn't.
Your attributes are there but are not shown by print_r(). Be aware that print_r() is not a reliable way of viewing the entire SimpleXML structure.
Example:
Demo
$obj = simplexml_load_string($xml);
foreach($obj->CATEGORY->CUSTOM->CUSTOM_PROPERTY as $custom_property)
{
echo $custom_property->attributes()->NAME . "\n";
}
Outputs
CATTYPE_INDEX
TEMPLATE_ID
DISPLAY_LIMIT
HIDE_ON_MENU
CAT_COLOUR

XPath string for all children of namespaced elements

Just getting started with XPath, and using it's implementation with PHP's SimpleXML objects. Right now I'm using //zuq:* to create an array of SimpleXML objects with the zuq prefix in a given document. However, I'd like the SimpleXML objects to reference all descendants regardless of namespace. I tried using //child::zuq:*, but the SimpleXML trees it creates don't seem to be complete.
Essentially, the objects captured should be all the top level objects of the zuq namespace throughout the document, containing all descendant elements regardless of namespace, including zuq.
tl;dr: How can I create a SimpleXML object tree from a given document where each SimpleXML root object is the highest level document element of a given namespace (such as zuq) containing all descendants of said element regardless of the descendant namespace? XPath is not a requisite but appears to be the best choice based on my reading.
test.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:zuq="http://localhost/zuq">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
<h1>Heading</h1>
<p>Paragraph</p>
<zuq:region name="myRegion">
<div class="myClass">
<h1><zuq:data name="myDataHeading" /></h1>
<p>
<zuq:data name="myDataParagraph">
<zuq:format type="trim">
<zuq:param name="length" value="200" />
<zuq:param name="append">
<span class="paragraphTrimOverflow">...</span>
</zuq:param>
</zuq:format>
</zuq:data>
</p>
</div>
</zuq:region>
</body>
</html>
$sxml = simplexml_load_file('test.html');
$sxml_zuq = $sxml->xpath('//zuq:*/descendant-or-self::node()');
print_r($sxml_zuq);
Produces:
Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => myRegion
)
[div] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => myClass
)
[h1] => SimpleXMLElement Object //I don't know why these don't contain their zuq descendants
(
)
[p] => SimpleXMLElement Object
(
)
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => myRegion
)
[div] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => myClass
)
[h1] => SimpleXMLElement Object
(
)
[p] => SimpleXMLElement Object
(
)
)
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => myClass
)
[h1] => SimpleXMLElement Object
(
)
[p] => SimpleXMLElement Object
(
)
)
[3] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => myClass
)
[h1] => SimpleXMLElement Object
(
)
[p] => SimpleXMLElement Object
(
)
)
[4] => SimpleXMLElement Object
(
)
[5] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => myDataHeading
)
)
[6] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => myClass
)
[h1] => SimpleXMLElement Object
(
)
[p] => SimpleXMLElement Object
(
)
)
[7] => SimpleXMLElement Object
(
)
[8] => SimpleXMLElement Object
(
)
[9] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => myDataParagraph
)
)
[10] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => myDataParagraph
)
)
[11] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => trim
)
)
[12] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => trim
)
)
[13] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => length
[value] => 200
)
)
[14] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => trim
)
)
[15] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => append
)
[span] => ...
)
[16] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => append
)
[span] => ...
)
[17] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => paragraphTrimOverflow
)
[0] => ...
)
[18] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => paragraphTrimOverflow
)
[0] => ...
)
[19] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => append
)
[span] => ...
)
[20] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => trim
)
)
[21] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => myDataParagraph
)
)
[22] => SimpleXMLElement Object
(
)
[23] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => myClass
)
[h1] => SimpleXMLElement Object
(
)
[p] => SimpleXMLElement Object
(
)
)
[24] => SimpleXMLElement Object
(
[#attributes] => Array
(
[name] => myRegion
)
[div] => SimpleXMLElement Object
(
[#attributes] => Array
(
[class] => myClass
)
[h1] => SimpleXMLElement Object
(
)
[p] => SimpleXMLElement Object
(
)
)
)
)
Don't trust the output of the print_r statement ... it seems to be showing an empty object, but in my testing the children are actually still there. For example, starting with your code above:
$sxml = simplexml_load_file('test.html');
$sxml_zuq = $sxml->xpath('//zuq:*/descendant-or-self::node()');
If I subsequently try a command like this:
print_r($sxml_zuq[0]->div->h1);
I get this output:
SimpleXMLElement Object
(
)
It seems to be empty, right? But if I modify the command to look like this:
echo $sxml_zuq[0]->div->h1->asXML();
I get the resultant tree with the namespaced child:
<h1><zuq:data name="myDataHeading"/></h1>
I'm not 100% sure why this is; it probably has something to do with the print_r statement trying to flatten the simplexml object and not dealing with the namespaces properly. But when you keep to the simplexml objects themselves that are returned from your xpath call, all of the children are preserved.
Now, in regards to your xpath itself, you probably DON'T want the "descendant-or-self" axis, because that will match not only the top-level zuq element, but also match all its children and create a larger array than you're actually seeking to return (unless I'm misunderstanding what you're asking). If you try something like this:
$sxml_zuq = $sxml->xpath('//zuq:*[not(ancestor::zuq:*)]');
then you'll get back an array of ONLY the top level of zuq namespaced elements. (while your example XML only had one such top-level element, your actual data may have several siblings at that level). You can then capture the content of each of these top level elements like this:
foreach ($sxml_zuq as $zuq_node) {
echo ($zuq_node->asXML());
}
Things get a little trickier if you want to repeat this process but do the search for top-level (or any) elements in the default namespace; you'd have to use the registerNamespace function to give the default namespace a temporary prefix, and do the xpath search on that.
I think you're looking for //zuq:*/descendant-or-self::*. This will result in all subtrees with the root having zuq namespace prefix.
The observed behavior seems to be an artifact of SimpleXML (the XPath specification does not deal with trees in the XPath query output, only separate nodes). You can probably solve it using something like
//zuq:*[not(ancestor::zuq:*)]/descendant-or-self::*
ancestor[...] checks whether there is an ancestor for which a condition is true - i.e. whether there is an ancestor with zuq prefix. So you should get only zuq: roots that have no zuq: ancestor.

Categories