Count how many children are in XML with PHP - 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.

Related

Reaching the last XML element

so I got this XML.
I got a lot of such similar blocks in XML, and I can loop through it. But how would I know how many blocks are there ?
Or how would I stop after the last block ?
Any suggestion is appreciated.
<StockBalanceOut xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/BON_StockBalanceOut" class="entity">
<_DocumentHash>f5a598f180ccdecffeb7774d58ca8743</_DocumentHash>
<AvailPhysicalAvailableQty>0</AvailPhysicalAvailableQty>
<AvailPhysicalReservedQty>0</AvailPhysicalReservedQty>
<AvailPhysicalReturnQty>0</AvailPhysicalReturnQty>
<AvailPhysicalReworkQty>0</AvailPhysicalReworkQty>
<AvailPhysicalScrapQty>0</AvailPhysicalScrapQty>
<Date>2014-09-26</Date>
<ItemId>15742-20907</ItemId>
<ItemShippingClass>Empty</ItemShippingClass>
<OnOrderQty>0</OnOrderQty>
<PhysicalInventAvailableQty>0</PhysicalInventAvailableQty>
<PhysicalInventReservedQty>0</PhysicalInventReservedQty>
<PhysicalInventReturnQty>0</PhysicalInventReturnQty>
<PhysicalInventReworkQty>0</PhysicalInventReworkQty>
<PhysicalInventScrapQty>0</PhysicalInventScrapQty>
<RecId>5637416600</RecId>
<RecVersion>1</RecVersion>
<Time>15:25:52</Time>
</StockBalanceOut>
<StockBalanceOut xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/BON_StockBalanceOut" class="entity">
<_DocumentHash>6c6a3aa160f3ab9388f8e1b5b2fd7dc1</_DocumentHash>
<AvailPhysicalAvailableQty>99</AvailPhysicalAvailableQty>
<AvailPhysicalReservedQty>0</AvailPhysicalReservedQty>
<AvailPhysicalReturnQty>0</AvailPhysicalReturnQty>
<AvailPhysicalReworkQty>0</AvailPhysicalReworkQty>
<AvailPhysicalScrapQty>0</AvailPhysicalScrapQty>
<Date>2014-09-26</Date>
<ItemId>21234-29752</ItemId>
<ItemShippingClass>Empty</ItemShippingClass>
<OnOrderQty>0</OnOrderQty>
<PhysicalInventAvailableQty>99</PhysicalInventAvailableQty>
<PhysicalInventReservedQty>0</PhysicalInventReservedQty>
<PhysicalInventReturnQty>0</PhysicalInventReturnQty>
<PhysicalInventReworkQty>0</PhysicalInventReworkQty>
<PhysicalInventScrapQty>0</PhysicalInventScrapQty>
<RecId>5637416601</RecId>
<RecVersion>1</RecVersion>
<Time>15:25:52</Time>
</StockBalanceOut>
From your XML, I got this information.
There are multiple 'blocks' for <StockBalanceOut>, you can access each one by :-
$objectOfXMLFile->StockBalanceOut[0];
$objectOfXMLFile->StockBalanceOut[1];
To reach till the end you can run a while loop. If any index (suppose 10 doesn't exist) for StockBalanceOut doesn't exist, then it will return null.
$counter=0; //run from 0
while(!is_null($xmlOBJ->StockBalanceOut[$counter]))
{
//do anything here
$counter++;
}
I would look at trying something like this. To save you the link trip, here is some example code to get you started.
<?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());
}
?>

Using insertBefore method in php

