sql element name using getname() - php

I am new on PHP and xml.
This is the xml file I'm using.
<product product_id = '4'>
<category_id>5</category_id>
<name> chocolate </name>
<price> 120 </price>
<unit> piece </unit>
<quantity> 100 </quantity>
<brandname> catberry </brandname>
<image>NULL</image>
<offer>NULL</offer>
</product>
I cannot get the children element of product.
following loop doesn't work. How can it be done?
code:
function update_products($id, $xml)
{
include_once('config.php');
foreach ($xml->children() as $key ) {
echo $key->getname().'</br>';
foreach ($xml->children->children as $child ) {
echo $child->getname();
}
}
}

Related

Merge SimpleXML elements by SKU attribute

I have 3 xml files with same structure. What I need to do is merge them together via php.
Take a look at my example file below
1.xml
<data>
<product productsku="ABC1" price="550000" pricesale="" hn="1"></product>
<product productsku="ABC2" price="" pricesale="" hn="0"></product>
</data>
2.xml
<data>
<product productsku="ABC2" price="550000" pricesale="" dn="2"></product>
<product productsku="ABC3" price="" pricesale="" dn="0"></product>
</data>
3.xml
<data>
<product productsku="ABC3" price="550000" pricesale="" gn="3"></product>
<product productsku="ABC4" price="" pricesale="" gn="0"></product>
</data>
I would like to get the following result:
<data><product productsku="ABC1" price="550000" pricesale="" hn="1"></product>
<product productsku="ABC2" price="550000" pricesale="" dn="2" hn="0"></product>
<product productsku="ABC3" price="550000" pricesale="" dn="0" gn="3"></product>
<product productsku="ABC4" price="" pricesale="" gn="0"></product>
</data>
The code that I am trying
<?php
$xml1 = file_get_contents('1.xml');
$xml2 = file_get_contents('2.xml');
$targetDom = new DOMDocument();
$targetDom->loadXml($xml1);
$targetXpath = new DOMXpath($targetDom);
$addDom = new DOMDocument();
$addDom->loadXml($xml2);
$addXpath = new DOMXpath($addDom);
// merge attributes of product elements depending on productsku
foreach ($targetXpath->evaluate('//product[#productsku]') as $product) {
$productsku = $product->getAttribute('productsku');
foreach ($addXpath->evaluate('//product[#productsku='.$productsku.']/#*') as $attribute) {
if (!$product->hasAttribute($attribute->name)) {
$product->setAttribute($attribute->name, $attribute->value);
}
}
}
// copy products elements that are not in target dom
foreach ($addXpath->evaluate('//product[#productsku]') as $product) {
$productsku = $product->getAttribute('productsku');
if ($targetXpath->evaluate('count(//product[#productsku='.$productsku.'])') == 0) {
$targetDom->documentElement->appendChild(
$targetDom->importNode($product)
);
}
}
echo $targetDom->saveXml();
I tried the above, it works fine if the SKU is numeric. But my SKU or ID is not a number. And I have 3 xml files
I tried to find the solution on stackoverflow.
But all is not as I expected.
I'm really not good at this. Please help me through a php snippet.
I found the xml_adopt function here: PHP - SimpleXML - AddChild with another SimpleXMLElement
Then it's a matter of loading each file, keeping track of products and overwriting them if the product has only been seen with no price, then adopting them into a single SimpleXMLElement.
<?php
/*
Question Author: Phan Vũ
Question Answerer: Jacob Mulquin
Question: Merge SimpleXML elements by SKU attribute
URL: https://stackoverflow.com/questions/74625741/merge-simplexml-elements-by-sku-attribute
Tags: php, xml
*/
// https://stackoverflow.com/a/11727581/1427345
function xml_adopt($root, $new) {
$node = $root->addChild($new->getName(), (string) $new);
foreach($new->attributes() as $attr => $value) {
$node->addAttribute($attr, $value);
}
foreach($new->children() as $ch) {
xml_adopt($node, $ch);
}
}
$xml = new SimpleXMLElement('<data></data>');
$files = ['1.xml', '2.xml', '3.xml'];
$to_adopt = [];
foreach ($files as $file) {
$load = simplexml_load_file($file);
foreach ($load->product as $product) {
$sku = (string) $product->attributes()['productsku'];
if (!isset($to_adopt[$sku])) {
$to_adopt[$sku] = $product;
} else {
$price = (string) $to_adopt[$sku]->attributes()['price'];
if (empty($price)) {
$to_adopt[$sku]['price'] = $price;
}
$existing_attributes = ((array) $to_adopt[$sku]->attributes())['#attributes'];
foreach ($product->attributes() as $name => $attribute) {
if (!in_array($name, $existing_attributes)) {
$to_adopt[$sku][$name] = $attribute;
}
}
}
}
}
foreach ($to_adopt as $adopt) {
xml_adopt($xml, $adopt);
}
file_put_contents('output.xml', $xml->asXML());
Yields:
<?xml version="1.0"?>
<data>
<product productsku="ABC1" price="550000" pricesale="" hn="1"/>
<product productsku="ABC2" price="550000" pricesale="" hn="0" dn="2"/>
<product productsku="ABC3" price="550000" pricesale="" dn="0" gn="3"/>
<product productsku="ABC4" price="" pricesale="" gn="0"/>
</data>

