SimpleXML Lower level variable - php

I'm parsing a file with simple_xml_load_file(), level by level. Here's the sample structure:
<person name="Joe Smith" ...>
<info age="19">
<height val="1.85" />
</info>
<info age="19">
<weight val="82" />
</info>
<info age="19">
<build val="14" />
</info>
</person>
...
As I am parsing I am not going deep, as I don't need to. I do need the age however, without going through each info tag. I need the variables contained in <person> and only the age. How would I go about getting age without another loop?
$persons=$dom->person;
foreach($persons as $person){
$name=$person['name'];
$age=????
}

This should do the job:
foreach($dom->person as $person){
$name=$person['name'];
foreach($person->info as $info) {
echo $info['age'] . '<br>';
}
}
Or if you want to get one age at a specific position:
echo $person->info[0]['age']; // Gets age attribute of first <info> node

Related

Count how many children are in XML with PHP

i know a few about php, so sorry for the question:
i have this file xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<alert>
<status> </status>
<nothing> </nothing>
<info>
<area>
</area>
</info>
<info>
<area>
</area>
</info>
<info>
<area>
</area>
</info>
</alert>
i must do a for loop and inside a "foreach" for each
The problem is that i'm not sure what is a way to know how many times i had to repeat a for loop. Because in this file xml (that is an example) i don't know how many are
Is good if:
$url = "pathfile";
$xml = simplexml_load_file($url);
$numvulcani = count($xml->alert->info); // is good ?
for ($i = 0; $i <= $numvulcani; $i++) {
foreach ($xml->alert->info[$i] as $entry) {
$area = $entry->area;
}
}
is true ?
sorry for bad english
You need to use SimpleXMLElement::count function for this — It counts the children of an element.
<?php
$xml = <<<EOF
<people>
<person name="Person 1">
<child/>
<child/>
<child/>
</person>
<person name="Person 2">
<child/>
<child/>
<child/>
<child/>
<child/>
</person>
</people>
EOF;
$elem = new SimpleXMLElement($xml);
foreach ($elem as $person) {
printf("%s has got %d children.\n", $person['name'], $person->count());
}
?>
The output will be as follows :
Person 1 has got 3 children.
Person 2 has got 5 children.
Also take a look at this link : xml count using php
Try replacing foreach ($xml->alert->info[$i] as $entry) with:
foreach ($xml->alert->info[$i] as $j => $entry)
The current item index will be $j
You're perhaps overcomplicating this a bit as it's new to you.
First of all, you don't need to reference the alert root element like $xml->alert because the SimpleXMLElement named by the variable $xml represents that document element already.
And second, you don't need to count here, you can just foreach directly:
foreach ($xml->info as $info) {
echo ' * ', $info->asXML(), "\n";
}
This iterates over those three info elements that are children of the alert element.
I recommend the Basic SimpleXML usage guide in the PHP manual for a good start with SimpleXML.

PHP xpath get elements by attribute in foreach loop

