php xml parsing with attributes - php

I have some XML that looks like this
$xml_str = '<RESPONSE>
<FIELDS>
<FIELD KEY="A">1</FIELD>
<FIELD KEY="B">2</FIELD>
<FIELD KEY="C">3</FIELD>
<FIELD KEY="D">4</FIELD>
</FIELDS>
</RESPONSE>';
There is only ever going to be 1 "FIELDS" in the response. Is there a easy way I can put the "FIELD" elements in a array with the keys being the "KEY" and the value being the element value?
I could do this
$xml_data = simplexml_load_string($xml_str);
foreach ($xml_data->FIELDS->FIELD as $field) {
foreach ($field->attributes() as $a => $b) {
$array[$b] = $field[0];
}
}
But I'm wondering if there is a better way?
TIA

Related

Displaying data via PHP and SimpleXML problem

I have gone through a lot of the SimpleXML questions on this site. My data is a bit strange and I cannot change that. I am trying to get things like 'Building1' and 'Hostname1' from my data, so I can take that data and look up other data, then display it.
Here is a sample of my data:
<?xml version='1.0' encoding='UTF-8'?>
<results preview = '0'>
<result offset='0'>
<field k='hostname'>
<value h='1'><text>Hostname 1</text></value>
</field>
<field k='os'>
<value><text>Windows 7</text></value>
</field>
<field k='location'>
<value h='1'><text>Building 1</text></value>
<field>
</result>
<result offset='1'>
<field k='hostname'>
<value h='1'><text>Hostname 2</text></value>
</field>
<field k='os'>
<value><text>Windows 10</text></value>
</field>
<field k='location'>
<value h='1'><text>Building 2</text></value>
</field>
</result>
........
And here is how I am trying to look at it:
$xml = simplexml_load_file(data.xml);
print_r($xml);
$testArray = new SimpleXMLElement($xml);
$records = $testArray->results->result;
print_r($records);
For some reason I just cannot figure out how to get the data from the xml elements. If anyone can point me in the right direction, I'd appreciate it. I've tried many, many options. Thanks-
This is a really common mistake, but a really hard one to spot if you don't know what you're looking for: the first object you get back when parsing with XML is the root element, not something representing the document.
So in your case, $testArray is the element <results preview = '0'>, and you want $testArray->result not $testArray->results->result.
By the way, "testArray" is a bad name for this variable - it's not an array, it's an object.
I used xml as string in file
<?php
$sXmlString = <<<EOF
<?xml version="1.0" encoding="UTF-8"?>
<results preview = "0">
<result offset="0">
<field k="hostname">
<value h="1"><text>Hostname 1</text></value>
</field>
<field k="os">
<value><text>Windows 7</text></value>
</field>
<field k="location">
<value h="1"><text>Building 1</text></value>
</field>
</result>
<result offset="1">
<field k="hostname">
<value h="1"><text>Hostname 2</text></value>
</field>
<field k="os">
<value><text>Windows 10</text></value>
</field>
<field k="location">
<value h="1"><text>Building 2</text></value>
</field>
</result>
</results>
EOF;
echo '<pre>';
$xml = simplexml_load_string($sXmlString);
print_r($xml);
echo '<hr/>';
echo count($xml->result);
echo '<hr/>';
foreach($xml->result as $report)
{
var_dump($report);
echo '<hr/>';
}
In the code you can see $xml it self reference to the "results" (or root) element.
You need to travel from the root to child elements. $xml->result will give the result object in the results set and you need to go for loop as it as array of objects.

Accessing a specific XML element using xpath in PHP 7.x

