Accessing elements in Simplexml with complex structure - php

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
}
}
`

Related

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>';
}

Retrieved value from xml php?

I need your help guys,
I have this issue:
When I use the bigbluebutton api for retrieve the meetings from the server I received this result:
Array
(
[returncode] => SimpleXMLElement Object ( [0] => SUCCESS )
[messageKey] => SimpleXMLElement Object ( )
[message] => SimpleXMLElement Object ( )
[0] => Array
(
[meetingId] => SimpleXMLElement Object ( [0] => 1111)
[meetingName] => SimpleXMLElement Object ( [0] => Test MeetingName )
[createTime] => SimpleXMLElement Object ( [0] => 1402148945933 )
[attendeePw] => SimpleXMLElement Object ( [0] => passw)
[moderatorPw] => SimpleXMLElement Object ( [0] => passw)
[hasBeenForciblyEnded] => SimpleXMLElement Object ( [0] => false )
[running] => SimpleXMLElement Object ( [0] => false )
)
)
Where the second array will be populated by the meetings. Now there is one meeting so u see only one element.
I don't need help with cycle for or foreach but I need your help for retrieve the meetingid or meetingname or attendepw.
i found this on stackoverflow :Get value from SimpleXMLElement Objectsimplexmlelement-object
and the solution was: $value = (string) $xml->code[0]->lat;
But I think this is not the solution for me.
I tried this code:
$array=$result['message'];
$id=$array['meetingId'];
But now I can't retrieved the id from this $id.
Sorry for my English, any help will be appreciated
To get the meetingId SimpleXMLElement Object
$meetingIdEl = $result[0]['meetingId'];
To get the value of meetingIdEl
$mettingId = $meetingIdEl->__toString(); // or (string)$meetingIdEl;
echo $meetingId; // 1111
SimpleXMLElement Documentation

SimpleXMLElement parsing issue with PHP

I'm trying to parse out the following response:
SimpleXMLElement Object (
[responseType] => SimpleXMLElement Object (
[inputConceptName] => aspirin [inputKindName] => % )
[groupConcepts] => SimpleXMLElement Object (
[concept] => Array (
[0] => SimpleXMLElement Object (
[conceptName] => ASPIRIN
[conceptNui] => N0000145918
[conceptKind] => DRUG_KIND )
[1] => SimpleXMLElement Object ( #
[conceptName] => Aspirin
[conceptNui] => N0000006582
[conceptKind] => INGREDIENT_KIND )
) ) )
in PHP. I have it stored as a curl string:
$xml = simplexml_load_string($data);
print_r($xml);
How do I get just the conceptNui of the first object as a PHP variable?
Take a look at the documentation, it give simple example to understand the friendly syntax to extract the data :
http://www.php.net/manual/en/simplexml.examples-basic.php
In your case, it could be :
$xml->groupConcepts->concept[0]->conceptNui
As your structure is
SimpleXMLElement Object (
[responseType] => SimpleXMLElement Object (
[inputConceptName] => aspirin
[inputKindName] => % )
[groupConcepts] => SimpleXMLElement Object (
[concept] => Array ([0] => SimpleXMLElement Object (
[conceptName] => ASPIRIN
[conceptNui] => N0000145918
[conceptKind] => DRUG_KIND )
[1] => SimpleXMLElement Object (
[conceptName] => Aspirin
[conceptNui] => N0000006582
[conceptKind] => INGREDIENT_KIND )
)
)
)
$conceptNui = $mainObj->groupConcepts->concept[0]->conceptNui;

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.

How can I properly parse a SimpleXML Object in PHP?

I'm using the CloudFusion class to get Amazon.com data and my code is simple:
$items = $pas->item_search( "shoes", array(
"ResponseGroup" => "Small",
"SearchIndex" => "Blended" ));
$items = $items->body->Items;
echo "<pre>";
print_r( $items );
echo "</pre>";
This returns the following:
SimpleXMLElement Object (
[Request] => SimpleXMLElement Object
(
[IsValid] => True
[ItemSearchRequest] => SimpleXMLElement Object
(
[Keywords] => shoes
[ResponseGroup] => Small
[SearchIndex] => Blended
)
)
[TotalResults] => 737435
[TotalPages] => 245816
[SearchResultsMap] => SimpleXMLElement Object
(
[SearchIndex] => Array
(
[0] => SimpleXMLElement Object
(
[IndexName] => Kitchen
....
)
[Item] => Array
(
[0] => SimpleXMLElement Object
(
[ASIN] => B0001Z95QY
[DetailPageURL] => http://www.amazon.com/Household-Essentials-MS6030-Seasonal-Storage/dp/B0001Z95QY%3FSubscriptionId%3D0WASFFPR5B82TH4ZQB82%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB0001Z95QY
[ItemLinks] => SimpleXMLElement Object
(
[ItemLink] => Array
(
[0] => SimpleXMLElement Object
(
[Description] => Technical Details
[URL] => http://www.amazon.com/Household-Essentials-MS6030-Seasonal-Storage/dp/tech-data/B0001Z95QY%3FSubscriptionId%3D0WASFFPR5B82TH4ZQB82%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB0001Z95QY
) ....................
)
[1] => SimpleXMLElement Object
(
[ASIN] => B001ACNBZ8
[DetailPageURL] => http://www.amazon.com/Peet-Shoe-Dryer-Boot-Original/dp/B001ACNBZ8%3FSubscriptionId%3D0WASFFPR5B82TH4ZQB82%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB001ACNBZ8
[ItemLinks] => SimpleXMLElement Object
(...................
)
)
What I'd like to do is get down to the "Item" level, then run a foreach to get each individual entry. I tried $items = $items->Item, but this returns only the first entry.
Any ideas?
First of all, you should avoid using print_r() on SimpleXMLElement, instead just take a look at the XML using asXML(). That's also what you should post here, instead of print_r()'s output.
I can't decipher the code you have posted so I'll take a wild guess and suggest that you try something like:
foreach ($items->body->Items->Item as $Item)
{
}
At any rate, if you want to iterate over something, foreach is the answer.

Categories