Getting XML file from another domain to Mysql database - php

I'm trying to get xml information from an url to be imported into mysql trough a php script, but I'm having some trouble and my experience dosen't cover this area.
The XML is formed as this example:
<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:g="http://base.google.se/ns/1.0">
<channel>
<title></title>
<description></description>
<link></link>
<item>
<g:id></g:id>
<title></title>
<g:product></g:product>
</item>
<item>
<g:id></g:id>
<title></title>
<g:product></g:product>
</item>
and so on...
with the php script:
<?php
include '../connection-to-db.php';
$str_xml = file_get_contents('http://www.example.com/xmls/xmlfile.xml');
$library = new SimpleXMLElement($str_xml);
$arr = json_decode( json_encode($library) , true);
var_dump ($arr);
echo "Array got " .sizeof($arr['item']) . " items.<br> <br>";
if (sizeof($arr['item']) > 155555500) {
mysql_query("TRUNCATE TABLE google_stat");
$count = 0;
foreach ($arr['item'] as $shelf)
{
$gId = mysql_real_escape_string($shelf['g:id']);
$Title = mysql_real_escape_string($shelf['title']);
$gProductType = mysql_real_escape_string($shelf['g:product']);
mysql_query("INSERT INTO google_stat (gid, title, gcategory)
VALUES ('$gID', '$Title', '$gCategory')")
or die(mysql_error());
$count ++;
}
echo " Counted: " . $count . "inserts";
} else {
echo "Non counted, no insert done";
}
?>
Problem is when SimpleXMLElement it seems all items with g: in there names disappears when I look at the output, it dosen't even fint any items.
I've even tried with a localfile with same XML tree and can't even make that work.
I'm thankful for any help given, since I realize more and more I'm on deep water with this.
UPDATE:
<?php
include '../connection-to-db.php';
$str_xml = file_get_contents('http://www.example.com/xmls/xmlfile.xml');
$library = new SimpleXMLElement($str_xml);
$arr = json_decode( json_encode($library) , true);
echo "Array got " .sizeof($library->channel->item) . " items.<br> <br>";
if (sizeof($library->channel->item) > 100) {
mysql_query("TRUNCATE TABLE google_stat");
$count = 0;
foreach ($library->channel->item as $shelf)
{
$gId = (string) $shelf->children('g', TRUE)->id;
$Title = (string) $shelf->title;
$gProductType = $shelf->children('g', TRUE)->product;
echo $gId."<br />";
echo $Title."<br />";
echo $gProductType."<br />";
$count ++;
}
echo " Counted: " . $count . "inserts";
} else {
echo "Non counted, no insert done";
}
?>
Now I get the number of items in array, but $gId, $Title etc, dosen't echo any values.
Edit2: had to high array check, it works.

It has to do with the namespace prefix you want. You can access the g: items like so:
<?php
$str_xml = file_get_contents('test.xml');
$library = new SimpleXMLElement($str_xml);
$count = 0;
foreach ($library->channel->item as $shelf)
{
$gId = (string) $shelf->title;
$Title = (string) $shelf->children('g', TRUE)->id;
$gProductType = (string) $shelf->children('g', TRUE)->product;
echo $gId."<br />";
echo $Title."<br />";
echo $gProductType."<br />";
$count ++;
}
echo " Counted: " . $count . " inserts";
?>
See https://www.sitepoint.com/simplexml-and-namespaces/ for further reference.
xml.test
<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:g="http://base.google.se/ns/1.0">
<channel>
<title>product</title>
<description>lots of products</description>
<link>www.example.com</link>
<item>
<g:id>ID 1</g:id>
<title>Title 1</title>
<g:product>Product 1</g:product>
</item>
<item>
<g:id>ID 2</g:id>
<title>Title 2</title>
<g:product>Product 2</g:product>
</item>
</channel>
</rss>
Output:
Title 1
ID 1
Product 1
Title 2
ID 2
Product 2
Counted: 2 inserts

Related

PHP Array Comparison using If

I am having a hard time trying to understand why I can't compare the values of two arrays in PHP. If I echo both of these during the loop using "echo $description->ItemDesriptionName;" and "echo $item->ItemName;" the values seem to show as the same, but when I try to compare them using if, nothing works. What am I missing?
<?php
$xml=simplexml_load_file("test.xml") or die("Error: Cannot create object");
$categories = $xml->Menu->Categories;
$items = $xml->Menu->Categories->Items->ItemObject;
$itemdescription = $xml->Menu->Options->Description->DescriptionObject;
foreach($items as $item) {
echo $item->ItemName . ' - ' . $item->Price . '</br>';
foreach ($itemdescription as $description) {
if ($description->ItemDescriptionName == $item->ItemName) {
echo 'We have a match!';
//where I would echo $description->ItemDescription;
}
}
}
?>
Here is the XML file
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Menu>
<Categories>
<Name>Category 1</Name>
<Items>
<ItemObject>
<ItemName>Item 1</ItemName>
<Price>1</Price>
</ItemObject>
<ItemObject>
<ItemName>Item 2</ItemName>
<Price>3</Price>
</ItemObject>
</Items>
</Categories>
<Options>
<Description>
<DescriptionObject>
<ItemDescriptionName>Item 1</ItemDescriptionName>
<ItemDescription>A Great item</ItemDescription>
</DescriptionObject>
<DescriptionObject>
<ItemDescriptionName>Item 2</ItemDescriptionName>
<ItemDescription>A Great item as well</ItemDescription>
</DescriptionObject>
</Description>
</Options>
</Menu>
</Root>
compare as string
and you have typo in ItemDescriptioName (ItemDescriptionName)
if ( (string)$description->ItemDescriptionName == (string)$item->ItemName) {
Convert to string and then compare
<?php
$xml=simplexml_load_file("test.xml") or die("Error: Cannot create object");
$menu = $xml->Menu;
$categories = $xml->Menu->Categories;
$items = $xml->Menu->Categories->Items->ItemObject;
$itemdescription = $xml->Menu->Options->Description->DescriptionObject;
foreach($items as $item) {
$itemname = $item->ItemName;
foreach ($itemdescription as $description) {
$descriptionname = $description->ItemDescriptionName ;
echo $itemname." ---- ".$descriptionname."<br/>";
if((string)$itemname === (string)$descriptionname){
echo "Yes its matched";
}
}
}
?>
Working fine for me
The properties like $description->ItemDescriptionName are SimpleXMLElement objects. So you do not compare strings but two objects.
SimpleXMLElement objects implement the magic method __toString(). They can be cast to string automatically, but a compare between to objects will not trigger that. You can force it:
if ((string)$description->ItemDescriptionName === (string)$item->ItemName) {
...
Can you access them directly instead using an accordant index?
...
$items = $xml->Menu->Categories->Items->ItemObject;
$itemdescription = $xml->Menu->Options->Description;
$i = 0;
foreach ($items as $item) {
echo $i.' '.$item->ItemName . ' - ' . $item->Price;
echo $itemdescription->DescriptionObject[$i]->ItemDescriptionName[0];
echo ' ';
echo $itemdescription->DescriptionObject[$i]->ItemDescription[0];
echo '</br>';
$i++;
}

PHP XMLReader xml:lang

How can I read the xml:lang Value from this xml File???
<Catalog><Products>
<Product>
<Id>123</Id>
<Name xml:lang="en">name english product</Name>
<Description xml:lang="en">desc xyz</Description>
<Name xml:lang="de">name german</Name>
<Description xml:lang="de">desc germa</Description>
<Image num="1"><Url>pic.jpg</Url></Image>
<Image num="2"><Url>pic2.jpg</Url></Image>
</Product>
<Product>...
I want the value of the xml:lang="de" - Tag and the Image-Values.
Does anybody have an idea???
Thanx :-)
Update: I parse the xml like this, but how do i get this values???
$datei = "test.xml";
$z = new XMLReader;
$z->open($datei);
$doc = new DOMDocument;
while ($z->read() && $z->name !== 'Product');
$i = 0; while ($z->name === 'Product')
{ $i++;
$node = simplexml_import_dom($doc->importNode($z->expand(), true));
...
I think this should do it.
$simpleXml = new SimpleXMLElement(file_get_contents($datei));
foreach ($simpleXml->Products->Product as $product) {
$name = $product->xpath('Name[#xml:lang="en"]')[0];
echo $name . "\n";
foreach($product->Image as $img) {
echo $img->Url . "\n";
}
}
xpath use to many resurses. You can scan it, taking needed nodes. In the code you will see how take name and value of nodes and attributes, which have prefix.
$simpleXml = new SimpleXMLElement(file_get_contents($datei)));
foreach ($simpleXml->Products->Product as $products) // list of nodes with same name
foreach($products as $product) { // every node
if ($product->getName() === 'Image') { // for image take child
echo $product->Url->getName() . " = " . $product->Url ."\n";
$attrs = $product->attributes(); // Attribute without prefix
if(isset($attrs['num'])) echo " num = " . $attrs['num'] . "\n";
}
else echo $product->getName() . " = " . $product ."\n";
$attrs = $product->attributes('xml', true); // if 2nd true, 1st is prefix
if(isset($attrs['lang'])) echo " lang = " . $attrs['lang'] . "\n";
}
result
Id = 123
Name = name english product
lang = en
Description = desc xyz
lang = en
Name = name german
lang = de
Description = desc germa
lang = de
Url = pic.jpg
num = 1
Url = pic2.jpg
num = 2

How to edit my code to save to mySQL from the beginning of XML?

I have this XML feed below I am trying to import into MySQL for all the products.
For example, inside the table XML_FEED I want something like
shop - product_id - product_name - product_link - .......
mywebstore - 322233 - MadBiker 600 - .........
mywebstore - 324633 - Samsung S4 - .........
The code until now it works only if the XML begins from <products> and not from <mywebstore>
How to change my code to do this ?
$xml = simplexml_load_file("test.xml");
foreach($xml->product as $product)
{
$columns = array();
$data = array();
foreach($product->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
$columns[] = $child->getName();
$data[] = mysql_real_escape_string((string)$child);
}
$col = '`'. implode('`,`',$columns) .'`';
$val = "'". implode("','",$data)."'";
$query = "INSERT INTO XML_FEED ($col) VALUES ($val)";
echo $query;
mysql_query($query);
}
Here is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<mywebstore>
<created_at>2010-04-08 12:32</created_at>
<products>
<product>
<id>322233</id>
<name><![CDATA[MadBiker 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
...
...
...
</products>
</mywebstore>
Use This code:
<?php
$xml = simplexml_load_file('test.xml');
foreach($xml->products->product as $product)
{
$columns = array();
$data = array();
foreach($product->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
$columns[] = $child->getName();
$data[] = mysql_real_escape_string((string)$child);
}
$col = '`'. implode('`,`',$columns) .'`';
$val = "'". implode("','",$data)."'";
$query = "INSERT INTO XML_FEED ($col) VALUES ($val)";
echo $query;
mysql_query($query);
}
?>
This should work for you:
<?php
//Xml stuff
$xml = simplexml_load_file("file.xml");
//Database stuff
$hostname = "localhost";
$username = "root";
$password = "";
try {
//DB Connection
$dbh = new PDO("mysql:host=$hostname;dbname=dbname", $username, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Connected to Database<br/>";
foreach($xml->products->product as $data) {
$sql = "INSERT INTO XML_FEED (shop, product_id, product_name, product_link, product_image, product_category, product_price_with_vat)
VALUES (:SHOP, :ID, :NAME, :LINK, :IMAGE, :CATEGORY, :PRICE)";
$stmt = $dbh->prepare($sql);
$params = array(
"SHOP" => $xml->getName(),
"ID" => $data->id ,
"NAME" => $data->name,
"LINK" => $data->link,
"IMAGE" => $data->image,
"CATEGORY" => $data->category,
"PRICE" => $data->price_with_vat
);
$stmt->execute($params);
}
//Close Connection
$dbh = null;
} catch(PDOException $e) {
echo $e->getMessage();
}
?>
Site Note:
Add error reporting to the top of your file(s) which will help during production testing.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>
Also if you want to show/see the data in html you can use this:
<?php
//Xml stuff
$xml = simplexml_load_file("file.xml");
echo "<table border='1'>";
echo "<tr>
<td>Shop</td>
<td>Product ID</td>
<td>Product Name</td>
<td>Product Link</td>
<td>Product Image</td>
<td>Product Category</td>
<td>Product Price with vat</td>
</tr>";
foreach($xml->products->product as $data) {
echo "<tr>
<td>" . $xml->getName() . "</td>
<td>" . $data->id . "</td>
<td>" . $data->name . "</td>
<td>" . $data->link . "</td>
<td>" . $data->image . "</td>
<td>" . $data->category . "</td>
<td>" . $data->price_with_vat. "</td>
</tr>";
}
echo "</table>";
?>
You are not able to get data because of missing or invalid parent node.
While working with XML needs to handle parent and child(children) node
relationship carefully. Unfortunately you have missed the exact same
thing.
When you use mywebstore node as a parent then its intermediate child node is products and products child node is product.
But when you use products node as a parent then its child node is product.
In your code you have handled the second condition. You have to handle the both conditions or you can use the first condition in your code.
Example:
<?php
$file = 'test.xml';
$xml = simplexml_load_file($file, null, LIBXML_NOCDATA);
if($xml === false){
echo "Failed to load '$file'.\n";
}else{
$productsArr = Array();
if(isset($xml->products)){
$productsArr = $xml->products;
}else if(isset($xml->product)){
$productsArr = $xml;
}
if(sizeof($productsArr) > 0){
foreach($productsArr->product as $productArr){
$productArr = (array) $productArr;
$id = null;
if(isset($productArr['#attributes'])){
$id = $productArr['#attributes']['id'];
unset($productArr['#attributes']);
}
if(!isset($productArr['id']) && !empty($id)){
$productArr['id'] = $id;
}
array_walk_recursive($productArr, function (&$value) {
$value = htmlentities($value,ENT_QUOTES,'UTF-8');
$value = mysql_real_escape_string($value);
});
$col = '`'. implode('`,`',array_keys($productArr)) .'`';
$val = "'". implode("','",array_values($productArr))."'";
$query = "INSERT INTO projectx ($col) VALUES ($val)";
echo "$query \n";
mysql_query($query);
}
}else{
echo "Invalid XML Format.Missing parent node '<mywebstore> or <products>'. \n";
}
}
XML:
Format with <mywebstore> as parent node XML with attribute ID:
`
<?xml version="1.0" encoding="UTF-8"?>
<mywebstore>
<created_at>2010-04-08 12:32</created_at>
<products>
<product id="322233">
<name><![CDATA[MadBiker' 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
<product>
<id>322234</id>
<name><![CDATA[MadBiker 700]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>344.00</price_with_vat>
</product>
</products>
</mywebstore>
Format with <mywebstore> as parent node XML without attribute ID (Same as Question XML):
`
<?xml version="1.0" encoding="UTF-8"?>
<mywebstore>
<created_at>2010-04-08 12:32</created_at>
<products>
<product>
<id>322233</id>
<name><![CDATA[MadBiker 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
</products>
</mywebstore>
`
Format with <products> as parent node XML with attribute ID:
`
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product id="322233">
<name><![CDATA[MadBiker' 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
<product>
<id>322234</id>
<name><![CDATA[MadBiker 700]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>344.00</price_with_vat>
</product>
</products>
`
Format with <products> as parent node XML without attribute(ID):
`
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<id>322233</id>
<name><![CDATA[MadBiker 600]]></name>
<link><![CDATA[http://www.mywebstore.co.uk/product/322233]]></link>
<image><![CDATA[http://www.mywebstore.co.uk/product/322233.jpg]]></image>
<category><![CDATA[Outdor > Extreme Sports]]></category>
<price_with_vat>322.33</price_with_vat>
</product>
</products>
Conclusion: In valid handling of parents & child node relationship.
Simply change this:
foreach($xml->product as $product)
{
with this:
foreach($xml->products[0] as $product)
{
In order to get the different products you should use xpath
Code:
$xml = simplexml_load_file("xml.xml");
// will search for array of products no matter what it is nested inside of
$products = $xml->xpath('//product');
foreach($products as $product)
{
$columns = array();
$data = array();
foreach($product->children() as $child)
{
echo $child->getName() . ": " . $child . "<br />";
$columns[] = $child->getName();
$data[] = mysql_real_escape_string((string)$child);
}
$col = '`'. implode('`,`',$columns) .'`';
$val = "'". implode("','",$data)."'";
$query = "INSERT INTO XML_FEED ($col) VALUES ($val)";
echo $query;
mysql_query($query);
}
Explanation:
Xpath for simplexml simply returns an array of the simple xml objects or here the product xml elements.
Since we want to return an array of all the products, we search "foreach" occurrence of the product using xpath.
Inside of the xpath string, A double slash (//) signals that all elements in the XML document that match the search criteria are returned, regardless of location/level within the document.
Firstly, simplexml_load_file() returns a pointer to the root element of the XML feed, i.e. the very first XML tag in the input file. In other words, when you write:
$xml = simplexml_load_file("test.xml");
if test.xml contains "<mywebstore> <products> <product> (...)" then $xml points at <mywebstore>
if test.xml contains "<products> <product> (...)" then $xml points at <products>
Secondly, $xml->[tagName] looks for direct children only, not recursively. Therefore $xml->product finds something only if a <product> tag exists as a child of the root element.
In general, it is better for the code to match the input structure exactly. Adapt your outer loop to the expected input:
foreach($xml->product as $product) {
...
}
or
foreach($xml->products->product as $product) {
...
}
If for some reason the <products> tag can be at various locations in the input XML feed, perhaps proceed in two steps:
// try to locate the <product> nodes
if (count($xml->product) !== 0) {
$productNodes = $xml->product;
} else if (count($xml->products->product) !== 0) {
$productNodes = $xml->products->product;
} else {
throw new Exception('No <product> node found');
}
// do the job
foreach($productNodes as $product){
...
}
Or for extreme flexibility, use an xpath. The below will return a list of all <product> nodes anywhere in the XML feed.
$productNodes = $xml->xpath('//product');
foreach($productNodes as $product){
...
}
I trust the MySQL part is not an issue, so I will just stick to the usual incantation:
Please, don't use mysql_* functions in new code. They are no longer maintained and are officially deprecated. See the red box? Learn about prepared statements instead, and use PDO or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.

how to get elements values from simple xml

I have the following xml document:
<?xml version="1.0"?>
<root>
<offers count="3009">
<offer>
<offerId>25</offerId>
<offer_type>for sale</offer_type>
<offer_status>available</offer_status>
<building_floors></building_floors>
<title>title</title>
<photos count="4">
<photo zIndex="1">1.jpg</photo>
<photo zIndex="2">2.jpg</photo>
<photo zIndex="3">3.jpg</photo>
<photo zIndex="4">4.jpg</photo>
</photos>
</offer>
</offers>
</root>
I am using this php code to get results from the xml:
$xml = simplexml_load_file("offers.xml")
or die("Error: Cannot create object");
foreach($xml->children() as $offers){
foreach($offers->children() as $offer => $data){
echo $data->offerId;echo "<br />";//and so on for each element
foreach ($xml->offers->offer->photos->photo as $aaa){
$photos=$aaa; echo "<br />";
//echo $xml;
$photo = explode("<br /> ", $photos);
foreach($photo as $value) echo $value; echo '<br />';//echo $value
}
}
}
When I try to loop the photo element I get all photos but only for the first offer.
My question is what I am doing wrong and why I do not get photos for each offer?
The problem is with the way you retrieve the photo elements. You start from the root element so it always give you the same node.
You should use $data like this :
foreach ($data->photos->photo as $aaa){
cleaning a bit your code you should use this to display the photo elements:
$xml = simplexml_load_file("offers.xml") or die("Error: Cannot create object");
foreach($xml->children() as $offers){
foreach($offers->children() as $offer){
echo "Offer id : " . $offer->offerId . "<br>";
foreach ($offer->photos->photo as $photo){
$val = (string) $photo;
echo $val . "<br>";
}
}
}

PHP access XML node element

I am trying to edit some XML with PHP. Currently the XML looking something like:
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Main Title</title>
<link>http://exmaple.com</link>
<description> blahblahblah </description>
<language>en</language>
<item>
<title>Tite1</title>
<link>http://www.example.com (THIS IS WHAT I WANT)</link>
<description>blah blah blah</description>
</item>
.
.
.
</channel>
</rss>
I've tried to access the 2nd level link but my code only changes the first Link node value. Here is the code:
$xml->load('http://www.google.com/doodles/doodles.xml');
$element = $xml->getElementsByTagName('channel')->item(0);
$secondlvl = $element->getElementsByTagName('item')->item(0);
$2ndlevellinknode = $element->getElementsByTagName('link')->item(0);
$2ndlevellinknode->nodeValue = $newvalue;
Any suggestions? Also is it possible to use this line of code in a for loop like this
for ($i = 0; $i <= 20; $i++) {
$element = $xml->getElementsByTagName('channel')->item(0);
$secondlvl = $element->getElementsByTagName('item')->item(0);
$2ndlevellinknode = $element->getElementsByTagName('link')->item($i);
$2ndlevellinknode->nodeValue = $newvalue;
}
this should give you an idea.
$f = simplexml_load_file('test.xml');
print $f->channel->title . "\n";
print $f->channel->link . "\n";
print $f->channel->description . "\n";
foreach($f->channel->item as $item) {
print $item->title . "\n";
}

Categories