Ok so I have some XML data.
$mydata = <<<XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE fmresultset PUBLIC "-//FMI//DTD fmresultset//EN" "https://HIDDEN:443/fmi/xml/fmresultset.dtd">
<fmresultset xmlns="http://www.filemaker.com/xml/fmresultset" version="1.0">
<resultset count="1" fetch-size="1">
<record mod-id="27" record-id="754">
<field name="a_Constant_c">
<data>1</data>
</field>
<field name="a_Sch_ID_pk">
<data>100060</data>
</field>
<field name="a_SchoolHead_pk">
<data>100060_1</data>
</field>
<field name="b___Data_____________">
<data/>
</field>
<field name="b_1Name_School_Code_t">
<data>PJA</data>
</field>
<field name="b_1Name_School_t">
<data>Palmetto</data>
</field>
<field name="b_1Name_SchoolHead_t">
<data>John Doe</data>
</field>
<field name="b_Ad_Address1_t">
<data/>
</field>
<field name="b_Ad_Address2_t">
<data>123 Main St.</data>
</record>
</resultset>
</fmresultset>
XML;
Now what I want to do is basically be able to read the value of the data from a specific field and assign it to a variable.
So far I have something like this...
$xml = simplexml_load_string($mydata);
Now I want to be able to assign let's say the data in the field name b_1Name_School_Code_t (which is PJA)
So I think it should be something like this
$school = $xml->resultset->record->field->data;
echo "School Name: ".$school;
Then I would like to see on the screen
School Name: PJA
So what I am missing to be able to make this happen?
You are only getting to the first field element in your example, which is why you get 1. Instead, loop through all the field elements, and stop when you get to the one you need:
$xml = simplexml_load_string($mydata);
$fields = $xml->resultset->record->field;
foreach ($fields as $field) {
if ((string) $field->attributes()->name === "b_1Name_School_Code_t") {
echo "School name: ".$field->data; // School name: PJA
break;
}
}
Demo
I use SimpleXMLElement::attributes() to get the name attribute of the element (note the cast to string, otherwise you get an SimpleXMLElement)
However, it would make more sense to use XPath to go directly to the element you're after:
$xml = simplexml_load_string($mydata);
$xml->registerXPathNamespace("fmresultset", "http://www.filemaker.com/xml/fmresultset");
$node = $xml->xpath("//fmresultset:resultset/fmresultset:record/fmresultset:field[#name='b_1Name_School_Code_t']");
var_dump($node[0]->data); // PJA
Demo
Notice the namespace registration and the accessing of the first element, since xpath() returns an array of SimpleXMLElements

PHP and XML: getElementByType

I'm somewhat new to php and I'm trying to loop through my XML file in order to extract data and display it in HTML. I know how to do the display to HTML part, but I'm a little confused for what to do for the XML part.
Here is a sample file of what I am trying to do (you can picture it as a categorized list of movies where groupType would be genre):
<mainGroup>
<groupHeading type="heading">This is a sample heading</groupHeading>
<group type="groupType1">
<title>Title1</title>
<date when="0001"></date>
</group>
<group type="groupType1">
<title>Title2</title>
<date when="0002"></date>
</group>
<group type="groupType2">
<title>Title3</title>
<date when="0003"></date>
</group>
</mainGroup>
... There are more mainGroups with differet group types etc
Basically, I will have 10+ mainGroups, with many different groups inside of it, so I need a way to loop through these using php. The main problem is the fact that I need someway to "getElementBy Type()", but that does not exist.
If anything is confusing, I can elaborate more, I'm still a novice to php so I hope I can do this.
real simple --> use PHP's simplexml ---> live demo: http://codepad.viper-7.com/i4MRGI
$xmlstr = '<mainGroup>
<groupHeading type="heading">This is a sample heading</groupHeading>
<group type="groupType1">
<title>Title1</title>
<date when="0001"></date>
</group>
<group type="groupType1">
<title>Title2</title>
<date when="0002"></date>
</group>
<group type="groupType2">
<title>Title3</title>
<date when="0003"></date>
</group>
</mainGroup>';
// create simplexml object
$xml=simplexml_load_string($xmlstr);
// loop through all <groupheading>, we use an xpath-query...
foreach ($xml->xpath("//groupHeading") as $gh) {
echo($gh),'<br />';
}
// now the titles under every group with groupType1...
foreach ($xml->xpath("//group[#type='groupType1']/title") as $gt1) {
echo $gt1,'<br />';
}
EDIT: echo title of each groupHeading, then titles of child-nodes if grouptype=1:
---> see new demo: http://codepad.viper-7.com/eMuyr5
foreach ($xml->groupHeading as $gh) {
echo($gh),'<br />';
foreach ($gh->xpath("//group[#type='groupType1']/title") as $gt1) {
echo $gt1,'<br />';
}
}
You could use PHP DOM
If you wanted to search groups for a particular type and then get the results you could do something like this:
EDIT - $string would be your XML. If you needed to load it from a file you can do
$string = file_get_contents('/path/to/your/file');
$dom = new DOMDocument;
$dom->loadXML($string);
$searchtype = "groupType1";
$results = array();
$groups = $dom->getElementsByTagName('group');
foreach( $groups as $g ) {
if( $g->getAttribute('type') == $searchtype ) {
$results[] = array(
'title' =>$g->getElementsByTagName('title')->item(0)->nodeValue,
'date' =>$g->getElementsByTagName('date')->item(0)->getAttribute('when')
);
}
}
print_r($results);

