How to parse XML (SimpleXML) - php

I need to parse XML string into an array.
I have XML
<group xmlns="123" id="personal">
<field id="last_name">last</field>
<field id="first_name">first</field>
<field id="birth_day">10/10/1990</field>
<field id="gender"/>
</group>
I'm using SimpleXML in php
$obj = simplexml_load_string($xml_string);
var_dump($obj);
SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => personal
)
[field] => Array
(
[0] => first
[1] => last
[2] => 10/10/1990
[3] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => gender
)
)
)
)
how to get such array? is it possible?
[field] => Array(
[last_name] => last,
[first_name] => first,
[birth_day] => 10/10/1990,
[gender] => NULL,
....
)
I do not know how else to explain this situation.
I want to index the id attribute value were.
please help.

Simple as that (Note it uses PHP 5.3 features):
libxml_use_internal_errors(true); // Turn off warnings because of invalid '123' namespace
$obj = simplexml_load_string($xml);
$obj->registerXPathNamespace('ns', '123');
$fields = $obj->xpath('//ns:field');
libxml_clear_errors(); // Clear warnings buffer
$result = array();
array_walk($fields, function($el) use (&$result) {
$result[(string)$el['id']] = (string)$el ?: null;
});
echo '<pre>'; print_r($result); echo '</pre>';
Output (null value is not shown by print_r):
Array
(
[last_name] => last
[first_name] => first
[birth_day] => 10/10/1990
[gender] =>
)

Try this,
print_r((array)($obj));
Check examples at simple_xml_load

You can go over your XML like this:
foreach ($obj->field as $field) {
...
}
$field will be the array containing last_name, first_name, birthday and gender.

Related

XML parsing is not working when it's only one array