Merge duplicate content .xml in php

I am learning the php code.
I'm in a situation where it has to be done as soon as possible.
Please help me reorganize my xml duplicate data.
original .xml file
<products>
<product>
<ID>ID1</ID>
<SKU_parent>SKU1</SKU_parent>
<SKU>MA</SKU>
<price>10</price>
<price-sale>5</price-sale>
<KHO1>10</KHO1>
<KHO2>6</KHO2>
<KHO3>2</KHO3>
</product>
<product>
<ID>ID2</ID>
<SKU_parent>SKU2</SKU_parent>
<SKU>MA2</SKU>
<price>500</price>
<price-sale>200</price-sale>
<KHO1>20</KHO1>
<KHO2>0</KHO2>
<KHO3>0</KHO3>
</product>
<product>
<ID>ID3</ID>
<SKU_parent>SKU2</SKU_parent>
<SKU>MA2</SKU>
<price>500</price>
<price-sale>200</price-sale>
<KHO1>0</KHO1>
<KHO2>30</KHO2>
<KHO3>0</KHO3>
</product>
<product>
<ID>ID2</ID>
<SKU_parent>SKU2</SKU_parent>
<SKU>MA2</SKU>
<price>500</price>
<price-sale>200</price-sale>
<KHO1>0</KHO1>
<KHO2>0</KHO2>
<KHO3>40</KHO3>
</product>
into something like this:
<products>
<product>
<ID>ID1</ID>
<SKU_parent>SKU1</SKU_parent>
<SKU>MA</SKU>
<price>10</price>
<price-sale>5</price-sale>
<KHO1>10</KHO1>
<KHO2>6</KHO2>
<KHO3>2</KHO3>
</product>
<product>
<ID>ID2</ID>
<SKU_parent>SKU2</SKU_parent>
<SKU>MA2</SKU>
<price>500</price>
<price-sale>200</price-sale>
<KHO1>20</KHO1>
<KHO2>30</KHO2>
<KHO3>40</KHO3>
</product>
I've tried searching on stackoverflow but it doesn't seem to work.
I appreciate it when someone help me with this php code
For starters, I converted your XML string into an array.
I reduced your array using SKU_parent as a unique key.
I rebuilt the array again into a XML, using the Francis Lewis function (with some slight modifications, by hardcoding the product node if the array key was numeric) - Source: https://stackoverflow.com/a/19987539/4527645
$xml_string = '<products>
<product>
<ID>ID1</ID>
<SKU_parent>SKU1</SKU_parent>
<SKU>MA</SKU>
<price>10</price>
<price-sale>5</price-sale>
<KHO1>10</KHO1>
<KHO2>6</KHO2>
<KHO3>2</KHO3>
</product>
<product>
<ID>ID2</ID>
<SKU_parent>SKU2</SKU_parent>
<SKU>MA2</SKU>
<price>500</price>
<price-sale>200</price-sale>
<KHO1>20</KHO1>
<KHO2>0</KHO2>
<KHO3>0</KHO3>
</product>
<product>
<ID>ID3</ID>
<SKU_parent>SKU2</SKU_parent>
<SKU>MA2</SKU>
<price>500</price>
<price-sale>200</price-sale>
<KHO1>0</KHO1>
<KHO2>30</KHO2>
<KHO3>0</KHO3>
</product>
<product>
<ID>ID2</ID>
<SKU_parent>SKU2</SKU_parent>
<SKU>MA2</SKU>
<price>500</price>
<price-sale>200</price-sale>
<KHO1>0</KHO1>
<KHO2>0</KHO2>
<KHO3>40</KHO3>
</product>
</products>';
$xml = simplexml_load_string($xml_string, 'SimpleXMLElement', LIBXML_NOCDATA);
$json = json_encode($xml);
$xml_array = json_decode($json, true);
$unique = array_reduce($xml_array['product'], function($final, $article){
static $seen = [];
if (!array_key_exists($article['SKU_parent'], $seen)) {
$seen[$article['SKU_parent']] = NULL;
$final[] = $article;
}
return $final;
});
function to_xml(SimpleXMLElement $object, array $data)
{
foreach ($data as $key => $value) {
if (is_array($value)) {
if (is_numeric($key)) {
$new_object = $object->addChild('product');
}
to_xml($new_object, $value);
} else {
if ($key != 0 && $key == (int) $key) {
$key = "key_$key";
}
$object->addChild($key, $value);
}
}
}
$xml = new SimpleXMLElement('<products/>');
to_xml($xml, $unique);
header('Content-Type: text/xml');
print $xml->asXML();
You can also check a working example of this code here: https://onlinephp.io/c/1d06d
This code eliminates the duplicate product nodes by SKU_parent. In order to merge all the values that are not 0, you have to improve the array_reduce or find another method with array_merge_recursive for example. This is just a starting point.
If you're simply using product->ID as the identifier, you could just do:
$xml = new DOMDocument;
$xml->load('dedup.xml');
$xpath = new DOMXpath($xml);
$dupNodes = $xpath->query('/products/product[ID = preceding-sibling::product/ID]');
foreach ($dupNodes as $dupNode) {
$dupNode->parentNode->removeChild($dupNode);
}
echo $xml->saveXML();

