PHP XML DOM - Distinguishing nodes based on parent attributes/elements - php

First of all, thanks for the time reading this :)
I need help reordering an XML feed. I've tried many things and researched, but can't come up with a solution.
<xml>
<group>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
</result>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
</result>
</group>
<group region=top>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
</result>
</group>
<group type=bottom>
<result>
<title>Title</title>
<url>URL</url>
<text>Text</text>
<moreinfo>
<result>
<title>Title</title>
</result>
<result>
<title>Title</title>
</result>
</moreinfo>
</result>
</group>
</xml>
What I am trying to do is re-order the XML feed to display each node inside 'result'. However, I need the feed reordered so the 'result' from 'group region=top' is at the top, then the results from 'group', then results from 'group region=bottom'.
You might notice there is another 'result' tag nested inside of a 'result' tag in 'group region=bottom', which is causing most of the issues. The way I envision a solution to this is with the following pseudo-code:
$books = $doc->getElementsByTagName( "result" );
foreach( $books as $book )
{
if (parent_attribute = top){
$toptitle = $book->getElementsByTagName( "title" );
$toptitle = $toptitle->item(0)->nodeValue;
$topnew[] =array("title"=>$toptitle);
}
if (parent_attribute = null){
$middletitle = $book->getElementsByTagName( "title" );
$middletitle = $middletitle->item(0)->nodeValue;
$middlenew[] =array("title"=>$middletitle);
}
if (parent_attribute = bottom){
$bottomtitle = $book->getElementsByTagName( "title" );
$bottomtitle = $bottomtitle->item(0)->nodeValue;
if (parent_element = moreinfo){
$moretitle = $book->getElementsByTagName( "title" );
$moretitle = $moretitle->item(0)->nodeValue;
}
$bottomnew[] =array("title"=>$bottomtitle, "more"=>$moretitle);
}
}

The XML you posted is invalid and not consistent, as attribute values have to be enclosed in "", for consistency see my comment above.
Here's how I do it using simplexml and xpath, it can be easily adapted to DOM as well.
$xml = simplexml_load_string($x); // assuming XML in $x
$regions['top'] = $xml->xpath("group[#region='top']/result");
$regions['middle'] = $xml->xpath("group[not(#*)]/result"); // <group> with no attribute
$regions['bottom'] = $xml->xpath("group[#region='bottom']/result");
// output:
foreach ($regions as $region => $results) {
echo "$region:<br />";
foreach ($results as $result) {
echo $result->title . "<br />";
if (count($result->moreinfo) > 0)
foreach ($result->moreinfo->result as $subresult)
echo "____$subresult->title<br />";
} // foreach $results
} // foreach $regions
see it working: http://codepad.viper-7.com/5adWxC

Related

PHP simpleXML: Read XML, add node and save

I'm having some problems with adding a xml node to its parent.
I receive variables $cat, $title and $isbn.
I want to parse $title and $isbn to an XML node and add it to the right categorie ($cat).
die(var_dump($parent)); --> returns NULL, so the biggest problem (I think) is that I can't figure out how to add my node to the right parent because I cant get it identified.
Any suggestions?
The XML file:
<?xml version="1.0"?>
<books version="1.0">
<categorie name="catone" id="100">
<book title="1_WS2012" isbn="isbnone" />
<book title="1W2012DHCP" isbn="ibsntwo" />
</categorie>
<categorie title="cattwo" id="101">
<book title="2W2008R2DC" isbn="isbnthree" />
</categorie>
<categorie title="catthree" id="103">
<book title="3SBS" isbn="isbnfout=" />
</categorie>
</books>
The Code:
//Get variables
$cat = "catone";
$title = "testtitle";
$isbn = "testisbn";
$xmlDoc = simplexml_load_file("books.xml");
$parent = null;
//Construct node
$childstring = "<book></book>";
$child = new SimpleXMLElement($childstring);
$child->addAttribute('title', $title);
$child->addAttribute('isbn', $isbn);
//This works (results in <book title="testtile" isbn="testisbn" />)
//Add node to correct parent
for ($i=0; $i <= sizeof($xmlDoc->categorie) -1; $i++) {
//The condition does also work
if (strtoupper($xmlDoc->categorie[$i]->attributes()->name) == strtoupper($cat))
{
//I'm stuck here
$parent = $xmlDoc->categorie[$i]->attributes()->xpath('/object/data[#type="me"]');;
$xmlDoc->$parent->addChild($child);
}
}
//Write file
file_put_contents("books.xml", $xmlDoc->asXML());
Desired result:
<books version="1.0">
<categorie name="catone" id="100">
<book title="1_WS2012" isbn="isbnone" />
<book title="1W2012DHCP" isbn="ibsntwo" />
<book title="testtitle" isbn"testisbn" />
</categorie>
<categorie title="cattwo" id="101">
<book title="2W2008R2DC" isbn="isbnthree" />
</categorie>
<categorie title="catthree" id="103">
<book title="3SBS" isbn="isbnfout=" />
</categorie>
</books>
First, use xpath to select the parent. xpath is like SQL for XML:
$xml = simplexml_load_string($x); // assume XML in $x
$parent = $xml->xpath("/books/categorie[#name = 'catone']")[0];
Note: The above code requires PHP >= 5.4 for the [0] at the end of line 2. (1)
Now, add the new <book> and its attributes:
$new = $parent->addChild("book","");
$new->addAttribute("title", "testtitle");
$new->addAttribute("isbn", "testisbn");
see it working: https://eval.in/131009
(1) if you are on PHP < 5.4, either update or do:
$parent = $xml->xpath("/books/categorie[#name = 'catone']");
$parent = $parent[0];

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 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);

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