access data attributes using simpleXML - php

I am using an API to get a Block FIPS number but I have not been able to target that specific number within the XML file.
I did a print_r() on the xml output and here is what I get
SimpleXMLElement Object ( [#attributes] => Array ( [status] => OK [executionTime] => 6 ) [Block] => SimpleXMLElement Object ( [#attributes] => Array ( [FIPS] => 060730200252015 ) ) [County] => SimpleXMLElement Object ( [#attributes] => Array ( [FIPS] => 06073 [name] => San Diego ) ) [State] => SimpleXMLElement Object ( [#attributes] => Array ( [FIPS] => 06 [code] => CA [name] => California ) ) )
Here is the XML that is being generated
<Response xmlns="http://data.fcc.gov/api" status="OK" executionTime="10">
<Block FIPS="060730200252015"/>
<County FIPS="06073" name="San Diego"/>
<State FIPS="06" code="CA" name="California"/>
</Response>
I have been trying to get the Block FIPS Number like this:
$fccAPI = "http://data.fcc.gov/api/block/2010/find?latitude=$lat&longitude=$lng";
//echo $fccAPI;
$fccXML= simplexml_load_file($fccAPI);
print_r($fccXML);
//Echo FIPS Number
echo $fccXML->FIPS;
Please help me target the Block FIPS number.

You need to use the following:
echo $fccXML->Block[0]['FIPS'];
$fccXML is the root node, the <Response> element. ->Block[0] selects the first Block element, and to access an attribute, use the square brackets notation with the attribute name, i.e. ['FIPS'].
The SimpleXML documentation has numerous examples if you're having trouble with the syntax.

Related

SimpleXML Skipping Attributes

Test XML:
<?xml version="1.0" encoding="UTF-8"?>
<Transfer>
<ABR recordLastUpdatedDate="20180329" replaced="N">
<ABN status="ACT" ABNStatusFromDate="20000214">80007321682</ABN>
<EntityType>
<EntityTypeInd>PUB</EntityTypeInd>
<EntityTypeText>Australian Public Company</EntityTypeText>
</EntityType>
<MainEntity>
<NonIndividualName type="MN">
<NonIndividualNameText>BLACK CABS COMBINED PTY LTD</NonIndividualNameText>
</NonIndividualName>
<BusinessAddress>
<AddressDetails>
<State>VIC</State>
<Postcode>3166</Postcode>
</AddressDetails>
</BusinessAddress>
</MainEntity>
</ABR>
</Transfer>
PHP Script:
$f='test.xml';
$reader=new XMLReader();
$reader->open($f);
while($reader->read()){
if($reader->nodeType==XMLReader::ELEMENT && $reader->name=='ABR'){
$doc=new DOMDocument('1.0','UTF-8');
$xml=simplexml_import_dom($doc->importNode($reader->expand(),true));
print_r($xml);
}
}
$reader->close();
PHP Output:
SimpleXMLElement Object
(
[#attributes] => Array
(
[recordLastUpdatedDate] => 20180329
[replaced] => N
)
[ABN] => 80007321682
[EntityType] => SimpleXMLElement Object
(
[EntityTypeInd] => PUB
[EntityTypeText] => Australian Public Company
)
[MainEntity] => SimpleXMLElement Object
(
[NonIndividualName] => SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => MN
)
[NonIndividualNameText] => BLACK CABS COMBINED PTY LTD
)
[BusinessAddress] => SimpleXMLElement Object
(
[AddressDetails] => SimpleXMLElement Object
(
[State] => VIC
[Postcode] => 3166
)
)
)
)
The Problem:
The attributes for the ABN element (status and ABNStatusFromDate) are not in the output, even though other attributes are.
Please help me understand why those attributes in particular are missing.
PS - Dummy text so SO doesn't give me warnings about my post being mostly code
Answer: print_r is not meant to be used to display a SimpleXML object.
I can access the attribute directly via $xml->ABN['status'].

SimpleXML to Array

I load some XML which produces a SimpleXML Object like so (only displaying one Object)
SimpleXMLElement Object
(
[Jobs] => SimpleXMLElement Object
(
[Job] => Array
(
[0] => SimpleXMLElement Object
(
[ID] => J000001
[Name] => Internal Time
[Description] => Use this job to record your internal and non-billable time for activities such as annual leave, sick leave, professional development, staff meetings etc
[Client] => SimpleXMLElement Object
(
[ID] => 8430219
[Name] => Fake Client
)
[ClientOrderNumber] => SimpleXMLElement Object
(
)
[State] => Planned
[StartDate] => 2016-03-21T00:00:00
[DueDate] => 2017-03-21T00:00:00
[InternalID] => 11442733
[Assigned] => SimpleXMLElement Object
(
[Staff] => SimpleXMLElement Object
(
[ID] => 344460
[Name] => Som Name
)
)
)
)
)
)
What I would like to do is create an array of the client Name and client ID. So I am aiming for something like so
[data] => array (
8430219 => Fake Client,
8430343 => Another Client,
etc
)
At the moment, I can get the name in place, but struggling with the id because it says it is an illegal offset type. This is what I have
foreach($oXML->Jobs as $oEntry) {
foreach ($oEntry->Job as $data) {
$jobsArray = array(
$data->Client->ID => $data->Client->Name
);
}
}
How can I create the array based on the SimpleXML Object I have?
Thanks
First of all, to obtain your desired array you can not use this syntax:
$jobsArray = array( $key => $val );
You have to use something like this:
$jobsArray[$key] = $val;
Otherwise, at each repeating loop, your syntax will override precedent array values.
Then, I suggest you to use XPath to simplify entire process. With XPath queries, you can retrieve a set of nodes with only one search.
Assuming you have this XML:
<?xml version="1.0"?>
<Jobs>
<Job>
<Client>
<ID>8430219</ID>
<Name>Fake Client</Name>
</Client>
<Client>
<ID>8430220</ID>
<Name>Fake Client 2</Name>
</Client>
</Job>
<Job>
<Client>
<ID>8430221</ID>
<Name>Fake Client 3</Name>
</Client>
</Job>
</Jobs>
With this xpath query:
$clients = $oXML->xpath( '/Jobs/Job/Client' );
you obtain in $clients all <Client> nodes. Then you can create your array in this way:
$result = array();
foreach( $clients as $client )
{
$result[$client->ID->__toString()] = $client->Name->__toString();
}
This is $result after foreach loop:
Array
(
[8430219] => Fake Client
[8430220] => Fake Client 2
[8430221] => Fake Client 3
)
Note that we have to cast as string single nodes (that are SimpleXML objects): this is absolutely necessary creating keys, otherwise the array assignment fails. You can obtain same result using (string) $client->ID instead of $client->ID->__toString()
Read more about SimpleXMLElement::xpath
Read more about XPath

PHP SimpleXML xpath query results

I have searched for this and the answers I find seem to say what I thought I understand. Obviously I am missing something. I am confused at the results from the xPath query. I have simplified my problem for a test case to post here.
My real xml has several dataset nodes at different depths. Ultimately, I want to get every dataset element with a given label and then loop over that and get the field values (at different locations (or depths) so I think I need xpath). I can use xpath to get the dataset elements that I want successfully. However, when I then run xpath on that result object, it gets me the fields I want and all the other fields too. I can't figure out why it isn't only returning field1, field2, and field3. When I print_r($value[0]), it shows only the fields I want. But, when I run xpath on $value[0], it returns all fields in the xml doc.
Sample XML
<myxml>
<dataset label="wanteddata" label2="anotherlabel">
<dataitem>
<textdata>
<field label="label1">field1</field>
<field label="label2">field2</field>
<field label="label3">field3</field>
</textdata>
</dataitem>
</dataset>
<dataset label="unwanteddata" label2="unwantedanotherlabel">
<dataitem>
<textdata>
<field label="label4">field4</field>
<field label="label5">field5</field>
<field label="label6">field6</field>
</textdata>
</dataitem>
</dataset>
</myxml>
Here is the test code.
$xmlstring = file_get_contents('simplexml_test.xml');
$xml = simplexml_load_string($xmlstring);
if ($xml === false) {
throw new Exception("Failed to load");
}
$value = $xml->xpath('//dataset[#label="wanteddata"]');
print_r($value[0]->xpath('//field'));
Code Output:
Array
(
[0] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label1
)
)
[1] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label2
)
)
[2] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label3
)
)
[3] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label4
)
)
[4] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label5
)
)
[5] => SimpleXMLElement Object
(
[#attributes] => Array
(
[label] => label6
)
)
)
//field selects all <field> elements within the entire XML document regardless of the context node from which you call that XPath. To make the XPath heed the context node, you need to add a dot (.) at the beginning of the XPath. In XPath, (.) references current context node :
print_r($value[0]->xpath('.//field'));