I am parsing the xml like following:
$result = '
<sms>
<status>0</status>
<message>
<contact_lists>
<contact_list><cl_id>11111</cl_id><phone>999999999</phone><name>Neu</name></contact_list>
<contact_list><cl_id>222222</cl_id><phone>888888888</phone><name>Alt</name></contact_list>
</contact_lists>
</message>
</sms>';
$xml = simplexml_load_string($result, "SimpleXMLElement", LIBXML_NOCDATA);
$json = json_encode($xml);
$array = json_decode($json,true);
$contact_lists = $array['contact_lists']['contact_list'];
A sometimes the array look like this, which is works.
Array ( [status] => 0 [message] => Array ( ) [contact_lists] => Array ( [contact_list] => Array ( [0] => Array ( [cl_id] => 11111 [phone] => 999999999 [name] => Neu ) [1] => Array ( [cl_id] => 222222 [phone] => 888888888 [name] => Alt ) ) ) )
B but sometime if the array has only one contact_list, it will look like following
Array ( [status] => 0 [message] => Array ( ) [contact_lists] => Array ( [contact_list] => Array ( [cl_id] => 11111 [phone] => 999999999 [name] => Neu ) ) )
when i use $contact_listsin foreach loop it works with A since there are multiple array keys like 0,1,2,etc... but with B it shows error Warning: Illegal string offset 'name' etc.. since there are no array key like 0,1,2,etc...
so parsing the xml is automatically removing the key numbering which causing the the issue.
1- is there a way to keep the key numbering if only one array?
2- tried to use if (count($contact_lists) >= 1) { , but its not working as well..
Any idea for a workaround to solve such issue ?
SOLUTION:
$contact_lists_found = isset($array['contact_lists']['contact_list']) ? $array['contact_lists']['contact_list'] : '';
if ($contact_lists_found !== '' ) {
if (array_key_exists('0', $contact_lists_found)) {
// more than contact list
$contact_lists = $array['contact_lists']['contact_list'];
} else {
// only one contact list
$contact_lists[0] = $array['contact_lists']['contact_list'];
}
} else {
$contact_lists = array();
}
You could just check, if the key 0 is set, and if not, then simply overwrite the element contact_list with itself wrapped into an array:
if(!isset($array['message']['contact_lists']['contact_list'][0])) {
$array['message']['contact_lists']['contact_list'] = [
$array['message']['contact_lists']['contact_list']
];
}
0 is not a valid tag name in XML, so you should never get that, unless there was more than one <contact_list> in the XML.

In PHP how can I read subvalue of an XML line? [duplicate]

Sorry if this seems like an easy question, but I've started pulling hair out on this...
I have a XML file which looks like this...
<VAR VarNum="90">
<option>1</option>
</VAR>
I'm trying to get the VarNum.
So far I've been successful using the follow code to get the other information:
$xml=simplexml_load_file($file);
$option=$xml->option;
I just can't get VarNum (the attribute value I think?)
Thanks!
You should be able to get this using SimpleXMLElement::attributes()
Try this:
$xml=simplexml_load_file($file);
foreach($xml->Var[0]->attributes() as $a => $b) {
echo $a,'="',$b,"\"\n";
}
That will show you all the name/value attributes for the first foo element. It's an associative array, so you can do this as well:
$attr = $xml->Var[0]->attributes();
echo $attr['VarNum'];
What about using $xml['VarNum'] ?
Like this :
$str = <<<XML
<VAR VarNum="90">
<option>1</option>
</VAR>
XML;
$xml=simplexml_load_string($str);
$option=$xml->option;
var_dump((string)$xml['VarNum']);
(I've used simplexml_load_string because I've pasted your XML into a string, instead of creating a file ; what you are doing with simplexml_load_file is fine, in your case !)
Will get you
string '90' (length=2)
With simpleXML, you access attributes with an array syntax.
And you have to cast to a string to get the value, and not and instance of SimpleXMLElement
For instance, see example #5 of Basic usage in the manual :-)
[0] => Array
(
[#attributes] => Array
(
[uri] => https://abcd.com:1234/abc/cst/2/
[id] => 2
)
[name] => Array
(
[first] => abcd
[last] => efg
)
[company] => abc SOLUTION
[email] => abc#xyz.com
[homepage] => WWW.abcxyz.COM
[phone_numbers] => Array
(
[phone_number] => Array
(
[0] => Array
(
[main] => true
[type] => work
[list_order] => 1
[number] => +919876543210
)
[1] => Array
(
[main] => false
[type] => mobile
[list_order] => 2
[number] => +919876543210
)
)
)
[photo] => Array
(
[#attributes] => Array
(
[uri] => https://abcd.com:1234/abc/cst/2/cust_photo/
)
)
)
I applied the below code
$xml = simplexml_load_string($response);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
print_r($array);
but it is not use full i want all the data in single array in php
Try this
$xml->attributes()['YourPropertyName']; //check property case also

Pull data from PHP array based on a given infromation

I am trying to pull ImageUrl's, Lat and Long from a php array where I provide the HotelCode: $hotelCode
My XML file looks like the code below:
<Hotels>
<Hotel>
<HotelCode>Code<HotelCode>
<Latitude>Lat</Latitude>
<Longitude>Long</Longitude>
<HotelImages>
<ImageURL>file.jpg</ImageURL>
<ImageURL>file2.jpg</ImageURL>
....
</HotelImages>
</Hotel>
....
</Hotels>
My PHP code is :
$xmlstring = file_get_contents($xmlurl);
$xml = simplexml_load_string($xmlstring);
$json = json_encode($xml);
$hotels = json_decode($json,TRUE);
print_r($hotels) is:
Array (
[Hotel] => Array (
[0] => Array (
[HotelCode] => ES002A
[comment] => Array (
[0] => Array ( ) )
[Latitude] => 37.396792
[Longitude] => -5.992054
[HotelImages] => Array (
[ImageURL] => Array (
[0] => http://image.metglobal.com/hotelimages/ES002A/9405329_0x0.jpg
[1] => http://image.metglobal.com/hotelimages/ES002A/9405330_0x0.jpg
[2] => http://image.metglobal.com/hotelimages/ES002A/9405331_0x0.jpg
)
)
)
print_r($hotelCodes) is
Array ( [0] => ESG56G [1] => ES0Z10 )
I have tried some diferent methods but none of them worked.
Well, first off you have an error in your xml.
<HotelCode>Code<HotelCode>
Should be:
<HotelCode>Code</HotelCode>
After that you can get the images with:
$hotels['Hotel']['HotelImages']['ImageURL'][0];
and
$hotels['Hotel']['HotelImages']['ImageURL'][0];
And the lat long respectivly:
$hotels['Hotel']['Latitude'];
$hotels['Hotel']['Longitude'];
You can loop around the [Hotel] array with a foreach and check if the [HotelCode] element is equal to the one you provided and return the lat and long properties after that.
foreach ($hotels as $hotel) {
if($hotel['HotelCode'] == 'YourCode'){
echo $hotel['Latitude'];
echo $hotel['Longtitude'];
}
}
Use array_keys
$hotelCodes = array_keys($hotels, "HotelCode");
This will return all values with key "HotelCode". Then you can loop the array with these values.
foreach ($hotelCodes as $code)
{
$iUrls = $hotels[$code]['HotelImages']['ImageURL'];
foreach ($iUrls as $iUrl)
{
echo $iUrl;
}
echo $hotels[$code]['Latitude'];
echo $hotels[$code]['Longitude'];
}

Loading XML using SimpleXML doesn't return attributes on some elements

I have loaded an XML file using
simplexml_load_file($filePath,'SimpleXMLElement', LIBXML_NOCDATA);
And for most of the XML provided it works fine. However, for some of the elements in the XML the attributes are not converted into an '#attributes' array, and are instead missing form the output. Here's a sample:
<UI_DEFINITION>
<EDIT_PERMISSION>testPermission</EDIT_PERMISSION>
<DEFAULT_VALUES>
<display>hidden</display>
<css_class>generic_css_class</css_class>
<title>{tag}</title>
<type>string</type>
<wrapper_format>{value}</wrapper_format>
<full_path>false</full_path>
<mandatory>false</mandatory>
<edit_permission>testPermission</edit_permission>
<max_length>0</max_length>
</DEFAULT_VALUES>
<LOOKUPS>
<DB_LOOKUP name="test3">
<VIEW>???</VIEW>
<ID_FIELD>???</ID_FIELD>
<DESCR_FIELD>???</DESCR_FIELD>
<ORDER>??? asc</ORDER>
</DB_LOOKUP>
<DB_LOOKUP name="test1">
<VIEW>???</VIEW>
<ID_FIELD>???</ID_FIELD>
<DESCR_FIELD>???</DESCR_FIELD>
<ORDER>??? asc</ORDER>
</DB_LOOKUP>
</LOOKUPS>
<AREA internal_name="main_details" title="" display="show">
<FIELD lookup="test1" title="Title">Title</FIELD>
<FIELD title="Name">Given_Name</FIELD>
<FIELD title="Mid. Name(s)">Middle_Names</FIELD>
<FIELD title="Family Name">Family_Name</FIELD>
<FIELD title="Gender">Gender</FIELD>
<FIELD title="Born" type="date">Date_of_Birth</FIELD>
<FIELD max_length="20" title="ID">Unique_Identifier</FIELD>
</AREA>
This gives the following output from print_r (I've added a line break at the bit that's the problem):
SimpleXMLElement Object ( [UI_DEFINITION] => SimpleXMLElement Object ( [EDIT_PERMISSION] => testPermission [DEFAULT_VALUES] => SimpleXMLElement Object ( [display] => hidden [css_class] => generic_css_class [title] => {tag} [type] => string [wrapper_format] => {value} [full_path] => false [mandatory] => false [edit_permission] => testPermission [max_length] => 0 ) [LOOKUPS] => SimpleXMLElement Object ( [DB_LOOKUP] => Array ( [0] => SimpleXMLElement Object ( [#attributes] => Array ( [name] => test3 ) [VIEW] => ??? [ID_FIELD] => ??? [DESCR_FIELD] => ??? [ORDER] => ??? asc ) [1] => SimpleXMLElement Object ( [#attributes] => Array ( [name] => test1 ) [VIEW] => ??? [ID_FIELD] => ??? [DESCR_FIELD] => ??? [ORDER] => ??? asc ) ) )
[AREA] => SimpleXMLElement Object ( [#attributes] => Array ( [internal_name] => main_details [title] => [display] => show ) [FIELD] => Array ( [0] => Title [1] => Given_Name [2] => Middle_Names [3] => Family_Name [4] => Gender [5] => Date_of_Birth [6] => Unique_Identifier ) ) ) )
As you can see, the attributes array is correctly added to most of the elements, but not to the FIELD elements. I've tried renaming them and it didn't seem to make a difference.
EDIT:
I should also add that I've tried surrounding the FIELD tags with a FIELDS tag, also to no avail.
EDIT:
I've simplified the XML hugely, and it still doesn't return anny attributes:
<UI_DEFINITION>
<FIELD lookup="test1" title="Title">Title</FIELD>
</UI_DEFINITION>
produces:
SimpleXMLElement Object ( [UI_DEFINITION] => SimpleXMLElement Object ( [FIELD] => Title ) )
The attributes are accessible, for example:
$obj = simplexml_load_string($xml);
foreach($obj->AREA->FIELD as $field)
{
echo $field->attributes()->title . '<br />';
}
print_r() does not always show the full structure with SimpleXML, but the attributes are there for use.
Sorry it's taken so long to come back and answer this question!
As MrCode suggested, the attributes were accessible. The problem I was in the serialisation of the SimpleXML object into another format. Using printr or json_convert on the while object resulted in the attributes not being available in the cases reported.
I didn't go far enough into this to find a code-based workaround for printing or converting these objects including the problematic cases, I simply worked around it as part of the XML data:
<UI_DEFINITION>
<FIELD lookup="test1" title="Title"><VALUEPATH>Title</VALUEPATH></FIELD>
</UI_DEFINITION>
Addint this extra level into the hierarchy resulted in the attributes being preserved at the top level, and the text value being available correctly at the sub-level.

simplexml_load_string loose data

I'm currently using file_get_contents to get an xml.
It work well and when I display the xml with the correct MIME type header('Content-type: text/xml') I obtain something like this :
<?xml version="1.0" encoding="iso-8859-1" ?>
<tarification compagnie="banane" cle="laclef">
<gamme reference="equilibre-sante">
<tarif formule="f100">Xx.xx</tarif>
<tarif formule="f200">Xx.xx</tarif>
</gamme>
</tarification>
To use it as an object I use simplexml_load_string but when I print_r the returned object I didn't see the formule attribute I just see something like this :
SimpleXMLElement Object
(
[#attributes] => Array
(
[compagnie] => banane
[cle] => laclef
)
[gamme] => Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[reference] => equilibre-sante
)
[tarif] => Array
(
[0] => Xx.xx
[1] => Xx.xx
)
)
)
)
I want to get formule attributes, I have already tested to do this by following this tutorial without success.
You need to use the SimpleXMLElement::attributes as:
$xml = simplexml_load_string($xmlstring);
foreach($xml->gamme->tarif as $tarif) {
foreach($tarif->attributes() as $a => $b) {
echo $a,'="',$b,"\"\n";
}
}
See it

Categories