PHP - referencing an XML attribute using simpleXML

Using the simplexml_load_file method, I am trying to retrieve and display the text of all name elements (from an XML file below) that have an attribute named "type' with the value of 'tablet.' This foreach loop is only displaying the value of the first element. Any advice? Thanks!
$XMLproducts = simplexml_load_file("products.xml");
foreach($XMLproducts->product->attributes() as $a => $b) {
$i = 0;
if ($b == "Tablet") {
echo $XMLproducts->product[$i]->name;
echo "<br>";
}
}
Here is the XML file:
<products>
<product type="Desktop">
<name>Desktop 1</name>
</product>
<product type="Tablet">
<name>Ipad 1</name>
</product>
<product type="Desktop">
<name>Desktop 2</name>
</product>
<product type="Tablet">
<name>Ipad 2</name>
</product>
</products>
As Scuzzy mentioned in the comments, using SimpleXMLElement::xpath simplifies the solution:
foreach ($XMLproducts->xpath('/products/product[#type="Tablet"]/name') as $name) {
echo $name , "<br>";
}
Try this
$XMLproducts = simplexml_load_file("products.xml");
foreach($XMLproducts->products->product as $product) {
foreach ($product->attributes() as $a => $b) {
$i = 0;
if ($b == "Tablet") {
echo $XMLproducts->product[$i]->name;
echo "<br>";
}
}
}

Add element to XML when not existing in child PHP

<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<a>product a</a>
<b>data</b>
<c>data</c>
</product>
<product>
<a>product b</a>
<c>data</c>
</product>
</products>
When child-element < B > is missing, i want to add it to the XML file. so the < product > ends up like this.No data has to be added, just the element.
<product>
<a>data</a>
<c>data</c>
<b></b>
</product>
can this be done with simplexml ?
<?php
$xml = simplexml_load_file("xml.xml", NULL, TRUE);
foreach ($xml->children() as $child) {}
This is definitely possible. Here's an example of how to do it (assuming you're not worried about the order in which the child element occurs):
$xml = new SimpleXMLElement('xml.xml', NULL, TRUE);
foreach ($xml->children() as $child) {
if (isset($child->b)) {
continue;
}
$child->b = '';
}
// output to new file
$xml->asXML('xml2.xml');
You can also find an online Demo that contains all data:
<?php
/**
* Add element to XML when not existing in child PHP
* #link http://stackoverflow.com/q/19562757/367456
*/
$xml = new SimpleXMLElement('<r><product><b>hello</b></product><product/><product/></r>');
foreach ($xml->children() as $child) {
if (isset($child->b)) {
continue;
}
$child->b = '';
}
$xml->asXML('php://output');
Program Output (beautified):
<?xml version="1.0"?>
<r>
<product>
<b>hello</b>
</product>
<product>
<b></b>
</product>
<product>
<b></b>
</product>
</r>

How do I get to read all the products from XML

