Dynamic xml handling with php - php

I work with many different types of xml files. I load the contents of these into my mysql database. Problem is that i need to define the tags I want to pick everytime.
Is there a php dom object functions that can iterate over all the tags and give them to me.
this is my sample xml
<products>
<product>
<name>Name of product</name>
<categories>
<category>Apparel</category>
<category>Trousers</category>
<category>Blue</category>
</categories>
<description>Blue trousers</description>
<price>599.00</price> <regularPrice>599.00</regularPrice>
</product>
</products>
Output should be NOT the values but the acctual name of the XML tags, in this case it should be
Products, Product, Name, Categories, category, description, price
Getting those values I could dynamicly point them via a connection table to always be save in the right table and in the right field.

*Try this code it will work as expected *
$xmlD = '
<products>
<product>
<name>Name of product</name>
<categories>
<category>Apparel</category>
<category>Trousers</category>
<category>Blue</category>
</categories>
<description>Blue trousers</description>
<price>599.00</price> <regularPrice>599.00</regularPrice>
</product>
</products>
';
$xml = simplexml_load_string($xmlD);
echo $xml->getName() . "<br />";
foreach($xml->children() as $child)
{
echo $child->getName(). "<br />";
foreach($child->children() as $innerChild):
echo $innerChild->getName(). "<br />";
endforeach;
}

Related

xpath Error while searching attributes

Hello I would like to extract with xpath all items with the name="Frequency" which contains a certain value but it doesn't give me anything. What Am I doing wrong?
XML File:
<products>
<product>
<title>PT2400</title>
<ElectricSpecifications>
<item name="Frequency">2310 - 2485 MHz (WLAN, BLUETOOTH, ZIGBEE</item>
</ElectricSpecifications>
</product>
</products>
foreach ($xpath->query("//product/ElectricSpecifications[#item='Frequency'][contains(., ' $value')]") as $item) {
var_dump($item);
}
item is not an attribute of ElectricSpecifications, but its child node, so instead of
[#item='Frequency']
syntax, try
item[#name='Frequency']
And so complete XPath should be like
//product/ElectricSpecifications/item[#name='Frequency' and contains(., ' $value')]

Get values XML feed by name - PHP

I'm using XML to insert products into my db with PHP. I can access / read the xml feed with the following code:
$xml=simplexml_load_file('testfeed.xml') or die("Error: Cannot create object");
foreach($xml->children() as $product) {
$pname = $product->name;
$pdescr = $product->description;
echo $pname;
echo $pdescr;
}
Below is my example XML:
<product ID="9">
<name>Product X</name>
<properties>
<property name="categoryPath">
<value>path-to-category</value>
</property>
<property name="stock">
<value>1</value>
</property>
</properties>
</product>
It's easy to get the values for name, but how do I get the value of the categorypath, since this one is inside properties->property->value and declared in the <property name="categoryPath">?
Thanks!
The easiest way without looping too much through the structures will be using XPath:
$values = $xml->xpath('//property[#name="categoryPath"]/value');
Just loop through the returned array and cast each result to string when needed, and you're done.
$xml=simplexml_load_file('./testfeed.xml') or die("Error: Cannot create object");
foreach($xml->children() as $product) {
$pname = $product->name;
$pdescr = $product->properties->property["name"];
$pdvalue = (string)$product->properties->property->value;
echo "Prdo Name: $pname\n";
echo "Prod Desc: $pdescr\n";
echo "Prod Value: $pdvalue\n";
}
Output:
Prdo Name: Product X
Prod Desc: categoryPath
Prod Value: path-to-category
Update:
While Jossif's answer is very good at getting all the nodes in bulk I'm including an edit for updated xml structure without using xpath:
$property = $product->properties->property;
$propertyAttribute = $property->attributes()->{'name'};
$catPath = ($propertyAttribute=="categoryPath")? $property->value : "value for missing paths";
print $catPath . PHP_EOL;
Since you don't seem to have any other similar xml nodes, you don't need the attribute to separate them.
You should be able to safely use this
$catPath = $product->properties->property->value;
print $catPath;
to get the string from the value node.

php xml remove elements not containing a specific word from large file

I am reading an xml file which looks like this but with a lot more products:
<?xml version="1.0" encoding="iso-8859-1"?>
<products>
<product>
<company>company.com</company>
<category>Category A</category>
<brand>Alle!rgica</brand>
<product_name>Name A</product_name>
<productid>6230</productid>
<description>A nice description</description>
<price>125.50</price>
</product>
<product>
<company>Team.com</company>
<category>Category B // something</category>
<brand>New Nordic > Healthcare</brand>
<product_name>Name B</product_name>
<productid>9489</productid>
<description>Active Legs? Buy it now for free</description>
<price>188.00</price>
</product>
</products>
I want to read it and then save it with only products containing the word "free" somewhere in the "product tag" and without the "products" tag and the xml header.
I know how to read the file and save it, but I can't figure out the best approach to remove everything but the products that contain "free".
I tried wth Regex but it didn't seem the best solution (mainly because the matching doesn't properly work):
preg_match_all('/<product>(.*?)(free|free-stuff)(.*?)<\/product>/is', $data, $result);
So in the case of the above the file should only contain:
<product>
<company>Team.com</company>
<category>Category B // something</category>
<brand>New Nordic > Healthcare æøå</brand>
<product_name>Name B</product_name>
<productid>9489</productid>
<description>Active Legs? Buy it now for free</description>
<price>188.00</price>
</product>
use xpath():
$xml = simplexml_load_string($x); // assume XML in $x
$result = $xml->xpath("//product[not(contains(., 'free'))]");
$result contains an array of <product>-nodes as SimpleXML-elements that do not contain "free".
Output:
foreach ($result as $r)
echo $r->asXML();
See it working: https://eval.in/338884
Use this code:
$xml = simplexml_load_file($filename);
foreach($xml->product as $product) {
foreach($product->children() as $child)
// lookup the pattern in all nodes inside product
if ($found = (false !== strpos((string)$child, 'free')))
// Found - we can don't continue searching
break;
// save product found
if ($found) $products[] = $product;
}
print_r( $products);

How should I modify this for each statement to only display entries where all of the values are unique?

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

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