im am trying to loop through all the LINE_ITEMS and it works fine but in the foreach-loop im trying to access the single LINE_ITEM by attribute by using xpath but i don't get any result. Does anyone know the problem ?
foreach($items = $xmlData->xpath('//zw:LINE_ITEM') as $item) {
$item->xpath('//namespace:PID[#type="erp_pid"]'); No result
}
$xmlData->xpath('//zw:LINE_ITEM')
works fine i get all LINE_ITEMS but
when i try to do some xpath on the item i don't get any result.
How can i access the PID value of for example "erp_pid" ?
<?xml version="1.0" encoding="UTF-8"?>
<NM_DOCS>
<NM_DOC>
<DOCUMENT qualifier="default" role="original" test="false" type="orders">
<VERSION>4.0</VERSION>
<HEADER>
<CONTROL_INFO>
<LAST_SAVE_DATE>2015-03-18T13:44:32+01:00</LAST_SAVE_DATE>
<PROCESS_TYPE>silent</PROCESS_TYPE>
<SOURCE>sales</SOURCE>
</CONTROL_INFO>
<SOURCING_INFO>
<REFERENCES>
<REFERENCE type="order_nexmart">
<ID>109546063</ID>
<DATES>
<DATE type="order">2015-03-18T13:44:30+01:00</DATE>
</DATES>
</REFERENCE>
</REFERENCES>
</SOURCING_INFO>
<DOCUMENT_INFO>
<DOCUMENT_ID>Test bestellnummer</DOCUMENT_ID>
<DATES>
<DATE type="delivery_ordered">2015-04-19T12:41:41+02:00</DATE>
</DATES>
<PARTIES>
<PARTY type="buyer">
<BUSINESS_ROLE>commercial</BUSINESS_ROLE>
<PORTAL_ID>BDE600028</PORTAL_ID>
<ADDITIONAL_IDS>
</ADDITIONAL_IDS>
<ADDRESS>
</ADDRESS>
<CONTACT_DETAILS>
<ACCOUNTS>
<ID type="emart">sales.nexmart</ID>
</ACCOUNTS>
</CONTACT_DETAILS>
</PARTY>
<PARTY type="supplier">
<BUSINESS_ROLE>commercial</BUSINESS_ROLE>
<PORTAL_ID>zweygart_app_de</PORTAL_ID>
<ADDITIONAL_IDS>
</ADDITIONAL_IDS>
<ADDRESS>
</ADDRESS>
<CONTACT_DETAILS>
</CONTACT_DETAILS>
</PARTY>
<PARTY type="delivery">
<BUSINESS_ROLE>commercial</BUSINESS_ROLE>
<ADDRESS>
</ADDRESS>
<CONTACT_DETAILS>
</CONTACT_DETAILS>
</PARTY>
<PARTY type="invoice_recipient">
<ADDRESS>
</ADDRESS>
<CONTACT_DETAILS>
</CONTACT_DETAILS>
</PARTY>
</PARTIES>
<REMARKS>
<REMARK type="order">Test bemerkung</REMARK>
</REMARKS>
</DOCUMENT_INFO>
</HEADER>
<LINE_ITEMS>
<LINE_ITEM>
<PRODUCT_ID>
<SUPPLIER_PID>119556</SUPPLIER_PID>
<GTIN>4030646269130</GTIN>
<ADDITIONAL_PIDS>
<PID type="supplier_pid_original">119556</PID>
<PID type="gtin_original">4030646269130</PID>
<PID type="erp_pid">119556</PID>
</ADDITIONAL_PIDS>
<DESCRIPTIONS>
<DESCR type="short">short desc</DESCR>
<DESCR type="short_original">some text</DESCR>
</DESCRIPTIONS>
</PRODUCT_ID>
</LINE_ITEM>
<LINE_ITEM>
<PRODUCT_ID>
<SUPPLIER_PID>123456789</SUPPLIER_PID>
<GTIN>123456789</GTIN>
<ADDITIONAL_PIDS>
<PID type="supplier_pid_original">123456</PID>
<PID type="gtin_original">123456</PID>
<PID type="erp_pid">123456</PID>
</ADDITIONAL_PIDS>
<DESCRIPTIONS>
<DESCR type="short">short desc</DESCR>
<DESCR type="short_original">Some description</DESCR>
</DESCRIPTIONS>
</PRODUCT_ID>
</LINE_ITEM>
</LINE_ITEMS>
</DOCUMENT>
</NM_DOC>
</NM_DOCS>
The problem is not XPath but SimpleXML. SimpleXMLElement::xpath() is limited. It converts the result into an array of SimpleXMLElement objects, but here are other nodes in a DOM. More important you will have to register the namespaces on each new SimpleXMLElement again.
$element = new SimpleXMLElement($xml);
$element->registerXPathNamespace('namespace', 'urn:foo');
foreach($element->xpath('//namespace:LINE_ITEMS/namespace:LINE_ITEM') as $item) {
$item->registerXPathNamespace('namespace', 'urn:foo');
var_dump((string)$item->xpath('.//namespace:PID[#type="erp_pid"]')[0]);
}
Output:
string(6) "119556"
string(6) "123456"
You might notice that I prefixed your detail expression with an .. A slash at the start of the expression always makes it relative to the document itself, not the current node. The . represents the current node.
If you use DOM directly, you create a separate DOMXPath object and register the namespaces on this object. Additionally you can use XPath expressions that return scalar values.
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('namespace', 'urn:foo');
foreach($xpath->evaluate('//namespace:LINE_ITEMS/namespace:LINE_ITEM') as $node) {
var_dump($xpath->evaluate('string(.//namespace:PID[#type="erp_pid"])', $node));
}
This works for me:
foreach($xmlData->LINE_ITEM as $item) {
$erp = ( $item->xpath('//PID[#type="erp_pid"]'));
foreach($erp as $v) {
echo $v. " / ";
}
}
Just remove the namespace in your xpath, your xml doesn't use a namespace.
If you want to iterate through a part of the xml be sure to use the correct path.