I have many categories in my XML file. How can I read all the products in it?
It only reads the first category.
I am including the xml file for you to look at. Here is the PHP code I'm using:
//get products from xml file
foreach($xml->CREATED->CATEGORY as $product){
$atts = $product->PRODUCT->attributes();
$productitemid = $atts['ITEM'];
$title = $product->MODEL;
$rrp = $product->RRP;
$productsdescription = $product->DESCRIPTION;
$prodname = $product->NAME;
echo $productitemid.' - ' ;
// echo $product->id.' - ';
mysql_query("INSERT INTO products (products_id,products_model,products_price,products_status) VALUES ('$productitemid','$title','$rrp','1')");
mysql_query("INSERT INTO products_description (products_id,products_name,products_description) VALUES ('$productitemid','$prodname','$productsdescription')");
}
And here is the XML structure:
<?xml version="1.0" encoding="iso-8859-1"?>
<STOREITEMS>
<CREATED value="Fri Feb 22 1:01:02 GMT 2013">
<CATEGORY id="441" name=" > test1">
<PRODUCT ITEM="12796">
<NAME>test1</NAME>
<MODEL>bb2018</MODEL>
<PRICE>2.28</PRICE>
<RRP>3.99</RRP>
<THUMB>bb2018s.jpg</THUMB>
<IMAGE>bb2018.jpg</IMAGE>
<DESCRIPTION>
test1
</DESCRIPTION>
<POWER/>
<SIZE/>
<ATTRIBUTES NAME="Size" ATTRIBUTEID="2">
<ATTRIBUTEVALUES VALUE="16" TITLE="Small" PRICEADJUST="0.00"/>
<ATTRIBUTEVALUES VALUE="17" TITLE="Medium" PRICEADJUST="0.00"/>
<ATTRIBUTEVALUES VALUE="18" TITLE="Large" PRICEADJUST="0.00"/>
</ATTRIBUTES>
</PRODUCT>
<CATEGORY id="442" name=" > test2">
<PRODUCT ITEM="12805">
<NAME>test2</NAME>
<MODEL>bb2034</MODEL>
<PRICE>0.58</PRICE>
<RRP>1.50</RRP>
<THUMB>bb2034s.jpg</THUMB>
<IMAGE>bb2034.jpg</IMAGE>
<DESCRIPTION>
test2
</DESCRIPTION>
<POWER/>
<SIZE/>
</PRODUCT>
<CATEGORY id="4423" name=" > test3">
<PRODUCT ITEM="13719">
<NAME>test3?</NAME>
<MODEL>BCPG02</MODEL>
<PRICE>2.83</PRICE>
<RRP>4.95</RRP>
<THUMB>bcg02s.jpg</THUMB>
<IMAGE>bcpg02.jpg</IMAGE>
<DESCRIPTION>
test3
</DESCRIPTION>
</PRODUCT>
</CATEGORY>
</CREATED>
</STOREITEMS>
i have done it like this it works. How do i get the products from the categorys then go to the next cateory and get the next porducts the dabase needs them sequence
//i have done it like this it works
$doc = new DOMDocument();
$var = $doc->load('shop.xml');
$root = $doc->documentElement; //root node
$items = $doc->getElementsByTagName('PRODUCT');
$cat = $doc->getElementsByTagName('CATEGORY');
foreach ($cat as $cats){
foreach ($items as $bar)
if ($categoriesid == $b)
$productsid = $bar->getAttribute('ITEM');
$modelcode = $bar->getElementsByTagName('MODEL')->item(0)->nodeValue;
$rrp = $bar->getElementsByTagName('RRP')->item(0)->nodeValue;
$productsdescription = $bar->getElementsByTagName('DESCRIPTION')->item(0)->nodeValue;
$prodname = $bar->getElementsByTagName('NAME')->item(0)->nodeValue;
$categoriesid = $cats->getAttribute('id');
$categoriesname = $cats->getAttribute('name');
}
You could try using DOMDocument like this:
$doc = new DOMDocument();
$var = $doc->load('yourxml.xml');
$root = $doc->documentElement; //root node
$items = $doc->getElementsByTagName('product');
foreach ($items as $bar)
{
$name = $bar->getElementsByTagName('name')->item(0)->nodeValue;
$model = $bar->getElementsByTagName('model')->item(0)->nodeValue;
$price = ....
//do something with the values
}
Please take look on below sample piece of code
hope this help you.
<?php
$xmlString= '<xml Version="1.0">
<created>
<category>
<product id="a"/>
</category>
<category>
<product id="b"/>
</category>
<category>
<product id="c"/>
</category>
<category>
<product id="d"/>
</category>
</created>
</xml>';
$xml = new SimpleXMLElement($xmlString);
foreach ($xml->created->category as $element)
{
foreach($element as $val)
{
echo " product : ".$val->attributes();
}
}
?>
Output of this code will read all product attribute
product : a product : b product : c product : d

Categories