php simplexml find value of a specific field

The XML, I have:
<?xml version="1.0" encoding="windows-1252" ?>
- <Tables>
- <Table name="I_BOOKING">
- <Row action="UPDATE" success="Y">
<Field name="AUTOBOOK">888800</Field>
<Field name="TOUROP">01</Field>
<Field name="REFERENCE">GSDFFD</Field>
<Field name="NBPAX">2</Field>
<Field name="NBINF">1</Field>
</Row>
</Table>
- <Table name="I_EXCDATERESA">
- <Row action="UPDATE" success="Y">
<Field name="EXCURS">KNO</Field>
<Field name="DATE">2012-04-12</Field>
<Field name="BOOKNR">125445</Field>
<Field name="NAME">TEST 12/4</Field>
<Field name="PICKUPTIME">00:00:00</Field>
</Row>
- <Row action="UPDATE" success="Y">
<Field name="EXCURS">KNO</Field>
<Field name="DATE">2012-04-13</Field>
<Field name="BOOKNR">14574575</Field>
<Field name="NAME">TEST 13/4</Field>
<Field name="PICKUPTIME">00:00:00</Field>
</Row>
</Table>
</Tables>
When I treat the table I_EXCDATERESA, I need to get the value of Field BOOKNR, so 125445 or 14574575 in this example, according to the row I am dealing with and load it in $autobook:
...
$simplexml = simplexml_import_dom($dom);
foreach ($simplexml->Table as $value)
{
$tableName = $value->attributes()->name;
foreach ($value->Row as $value)
{
if ($tableName == 'I_EXCDATERESA')
{
if ($value->Field->attributes()->name == 'BOOKNR')
{
$autoBook = $value->Field;
This is not working, $autobook is not loaded, as it is not on the first 'Field' but on the third
This is a great use case for XPath:
$search = $simplexml->xpath('/Tables/Table[name="I_EXCDATERESA"]/Row/Field[name="BOOKNR"]');
Test this, it worked for me:
foreach ($simplexml->Table as $value)
{
$tableName = $value->attributes()->name;
foreach ($value->Row as $value_1)
{
if ($tableName == 'I_EXCDATERESA')
{
foreach ($value_1->Field as $value_2)
{
if ($value_2->attributes()->name == 'BOOKNR')
{
$autoBook = $value_2[0];
echo $autoBook;
}
}
}
}
}
Your problem is with:
$value->Field->attributes()->name=='BOOKNR'
That's too much: I added another cycle on each field of elemts Row!
well there are couple of ways to approach this situation
using DOM
using the attribute() function inside simplexml which was covered here
and probably the easiest option is noticing that BOOKNER is the third node in every Row
I would do something like this.
for ($i = 0; $i < count($simplexml->->children()); $i++){
echo $simplexml->Table[$i]->Table->Field[2];
}
good luck
$simplexml->xpath('/Tables/Table[name="I_EXCDATERESA"]/Row/Field[name="BOOKNR"]');
does'nt work, you missed the #
$simplexml->xpath('/Tables/Table[#name="I_EXCDATERESA"]/Row/Field[#name="BOOKNR"]');

Select xml node by attribute in php [duplicate]

This question already has answers here:
SimpleXML: Selecting Elements Which Have A Certain Attribute Value
(2 answers)
Closed 2 years ago.
How do I find the node value by knowing the attribute value without traversing through every child and every attribute/value ?
$dom = new DOMDocument;
$dom->load('test.xml');
$rows = $dom->getElementsByTagName('row');
foreach ($rows as $row) {
$header = VALUE OF <field name="header">
$text = VALUE OF <field name="text">
}
XML:
<resultset>
<row>
<field name="item">2424</field>
<field name="header">blah blah 1</field>
<field name="text" xsi:nil="true" />
...
</row>
<row>
<field name="item">5321</field>
<field name="header">blah blah 2</field>
<field name="text">some text</field>
...
</row>
</resultset>
The simplest thing to do is use DOMXPath::querydocs
The following code finds all the <field> nodes within <row> nodes that have a name attribute equal to "header":
$dom = new DOMDocument;
$dom->loadXML($str); // where $str is a string containing your sample xml
$xpath = new DOMXPath($dom);
$query = "//row/field[#name='header']";
$elements = $xpath->query($query);
foreach ($elements as $field) {
echo $field->nodeValue, PHP_EOL;
}
Using the sample xml you provide, the above outputs:
blah blah 1
blah blah 2

Categories