how to fetch the child node of a xml file if exists otherwise jump to next node using php

I have an XML file which is similar to following
<Navigation Name="Klengeräte">
<Market Type="Navigation"></Market>
<Navigation Name="Bodenpflege">
<Market Type="Navigation"></Market>
<Navigation Name="Wöchentches">
<Market Type="Navigation">
</Market>
<Navigation Name="Ultra One">
<personalinfo>
<Name> testing</Name>
<grade> A </grade>
<info> test information </info>
</personalinfo>
</Navigation>
</Navigation>
<personalinfo>
<Name> testing</Name>
<grade> A </grade>
<info> test information </info>
</personalinfo>
<personalinfo>
<Name> testing</Name>
<grade> A </grade>
<info> test information </info>
</personalinfo>
</Navigation>
</Navigation>
and I want to read the personal information tags in the XML
If there is any case issues please ignore,I have tried in many ways but I did not find correct solution.
You can do it by using DOMDocument to get the 'personalinfo' tag and iterating with foreach and DOMNode .
$parser = new DOMDocument();
$parser->loadXML($xml);
$infos = $parser->getElementsByTagName('personalinfo');
foreach($infos as $info) {
foreach($info->childNodes as $infoChild) {
echo $infoChild->nodeName . '====' . $infoChild->nodeValue . '<br>';
}
}
This is not a perfect solution, but it should get you started in the right direction. See http://codepad.viper-7.com/f4u9FC for an implementation with your xml.
Thanks for your help i got the solutions.
We can get the information of all personal tags using
foreach($temp_xml->xpath('//PersonalInformation') as $product_xml){
$name = $product_xml{'Name'};
$grade = $product_xml{'grade'};
}
In this way we can read any value. It worked for me.

PHP and Xpath, filtering results based on greatgrandchildren

Consider the following test.xml
<root>
<parent>
<ID>1</ID>
<child1>Value1</child1>
<child2>value11</child2>
<child3>
<grandchild>
<greatgrandchild>value1111</greatgrandchild>
</grandchild>
</child3>
</parent>
<parent>
<ID>2</ID>
<child1>value2</child1>
<child3>
<grandchild>
<greatgrandchild>value2222</greatgrandchild>
</grandchild>
</child3>
</parent>
<parent>
<ID>3</ID>
<child1>value3</child1>
<child2>value33</child2>
<child3>
<grandchild>
<greatgrandchild>value3333</greatgrandchild>
</grandchild>
</child3>
</parent>
<parent>
<ID>4</ID>
<child1>value4</child1>
<child2>value44</child2>
<child3>
<grandchild>
<greatgrandchild>value4444</greatgrandchild>
</grandchild>
</child3>
</parent>
</root>
When I use the following for xpath '/root/parent', I can easily get the values of ID, child1, and child2.
However I do not get the values of the greatgrandchild of grandchild.
What can I do to get these values.
$query = '/root/parent'
$xQuery = $xml->xpath($query);
foreach($xQuery as $results){
echo $results->ID;
echo $results->child1;
echo $results->child2;
echo $results->greatgrandchild;
}
I would like to filter the result based on the value of greatgrandchild. I can successfully filter the results of ID and child1 and child2. I want to be getting a parent and all of its children and grandchildren and greatgrandchild based on the value of greatgrandchild.
Is this possible using xpath?
I have edited the wording of the question and used the proper test.xml as I had errors in it the first time around.
There are 2 problems in your code,
grandchild node is ambiguous and malformed. The closing tag of grandchild2 is grandchild which is wrong.
This is wrong------------+
|
v
<grandchild2>value3333</grandchild>
$results->grandchild does not exists, rather use $results->child3->grandchild. Here Xpath returns all the parent nodes under root node as SimpleXMLElement
To find all the parent element whose child1=value3 and grandchild1=value333 use this query.
/root/parent[child1 = "value3" and child3/grandchild = "value333"]