I have actually asked this before, but alas the PC got nicked that I had the solution on, and I no longer can get the previous solution to work.
I'm trying to add a new element to the XML below:
<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
<comments>
<comment>
<date>20120509</date>
<time>10:21:05</time>
<name>Lucy</name>
<text>Hello etc</text>
</comment>
<comment> ...etc
The PHP code I'm using is:
$xml = new DOMDocument('1.0', 'utf-8');
$xml->load(filename.xml);
$parent = $xml->firstChild;
$refnode = $parent->firstChild;
$new = $parent->insertBefore($xml->createElement('comment'), $refnode);
However, this adds a new "comment" immediately after the "data" tag, and if I try to add children (such as "date", "time" etc...) with $new->addChild(tag, value), I get an "undefined method" error. I've tried all manner of permutations, but nothing works.
desired result would be:
<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
<comments>
*<comment>
<date>20140225</date>
<time>17:39:05</time>
<name>Derek</name>
<text>New comment text</text>
</comment>*
<comment>
<date>20120509</date>
<time>10:21:05</time>
<name>Lucy</name>
<text>Hello etc</text>
</comment>
<comment> ...etc
Your XML file most likely contained the whitespace characters like in your example. These are interpreted as text nodes, which renders firstChild useless to obtain one of those elements you want.
You have to iterate over the children instead and get the first one, which is actually a DOMElement. Also you had to go one level deeper than you did. See appended sourcecode which outputs the result you want.
<?php
$xml = new DOMDocument();
$xml->loadXML('<?xml version="1.0" encoding="UTF-8"?>
<data>
<comments>
<comment>
<date>20120509</date>
<time>10:21:05</time>
<name>Lucy</name>
<text>Hello etc</text>
</comment>
</comments>
</data>');
$parent = $xml->firstChild;
foreach ($parent->childNodes as $c) {
if ($c instanceof DOMElement) {
$refnode = $c;
break;
}
}
foreach ($refnode->childNodes as $c) {
if ($c instanceof DOMElement) {
$refnode2 = $c;
break;
}
}
$insert = $xml->createElement('comment', 'test');
$refnode->insertBefore($insert, $refnode2);
echo $xml->saveHTML();

Getting a specific part from XML

I am trying to get the PAY where it has the ID 3 Where it says the label phone
but i really dont know how, i tried everything.
Thanks for helping!
Here is the XML code:
$books = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data>
<login>1</login>
<arrStatsData>
<item>
<Id>500</Id>
<Label>website_name</Label>
<Data>
<item>
<Id>4</Id>
<Label>transactions</Label>
<Data>
<sum>2029.34</sum>
<cst>47.67575</cst>
<num>86</num>
<avg>23.6</avg>
<pay>1981.66</pay>
</Data>
</item>
<item>
<Id>3</Id>
<Label>Phone</Label>
<Data>
<sum>205</sum>
<cst>17.353</cst>
<num>205</num>
<avg>1</avg>
<pay>187.647</pay>
</Data>
</item>
......
PHP Code:
$xml = simplexml_load_string($arrResult); //load xml from above
foreach($xml->arrStatsData->item->Data as $item)
{
foreach($item->item as $DATA)
{
echo $DATA->Id.'<br>';
}
My result now is:
1981.66
187.647
-0.4448
Since you know some information that's tell the node apart from the rest you can use XPath to get the value directly instead of iterating through all of them:
<?php
$sxe = new SimpleXMLElement($books);
$pay = $sxe->xpath('//item[./Id=3]/Data/pay');
echo (string) $pay[0];
Ouput:
187.647
Your PHP code would be like this:
$xml = simplexml_load_string($books);
foreach($xml->arrStatsData->item->Data as $item)
{
//echo '$item;';
foreach($item->item as $DATA)
{
if($DATA->Id == '3'){
echo $DATA->Data->pay."<br/>";
}
}
}
It retrieve the pay value when the ID is equals to 3.
Rolando Isidoro was faster to recommend xpath, my solution is slightly different, that's why I post it, too:
$pay = (string)$xml->xpath("//item[Id = '3']/Data/pay")[0];
echo $pay;
see it working: http://codepad.viper-7.com/qzPlmp

PHP SimpleXML add child to each parent repeatedly

I have this kind of XML:
<?xml version="1.0" encoding="utf-8"?>
<data>
<stats>
</stats>
<params>
</params>
<results>
<record id='SJDGH'>
<item>abc</item>
<item>def</item>
<item>ghi</item>
</record>
<record id='OIIO'>
<item>abc</item>
<item>def</item>
<item>ghi</item>
</record>
</results>
</data>
I'm generating a new <item> for every <record> in <results> in a loop:
// $data is SimpleXml objec from XML above
foreach ($data->results->record as $record)
{
$newitem = 'New item!'.time().$record->attributes()->id;
}
Somehow in this loop i need to change the SimpleXML object ($data) to contain new items in every <record>.
is it possible?
I needed a little guessing, but this might what you're looking for:
$records = $data->results->record;
foreach($records as $record)
{
$value = sprintf('New Item! %s / id:%s', time(), $record['id']);
$record->item[] = $value;
}
$data->asXML('php://output');
See it in action.
I think you might want to use addChild.
Check it out here: http://php.net/manual/en/simplexmlelement.addchild.php

php - simpleXML help

I have this XML code :
<?xml version="1.0"?>
<Days>
<day value="1">
<Imsaak>04:59</Imsaak>
<Fajr>05:09</Fajr>
<Sunrise>06:23</Sunrise>
<Dhuhr>12:39</Dhuhr>
<Asr>16:12</Asr>
<Sunset>18:55</Sunset>
<Maghrib>19:10</Maghrib>
<Isha>20:04</Isha>
</day>
<day value="2">
<Imsaak>04:58</Imsaak>
<Fajr>05:08</Fajr>
<Sunrise>06:22</Sunrise>
<Dhuhr>12:39</Dhuhr>
<Asr>16:12</Asr>
<Sunset>18:56</Sunset>
<Maghrib>19:11</Maghrib>
<Isha>20:05</Isha>
</day>
</Days>
and I want to select <day> node depending on the attribute value
I am using SimpleXMLElement class but I don't how to select with arrtibute value.
how I can do that??
EDIT: my code :
include 'days.xml';
$xml = new SimpleXMLElement($xmlstr);
foreach ($xml->day as $day) {
// process data
}
from php manual SimpleXMLElement::attributes (little bit edited)
Considering this data:
<?xml version="1.0" encoding="utf-8"?>
<data>
<item ID="30001">
<Company>Navarro Corp.</Company>
</item>
<item ID="30002">
<Company>Performant Systems</Company>
</item>
<item ID="30003">
<Company>Digital Showcase</Company>
</item>
</data>
Example of listing both the ID Attribute and Company Element values:
<?php
$xmlObject = new SimpleXMLElement($xmlstring);
foreach ($xmlObject->children() as $node) {
$arr = $node->attributes(); // returns an array
if(in_array("30002", $arr)){ // search the value of an attribute
print ("Company=".$node->Company);
}
//depending of your needs, you could use a switch / case instead of use an if
}
?>
$xml = new SimpleXMLElement($xmlStr)
$xml->day[0]->attribute()->value;//will echo out 1
of course you can loop through all of the day like this:
foreach($sml->day as $day){
$day->attribute()->value; //will trace out 1 and then 2
}

Categories