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 />";
}
}
Related
foreach($resultXML->products->children() as $product) {
echo "<p>".$product->{'advertiser-name'}." - ".$product->price."</p>
<p>".$product->{'description'}."</p>";
}
Suppose I wanted to screen out the ones that had the same title, and only display the first title that appears in the return results.
I'm not working with my own database, this is all about what's displayed.
I suppose the easiest way would be to keep track of the titles in an array, and checking it each iteration.
$titles = array();
foreach($resultXML->products->children() as $product) {
if (in_array($product->title, $titles) continue;
$titles[] = $product->title;
echo "<p>".$product->{'advertiser-name'}." - ".$product->price."</p>
<p>".$product->{'description'}."</p>";
}
Assuming that the title is contained in $product->title. You could do something fancier through array functions, but I don't see a reason to make a simple problem complicated.
You have not provided any exemplary XML, so given for
<?xml version="1.0" encoding="UTF-8"?>
<example>
<products>
<product>
<title>First Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
</products>
<products>
<product>
<title>Second Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
</products>
<products>
<product>
<title>Third Product</title>
<advertiser-name>Second Name</advertiser-name>
</product>
</products>
</example>
You want to get all product elements with an advertiser-name that is not an advertiser-name of all preceding product elements.
So for the XML above, that would be the 1st and 3rd product element.
You can write that down as an XPath expression:
/*/products/product[not(advertiser-name = preceding::product/advertiser-name)]
And as PHP code:
$xml = simplexml_load_string($buffer);
$expr = '/*/products/product[not(advertiser-name = preceding::product/advertiser-name)]';
foreach ($xml->xpath($expr) as $product) {
echo $product->asXML(), "\n";
}
This produces the following output:
<product>
<title>First Product</title>
<advertiser-name>First Name</advertiser-name>
</product>
<product>
<title>Third Product</title>
<advertiser-name>Second Name</advertiser-name>
</product>
So one answer to your question therefore is: Only query those elements from the document you're interested in. XPath can be used for that with SimpleXMLElement.
Related questions:
Implementing condition in XPath
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];
I have a xml file as follows:
<?xml version="1.0" ?>
<shop version="2.0" shop-name="XYZ">
<category name="FOO1">
<subcategory name="Foobar1">
<product name="Productname1" id="1">
<supplier name="XXX" logo="XXX.gif" />
<desc>DESC</desc>
</product>
<product name="Productname2" id="2">
...
</product>
</subcategory>
</category>
</shop>
And i would like to get attribute value of shop element - exactly shop-name
I used simplexml in php:
<?php
$dataXML=simplexml_load_file("data.xml");
$a=$dataXML->shop[0]["shop-name"];
echo $a;
?>
as a result I get nothing. Have any idea what is wrong?
use the getAttribute() methdo to read attribute name.
<?php
$dataXML = simplexml_load_file("data.xml");
$shopName = $dataXML->getAttribute("shop-name");
echo $shopName;
?>
Those are attributes, so you need to access them correctly with attributes() method:
$data = simplexml_load_file( 'data.xml' );
$attributes = $data->attributes();
echo $attributes['shop-name'];
Or you can access it directly, since it's the main attribute:
$data = simplexml_load_file( 'data.xml' );
echo $data['shop-name'];
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
i'm trying to pass an xml node to a function but can't figure out how - here's my xml markup:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<root>
<form>
<item>
<id>frm1</id>
<dbID>1</dbID>
<visible>1</visible>
</item>
</form>
<form>
<item>
<id>frm2</id>
<dbID>2</dbID>
<visible>1</visible>
</item>
</form>
</root>
when setting up a foreach loop - how's the syntax to iterate through the xml and passing the whole node to a function?
i've tried something like:
foreach($xml as $ctlXML => $value)
{
$ctl = generateCTL($ctlXML);
}
but it doesn't work as it should.
thanks
If you are using SimpleXML it is simple as
$xml = simplexml_load_file($path_to_file);
foreach($xml->form as $form){
$ctl = generateCTL($form->item);
}
Be careful - $form->item is an object