Parsing XML data using php to put into mysql database

I have been asked to parse a simple file which is stored as an XML file, the data is to be then put into a mysql database.
However I have absolutely no clue what to do and after looking online all the examples given seem either too complicated for my problem or not the right solution. The XML file looks like this:
<shop>
<products>
<product id="1" name="Cornetto" price="1.20" description="Traditional Cornetto" />
<product id="2" name="Smarties" price="1.00" description="Smarties Icecream" />
</products>
<stocks>
<stock id="1" amount="242" price="pounds" />
<stock id="2" amount="11" price="pounds" />
</stocks>
I've tried looking at SimpleXML and I think that's the direction I have to go but I just have no idea.
Any help or pointers would be great.
I personally like the normal XMl formatting so I changed it since its a bit more readable but this is how you can use it:
$xmlstr = <<<XML
<?xml version='1.0' standalone='yes'?>
<shop>
<products>
<product>
<id>1</id>
<name>Cornetto</name>
<price>1.20</price>
<description>Traditional Cornetto</description>
</product>
<product>
<id>2</id>
<name>Smarties</name>
<price>1.00</price>
<description>Smarties Icecream</description>
</product>
</products>
<stocks>
<stock>
<id>1</id>
<amount>242</amount>
<price>pounds</price>
</stock>
<stock>
<id>2</id>
<amount>11</amount>
<price>pounds</price>
</stock>
</stocks>
</shop>
XML;
Handling part:
$xml = new SimpleXMLElement($xmlstr);
echo 'single value: <br />';
echo $xml->products->product[0]->id; // get single value
echo '<br /><br />';
//Loop trough multiple products
echo 'multiple values: <br />';
foreach($xml->products->product as $product)
{
echo $product->id.' - ';
echo $product->name.' - ';
echo $product->price.' - ';
echo $product->description;
echo '<br/>';
}
Assuming the file is called data.xml
$string = file_get_contents('data.xml') reads the entire file into $string.
$xml = new SimpleXMLElement($string); parses that string, and converts it into an object tree similar to the actual document. So if that's the document -
<root>
<b>
<c>first</c>
<c>second</c>
</b>
</root>
The SimpleXMLElement object would be used like:
$xml->b // gets all children of b (c[0] and c[1])
print $xml->b->c[0] // gets the first c, will print "first"
You can use for example SimpleXMLElement and xpath
<?php
$xmlStr = <<<EOF
<?xml version="1.0"?>
<shop>
<products>
<product id="1" name="Cornetto" price="1.20" description="Traditional Cornetto" />
<product id="2" name="Smarties" price="1.00" description="Smarties Icecream" />
</products>
<stocks>
<stock id="1" amount="242" price="pounds" />
<stock id="2" amount="11" price="pounds" />
</stocks>
</shop>
EOF;
$xml=new SimpleXMLElement($xmlStr);
// get product line with xpath for example
$products=$xml->xpath("/shop/products/product");
if ($products) {
// loop over each product node
foreach ($products as $product) {
// do whatever you want with the data
echo("id=>".$product["id"].", name=>".$product["name"]."<br/>");
}
}
// same for stock
// get product line with xpath for example
$stocks=$xml->xpath("/shop/stocks/stock");
if ($stocks) {
// loop over each product node
foreach ($stocks as $stock) {
// do whatever you want with the data
echo("id=>".$stock["id"].", amount=>".$stock["amount"]."<br/>");
}
}
?>
$xml = simplexml_load_file($filename);
foreach($xml->product as $product) {
foreach($product->attributes() as $name => $attribute) {
echo "$name = $attribute";
}
}
$xml = simplexml_load_file($filename);
foreach($xml->products->product as $not)
{
foreach($not->attributes() as $a => $b)
{
echo $a,'="',$b,"\"<br />";
}
}

Categories