PHP XML xlink:href Attributes [duplicate]

This question already has answers here:
Simple XML - Dealing With Colons In Nodes
(4 answers)
Closed 8 years ago.
I'm having trouble reading attributes from the Spreadshirt API with SimpleXML. I can't grab the xlink:href attribute from resources, which is what I need as it's not displays in the data received. Seem to be able to grab everything else, though.
This is the XML I'm reading in:
<articles xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://api.spreadshirt.net" xlink:href="http://api.spreadshirt.net/api/v1/shops/800323/articles?fullData=true" offset="0" limit="50" count="16" sortField="default" sortOrder="default">
<article isDuplicate="false" xlink:href="http://api.spreadshirt.net/api/v1/shops/800323/articles/100402428" id="100402428">
<name>Hammer T-Shirt</name>
<price>
<vatExcluded>13.33</vatExcluded>
<vatIncluded>16.00</vatIncluded>
<vat>20.00</vat>
<currency xlink:href="http://api.spreadshirt.net/api/v1/currencies/2" id="2"/>
</price>
<resources>
<resource mediaType="png" type="preview" xlink:href="http://image.spreadshirt.net/image-server/v1/products/125642560/views/1"/>
</resources>
</article>
</atricles>
This is the data coming back from SimpleXML:
SimpleXMLElement Object
(
[#attributes] => Array
(
[isDuplicate] => false
[id] => 27368595
)
[name] => Hammer Boxers
[price] => SimpleXMLElement Object
(
[vatExcluded] => 10.00
[vatIncluded] => 12.00
[vat] => 20.00
[currency] => SimpleXMLElement Object
(
[#attributes] => Array
(
[id] => 2
)
)
)
[resources] => SimpleXMLElement Object
(
[resource] => SimpleXMLElement Object
(
[#attributes] => Array
(
[mediaType] => png
[type] => preview
)
)
)
)
Does anyone have any ideas? I'm stumped.
The isDuplicate and id attributes are in the same namespace as the element.
The href element is in the http://www.w3.org/1999/xlink namespace, as indicated by the xlink prefix that is registered on the <articles> root element.
To access all the elements for the namespace, call $element->attributes('http://www.w3.org/1999/xlink').
The idea is that the root element could instead say xmlns:foobar="http://www.w3.org/1999/xlink", and each <article> would have foobar:href="..." attributes, and the code above would still work, because the bound prefix is just a way of improving readability. What counts is the namespace URL, not its prefix.

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.

Categories