How to add spaces between values in xml? - php

I have to create an xml out of other xml. I already have the answer to that, but then I'm facing another problem. The output of the xml is quite messy in the tag.
The xml is this:
<rss>
<item id="12907">
<g:productname>Black Bag</g:productname>
<g:detailed_images>
<g:detailed_image>Image1.jpg</g:detailed_image>
<g:detailed_image>Image2.jpg</g:detailed_image>
<g:detailed_image>Image3.jpg</g:detailed_image>
<g:detailed_image>Image4.jpg</g:detailed_image>
<g:detailed_image>Image5.jpg</g:detailed_image>
<g:detailed_image>Image6.jpg</g:detailed_image>
<g:detailed_image>Image7.jpg</g:detailed_image>
<g:detailed_image>Image8.jpg</g:detailed_image>
<g:detailed_image>Image9.jpg</g:detailed_image>
<g:detailed_image>Image10.jpg</g:detailed_image>
<g:detailed_image>Image11.jpg</g:detailed_image>
<g:detailed_image>Image12.jpg</g:detailed_image>
</g:detailed_images>
</item>
<item id="12906">
<g:productname>Yellow Bag</g:productname>
<g:detailed_images>
<g:detailed_image>Image1.jpg</g:detailed_image>
<g:detailed_image>Image2.jpg</g:detailed_image>
<g:detailed_image>Image3.jpg</g:detailed_image>
<g:detailed_image>Image4.jpg</g:detailed_image>
<g:detailed_image>Image5.jpg</g:detailed_image>
<g:detailed_image>Image6.jpg</g:detailed_image>
<g:detailed_image>Image7.jpg</g:detailed_image>
<g:detailed_image>Image8.jpg</g:detailed_image>
<g:detailed_image>Image9.jpg</g:detailed_image>
<g:detailed_image>Image10.jpg</g:detailed_image>
<g:detailed_image>Image11.jpg</g:detailed_image>
<g:detailed_image>Image12.jpg</g:detailed_image>
</g:detailed_images>
</item>
</rss>
The php code that I'm using to create another xml file is this
<?php
$document = new DOMDocument;
$document->formatOutput = true;
$document->preserveWhiteSpace = false;
$document->load('xml_feeds.xml');
$xpath = new DOMXPath($document);
$fields = [
'productname' => 'string(g:productname)',
'detailed_images' => 'string(g:detailed_images)'
];
$xml = new DOMDocument;
$xml->formatOutput = true;
$xml->preserveWhiteSpace = false;
$rss = $xml->appendChild($xml->createElement('rss'));
foreach ($xpath->evaluate('//item') as $item) {
//create tag item
$createItem = $rss->appendChild($xml->createElement('item'));
//getting item's attribute value
$valueID = $item->getAttribute('id');
//create attribute
$itemAttribute = $xml->createAttribute('id');
$itemAttribute->value = $valueID;
$createItem->appendChild($itemAttribute);
foreach ($fields as $caption => $expression) {
$value = $xpath->evaluate($expression, $item);
$createItem->appendChild($xml->createElement($caption, $value));
}
}
$xml->save('new_createxml2.xml');
?>
The result of the new_createxml2.xml is this
<?xml version="1.0"?>
<rss>
<item id="12907">
<productname>Black Bag</productname>
<detailed_images>Image1.jpgImage2.jpgImage3.jpgImage4.jpgImage3.jpgImage4.jpgImage5.jpgImage6.jpgImage7.jpgImage8.jpgImage9.jpgImage10.jpgImage11.jpgImage12.jpg</detailed_images>
</item>
<item id="12906">
<productname>Yellow Bag</productname>
<detailed_images>Image1.jpgImage2.jpgImage3.jpgImage4.jpgImage3.jpgImage4.jpgImage5.jpgImage6.jpgImage7.jpgImage8.jpgImage9.jpgImage10.jpgImage11.jpgImage12.jpg</detailed_images>
</item>
</rss>
I really wonder how can I create the xml tidier than what I've made. I want it to display like this actually:
<?xml version="1.0"?>
<rss>
<item id="12907">
<productname>Black Bag</productname>
<detailed_images>Image1.jpg, Image2.jpg, Image3.jpg, Image4.jpg, Image3.jpg, Image4.jpg, Image5.jpg, Image6.jpg, Image7.jpg, Image8.jpg, Image9.jpg, Image10.jpg, Image11.jpg, Image12.jpg</detailed_images>
</item>
<item id="12906">
<productname>Yellow Bag</productname>
<detailed_images>Image1.jpg, Image2.jpg, Image3.jpg, Image4.jpg, Image3.jpg, Image4.jpg, Image5.jpg, Image6.jpg, Image7.jpg, Image8.jpg, Image9.jpg, Image10.jpg, Image11.jpg, Image12.jpg</detailed_images>
</item>
</rss>
Thank you for your help

The way you've tried it is quite simple for some things, but as you've found out that this method fails when you want processing for each individual piece of data. When you use 'string(g:detailed_images)' - this is the text content of all of the subnodes in your document, which is why you have all of the values stuck together. You could then process this string with some form of regular expression - but as you have no control of the content it's difficult to know what you are going to find.
Changing it to a more traditional - get values using a specific XPath call and processing the values allows you more control over the result.
foreach ($xpath->evaluate('//item') as $item) {
//create tag item
$createItem = $rss->appendChild($xml->createElement('item'));
//getting item's attribute value
$valueID = $item->getAttribute('id');
//create attribute
$itemAttribute = $xml->createAttribute('id');
$itemAttribute->value = $valueID;
$createItem->appendChild($itemAttribute);
$prodName = $xpath->evaluate("string(g:productname)", $item);
$createItem->appendChild($xml->createElement('productname', $prodName));
$images = [];
foreach ( $xpath->query("descendant::g:detailed_image", $item) as $image ) {
$images[] = $image->nodeValue;
}
$createItem->appendChild($xml->createElement('detailed_images',
implode(",", $images)));
}

Related

Remove all nodes from XML but specific ones in PHP

I have an XML from Google with a content like this:
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>E-commerce's products.</title>
<description><![CDATA[Clothing and accessories.]]></description>
<link>https://www.ourwebsite.com/</link>
<item>
<title><![CDATA[Product #1 title]]></title>
<g:brand><![CDATA[Product #1 brand]]></g:brand>
<g:mpn><![CDATA[5643785645]]></g:mpn>
<g:gender>Male</g:gender>
<g:age_group>Adult</g:age_group>
<g:size>Unica</g:size>
<g:condition>new</g:condition>
<g:id>fr_30763_06352</g:id>
<g:item_group_id>fr_30763</g:item_group_id>
<link><![CDATA[https://www.ourwebsite.com/product_1_url.htm?mid=62367]]></link>
<description><![CDATA[Product #1 description]]></description>
<g:image_link><![CDATA[https://data.ourwebsite.com/imgprodotto/product-1_big.jpg]]></g:image_link>
<g:sale_price>29.25 EUR</g:sale_price>
<g:price>65.00 EUR</g:price>
<g:shipping_weight>0.5 kg</g:shipping_weight>
<g:featured_product>y</g:featured_product>
<g:product_type><![CDATA[Product #1 category]]></g:product_type>
<g:availability>in stock</g:availability>
<g:availability_date>2022-08-10T00:00-0000</g:availability_date>
<qty>3</qty>
<g:payment_accepted>Visa</g:payment_accepted>
<g:payment_accepted>MasterCard</g:payment_accepted>
<g:payment_accepted>CartaSi</g:payment_accepted>
<g:payment_accepted>Aura</g:payment_accepted>
<g:payment_accepted>PayPal</g:payment_accepted>
</item>
<item>
<title><![CDATA[Product #2 title]]></title>
<g:brand><![CDATA[Product #2 brand]]></g:brand>
<g:mpn><![CDATA[573489547859]]></g:mpn>
<g:gender>Unisex</g:gender>
<g:age_group>Adult</g:age_group>
<g:size>Unica</g:size>
<g:condition>new</g:condition>
<g:id>fr_47362_382936</g:id>
<g:item_group_id>fr_47362</g:item_group_id>
<link><![CDATA[https://www.ourwebsite.com/product_2_url.htm?mid=168192]]></link>
<description><![CDATA[Product #2 description]]></description>
<g:image_link><![CDATA[https://data.ourwebsite.com/imgprodotto/product-2_big.jpg]]></g:image_link>
<g:sale_price>143.91 EUR</g:sale_price>
<g:price>159.90 EUR</g:price>
<g:shipping_weight>8.0 kg</g:shipping_weight>
<g:product_type><![CDATA[Product #2 category]]></g:product_type>
<g:availability>in stock</g:availability>
<g:availability_date>2022-08-10T00:00-0000</g:availability_date>
<qty>1</qty>
<g:payment_accepted>Visa</g:payment_accepted>
<g:payment_accepted>MasterCard</g:payment_accepted>
<g:payment_accepted>CartaSi</g:payment_accepted>
<g:payment_accepted>Aura</g:payment_accepted>
<g:payment_accepted>PayPal</g:payment_accepted>
</item>
...
</channel>
</rss>
I need to produce a XML file purged from all the tags inside <item> except for <g:mpn>, <link>, <g:sale_price> and <qty>.
In the example above, the result should be
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>E-commerce's products.</title>
<description><![CDATA[Clothing and accessories.]]></description>
<link>https://www.ourwebsite.com/</link>
<item>
<g:mpn><![CDATA[5643785645]]></g:mpn>
<link><![CDATA[https://www.ourwebsite.com/product_1_url.htm?mid=62367]]></link>
<g:sale_price>29.25 EUR</g:sale_price>
<qty>3</qty>
</item>
<item>
<g:mpn><![CDATA[573489547859]]></g:mpn>
<link><![CDATA[https://www.ourwebsite.com/product_2_url.htm?mid=168192]]></link>
<g:sale_price>143.91 EUR</g:sale_price>
<qty>1</qty>
</item>
...
</channel>
</rss>
I've looked at SimpleXML, DOMDocument, XPath docs but I couldn't find the way to exclude specific elements. I don't want to select by name the nodes I have to delete, as in a future Google could add some nodes and they will not be deleted by my script.
I've also tried to loop through namespaced elements with SimpleXML and unset them if not matched with the nodes I have to keep:
$g = $element->children($namespaces['g']); //$element is the SimpleXMLElement of <item> tag
foreach ($g as $gchild) {
if ($gchild->getName() != "mpn") { //for example
unset($gchild);
}
}
but the code above doesn't remove all nodes except for <g:mpn>, for example.
PS: consider the fact that the XML contains both namespaced and not namespaced elements
Thank you in advance.
EDIT:
I've managed to do this with the following code:
$elementsToKeep = array("mpn", "link", "sale_price", "qty");
$domdoc = new DOMDocument();
$domdoc->preserveWhiteSpace = FALSE;
$domdoc->formatOutput = TRUE;
$domdoc->loadXML($myXMLDocument->asXML()); //$myXMLDocument is the SimpleXML document related to the original XML
$xpath = new DOMXPath($domdoc);
foreach ($element->children() as $child) {
$cname = $child->getName();
if (!in_array($cname, $elementsToKeep)) {
foreach($xpath->query('/rss/channel/item/'.$cname) as $node) {
$node->parentNode->removeChild($node);
}
}
}
$g = $element->children($namespaces['g']);
foreach ($g as $gchild) {
$gname = $gchild->getName();
if (!in_array($gname, $elementsToKeep)) {
foreach($xpath->query('/rss/channel/item/g:'.$gname) as $node) {
$node->parentNode->removeChild($node);
}
}
}
I've used DOMDocument and DOMXPath and two loops on no-namespaced tags and namespaced tags, in order to use the removeChild function of DOMDocument.
Really there is not a cleaner solution?? Thanks again
Somewhat simpler:
$items = $xpath->query('//item');
foreach($items as $item) {
$targets = $xpath->query('.//*',$item);
foreach($targets as $target) {
if (!in_array($target->localName, $elementsToKeep)) {
$target->parentNode->removeChild($target);
}
};
};
Use XPath to express all child elements you want to remove.
Then use the library of your choice to remove the elements.
SimpleXMLElement example:
$sxe = simplexml_load_string($xml);
foreach ($sxe->xpath('//item/*[
not(
name() = "g:mpn"
or name() = "link"
or name() = "g:sale_price"
or name() = "qty"
)
]') as $child) unset($child[0]);
echo $sxe->asXML(), "\n";
DOMDocument example:
This one is mainly identical to the previous example, with a bit of a variation on the xpath expression to explicitly use namespace URIs for the elements. This prevents that it breaks when the namespace prefix changes (it also works in the SimpleXMLElement example):
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
foreach ($xpath->query('//item/*[
not(
(local-name() = "mpn" and namespace-uri() = "http://base.google.com/ns/1.0")
or (local-name() = "link" and namespace-uri() = "")
or (local-name() = "sale_price" and namespace-uri() = "http://base.google.com/ns/1.0")
or (local-name() = "qty" and namespace-uri() = "")
)
]') as $child) {
$child->parentNode->removeChild($child);
}
echo $doc->saveXML(), "\n";

PHP XML Trying to add stock_quantity by item id into main feed

I would like merge two feeds the one has all product data and has an product identifier ITEM_ID in every , the second XML feed has same value as ITEM_ID in <item id=""> and inside this <item> has stock_quantity tag but I can't figure it out how to merge these values.. The three dots in XML content means that there are more item tags
The first feed (items.xml) looks like:
<SHOP>
<SHOPITEM>
<DESCRIPTION>
<![CDATA[ <p><span>Just an description. </span></p> ]]>
</DESCRIPTION>
<URL>https://www.korkmaz.cz/tombik-cajova-konvice-2l/</URL>
<IMGURL>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52_konvice-tombik-1l.jpg?5f4fcd7d</IMGURL>
<IMGURL_ALTERNATIVE>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52-1_bez-trouby.jpg?5f4fcd7d</IMGURL_ALTERNATIVE>
<PURCHASE_PRICE>487,99</PURCHASE_PRICE>
<PRICE_VAT>797,00</PRICE_VAT>
<VAT>21%</VAT>
<CATEGORYTEXT>KUCHYŇSKÉ DOPLŇKY | Příprava čaje a kávy</CATEGORYTEXT>
<DELIVERY_DATE>0</DELIVERY_DATE>
<ITEM_ID>A093</ITEM_ID>
...
</SHOPITEM>
</SHOP>
The second feed (stock.xml) loks like:
<item_list>
<item id="A093">
<delivery_time orderDeadline="2021-09-14 12:00">2021-09-16 12:00</delivery_time>
<stock_quantity>32</stock_quantity>
...
</item>
</item_list>
So I trying something like this (similar method like the $item->ITEM_ID was in separate tag in stock.xml) but doesn't work for me..
<?php
$catalog_name = 'items.xml';
$catalog_url = 'https://admin.srovnej-ceny.cz/export/ca1b20bb6415b2d93ff36c9e3df3f96c.xml';
file_put_contents($catalog_name, fopen($catalog_url, 'r'));
$stock_name = 'stock.xml';
$stock_url = 'https://www.korkmaz.cz/heureka/export/availability.xml';
file_put_contents($stock_name, fopen($stock_url, 'r'));
$stocks=simplexml_load_file("stock.xml") or die("Error: Cannot create object");
foreach($stocks->children() as $item) {
$_stocks["" . $item['id'] . ""] = $item->stock_quantity;
}
$xml=simplexml_load_file("items.xml") or die("Error: Cannot create object");
$dom = new DOMDocument();
$dom->encoding = 'utf-8';
$dom->xmlVersion = '1.0';
$dom->formatOutput = true;
$xml_file_name = 'products.xml';
$root = $dom->createElement('SHOP');
$i=0;
foreach($xml->children() as $item) {
$item_node = $dom->createElement('SHOPITEM');
//$track = $xml->addChild('item');
$item_node->appendChild($dom->createElement('ITEM_ID', $item->ITEM_ID ));
$item_node->appendChild($dom->createElement('PRODUCTNAME', htmlspecialchars($item->PRODUCTNAME) ));
$item_node->appendChild($dom->createElement('DESCRIPTION', htmlspecialchars($item->DESCRIPTION)));
$item_node->appendChild($dom->createElement('MANUFACTURER', $item->MANUFACTURER));
$item_node->appendChild($dom->createElement('EAN', strval($item->EAN) ));
$item_node->appendChild($dom->createElement('IMGURL', strval($item->IMGURL)));
$item_node->appendChild($dom->createElement('PRICE_VAT', strval($item->PRICE_VAT)));
$item_node->appendChild( $dom->createElement('STOCK', $_stocks["" . $item['id'] . ""] ) );
$root->appendChild($item_node);
$i++;
}
$dom->appendChild($root);
$dom->save($xml_file_name);
echo "$i items to $xml_file_name has been successfully created";
?>
Without simplexml you can quite easily "merge" the two documents using the standard DOMDocument and DOMXPath functions.
Given input files as follows:
items.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<SHOP>
<SHOPITEM>
<DESCRIPTION>
<![CDATA[ <p><span>Just an description. </span></p> ]]>
</DESCRIPTION>
<URL>https://www.korkmaz.cz/tombik-cajova-konvice-2l/</URL>
<IMGURL>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52_konvice-tombik-1l.jpg?5f4fcd7d</IMGURL>
<IMGURL_ALTERNATIVE>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52-1_bez-trouby.jpg?5f4fcd7d</IMGURL_ALTERNATIVE>
<PURCHASE_PRICE>487,99</PURCHASE_PRICE>
<PRICE_VAT>797,00</PRICE_VAT>
<VAT>21%</VAT>
<CATEGORYTEXT>KUCHYŇSKÉ DOPLŇKY | Příprava čaje a kávy</CATEGORYTEXT>
<DELIVERY_DATE>0</DELIVERY_DATE>
<ITEM_ID>A093</ITEM_ID>
</SHOPITEM>
<SHOPITEM>
<DESCRIPTION>
<![CDATA[ <p><span>Just an description. </span></p> ]]>
</DESCRIPTION>
<URL>https://www.korkmaz.cz/tombik-cajova-konvice-2l/</URL>
<IMGURL>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52_konvice-tombik-1l.jpg?5f4fcd7d</IMGURL>
<IMGURL_ALTERNATIVE>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52-1_bez-trouby.jpg?5f4fcd7d</IMGURL_ALTERNATIVE>
<PURCHASE_PRICE>1850,99</PURCHASE_PRICE>
<PRICE_VAT>2598,00</PRICE_VAT>
<VAT>21%</VAT>
<CATEGORYTEXT>KUCHYŇSKÉ DOPLŇKY | Příprava čaje a kávy</CATEGORYTEXT>
<DELIVERY_DATE>0</DELIVERY_DATE>
<ITEM_ID>A094</ITEM_ID>
</SHOPITEM>
<SHOPITEM>
<DESCRIPTION>
<![CDATA[ <p><span>Just an description. </span></p> ]]>
</DESCRIPTION>
<URL>https://www.korkmaz.cz/tombik-cajova-konvice-2l/</URL>
<IMGURL>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52_konvice-tombik-1l.jpg?5f4fcd7d</IMGURL>
<IMGURL_ALTERNATIVE>https://cdn.myshoptet.com/usr/www.korkmaz.cz/user/shop/orig/52-1_bez-trouby.jpg?5f4fcd7d</IMGURL_ALTERNATIVE>
<PURCHASE_PRICE>200,99</PURCHASE_PRICE>
<PRICE_VAT>300,00</PRICE_VAT>
<VAT>21%</VAT>
<CATEGORYTEXT>KUCHYŇSKÉ DOPLŇKY | Příprava čaje a kávy</CATEGORYTEXT>
<DELIVERY_DATE>0</DELIVERY_DATE>
<ITEM_ID>A095</ITEM_ID>
</SHOPITEM>
stock.xml
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<item_list>
<item id="A093">
<delivery_time orderDeadline="2021-09-14 12:00">2021-09-16 12:00</delivery_time>
<stock_quantity>32</stock_quantity>
</item>
<item id="A094">
<delivery_time orderDeadline="2021-09-14 12:00">2021-09-16 12:00</delivery_time>
<stock_quantity>8366</stock_quantity>
</item>
<item id="A095">
<delivery_time orderDeadline="2021-09-14 12:00">2021-09-16 12:00</delivery_time>
<stock_quantity>6732</stock_quantity>
</item>
</item_list>
To generate the "combined xml" type output based upon matching item IDS:
<?php
/*
#
# XML file merge
#
Read "stock.xml" and find matching elements in "items.xml"
- update "items.xml" with nodes cloned from "stock.xml"
*/
function getdom($file){
libxml_use_internal_errors( true );
$dom=new DOMDocument;
$dom->validateOnParse=true;
$dom->recover=true;
$dom->strictErrorChecking=true;
$dom->preserveWhiteSpace=true;
$dom->formatOutput=true;
$dom->load($file);
libxml_clear_errors();
return $dom;
}
$items=getdom('items.xml');
$xpi=new DOMXPath($items);
$stock=getdom('stock.xml');
$xps=new DOMXPath($stock);
/*
If ALL nodes from "stock.xml" are to be merged per ID then set `$merge_only_selected=false`
`$merge_nodes` is an array of nodes from "stock.xml" that will be merged if `$merge_only_selected` is true
*/
$merge_only_selected=true;
$merge_nodes=array('stock_quantity','stock_supplier');
#Find all items in the "stock.xml" file to get the item ID
$col=$xps->query( '//item[#id]' );
foreach( $col as $node ){
#The ID from the "item"
$id=$node->getAttribute('id');
# nodelist of items within "items.xml" that have the same ID.
$item=$xpi->query( sprintf( '//SHOPITEM/ITEM_ID[ text()="%s" ]', $id ) );
# only proceed if we have found a matching node in "items.xml"
if( $item && $item->length > 0 ){
# Find the matched element
$obj=$item->item(0);
# Find the children from the "item"
$children=$node->childNodes;
# for each child found, clone it and import to the "items.xml" file
foreach( $children as $child ){
if( $child->nodeType==XML_ELEMENT_NODE && $id==$obj->nodeValue ){
if( $merge_only_selected==true && !in_array( $child->tagName, $merge_nodes ) ){
continue;
}
$clone=$child->cloneNode(true);
$obj->parentNode->appendChild( $items->importNode( $clone, true ) );
}
}
}
}
#To actually save the modified "items.xml" file:
#$items->save('items.xml');
#To simply view the changes:
printf('<textarea cols=150 rows=50>%s</textarea>',$items->saveXML() );
?>
This is a lot easier with DOM+Xpath. You can use DOMXpath::evaluate() to fetch node lists and scalar values from the XML.
An Xpath expression like /SHOP/SHOP_ITEM returns a DOMNodeList which implements Traversable to support foreach().
But Xpath expression can return scalar values as well. A boolean if they are a condition or a string/number if they contain a type cast or function call. string(/item_list/item[#id="A093"]/stock_quantity) will return the text content of the first matching node or an empty string.
DOMDocument::importNode() allows you to copy a node from another document. But in this case I would suggest creating a new node with a name matching the existing elements.
// bootstrap the XML
$shopDocument = new DOMDocument();
// ignoring pure whitespace nodes (indentation)
$shopDocument->preserveWhiteSpace = FALSE;
$shopDocument->loadXML(getShopXML());
$shopXpath = new DOMXpath($shopDocument);
$stocksDocument = new DOMDocument();
$stocksDocument->loadXML(getStocksXML());
$stocksXpath = new DOMXpath($stocksDocument);
// iterate the shop items
foreach ($shopXpath->evaluate('/SHOP/SHOPITEM') as $shopItem) {
// get the item ID
$itemID = $shopXpath->evaluate('string(ITEM_ID)', $shopItem);
$stockQuantity = 0;
if ($itemID !== '') {
// fetch the stock quantity using the item id
$stockQuantity = (int)$stocksXpath->evaluate(
"string(/item_list/item[#id = '$itemID']/stock_quantity)"
);
// check if here is a "STOCK_QUANTITY" element in the item
if ($shopXpath->evaluate('count(STOCK_QUANTITY) > 0', $shopItem)) {
// update it
foreach ($shopXpath->evaluate('STOCK_QUANTITY', $shopItem) as $quantity) {
$quantity->textContent = (string)$stockQuantity;
}
} else {
// add one
$shopItem
->appendChild($shopDocument->createElement('STOCK_QUANTITY'))
->textContent = (string)$stockQuantity;
}
}
}
$shopDocument->formatOutput = TRUE;
echo $shopDocument->saveXML();

Same variable from multiple XML

$var1 = new SimpleXMLElement('CSVXML/xvar.xml', null, true);
$var2 = new SimpleXMLElement('CSVXML/yvar.xml', null, true);
let's say I get variables from two diffrents XML files, in the first XML files
<Number>3698</Number>
<InternalNumber>1</InternalNumber>
<Name>Bob</Name>
<Number>3500</Number>
<InternalNumber>2</InternalNumber>
<Name>Mike</Name>
<Number>2775</Number>
<InternalNumber>3</InternalNumber>
<Name>Dan</Name>
in the second XML I get the followings
<player>3698</player>
<group>A</group>
I do this
$varID = $var1->Number;
$varnumber = $var2->player;
if ($varID == $varnumber ){
echo '$var1->InternalNumber';
}
is this possible ?
I simply want to put out a variable, is A for XML! = B from XML2, is there anyway possible to do that?
I found this working fine. tested link
<?php
$str = <<<XML
<items>
<item>
<Number>3698</Number>
<InternalNumber>1</InternalNumber>
<Name>Bob</Name>
</item>
<item>
<Number>3500</Number>
<InternalNumber>2</InternalNumber >
<Name>Mike</Name>
</item>
<item>
<Number>2775</Number>
<InternalNumber>3</InternalNumber>
<Name>Dan</Name>
</item>
</items>
XML;
$str2 = <<<XML
<item>
<player>3698</player>
<group>A</group>
</item>
XML;
$da = new SimpleXMLElement($str2);
$varnumber = $da->player;
$data = new SimpleXMLElement($str);
foreach ($data->item as $item)
{
$this_number = $item->Number;
//echo $this_number."-".$item->InternalNumber."-".$varnumber."\n";
if((int)$this_number == (int)$varnumber ){
$this_internalnumber = $item->InternalNumber;
echo $this_internalnumber."\n";
}
else{
echo "No Match found \n";
}
}
Hope this helps.

How to correct this code for adding selected xml tags from one xml source into another using xpath and php class methods

I want to read the following xml and find specific xml tags by their id values , Finally i want to copy these selected tags inside another xml using php user define class methods: sample given below:
<items>
<item>
<id>1</id>
<name>Item-1</name>
<price>10</price>
</item>
<item>
<id>2</id>
<name>Item-2</name>
<price>20</price>
</item>
<item>
<id>3</id>
<name>Item-3</name>
<price>30</price>
</item>
</items>
<customer>
<purchasedItems>
// add the xml here for the purchased Item chosen by id values
</purchasedItems>
</customer>
If customer purchased Item-1 and Item-3, then output will be:
<customer>
<purchasedItems>
<item>
<id>1</id>
<name>Item-1</name>
<price>10</price>
</item>
<item>
<id>3</id>
<name>Item-3</name>
<price>30</price>
</item>
</purchasedItems>
</customer>
i try with the following code which is not working :
<?php
header('Content-Type: text/xml');
class Items {
public static function addItem($purchasedItemsXml, $Items, $parentTag, $idTag ,$id)
{
$docSource = new DOMDocument();
$docSource->loadXML($Items);
$docDest = new DOMDocument();
$docDest->loadXML($purchasedItemsXml);
$xpath = new DOMXPath($docSource);
$result = $xpath->query("//{$idTag}[text()='{$id}']/parent::*");
$result = $docDest->importNode($result->item(0), true);
$items = $docDest->getElementsByTagName($parentTag)->item(0);
$items->appendChild($result);
echo $docDest->saveXML();
return ;
}
}
Updates: After changing Following code,Now Its Working Thanks to all.
class purchasedItems extends Items{
public static function addPurchasedItems($purchasedItemsXml, $Items, $parentTag, $idTag, $ids){
$count =0;
foreach ($ids as $id) {
if($count==0){
$xml = self::addItem($purchasedItemsXml, $Items, $parentTag, $idTag, $id);
}
else{
$xml = self::addItem($xml, $Items, $parentTag, $idTag, $id);
}
$count++;
}
echo $xml;
return ;
}
}
$Items = "<items>
<item>
<id>1</id>
<name>Item-1</name>
<price>10</price>
</item>
<item>
<id>2</id>
<name>Item-2</name>
<price>20</price>
</item>
<item>
<id>3</id>
<name>Item-3</name>
<price>30</price>
</item>
</items>";
$purchasedItemsXml = "<customer>
<purchasedItems>
</purchasedItems>
</customer>";
$ids = array(1, 3);
$parentTag = 'purchasedItems';
$idTag = 'id';
purchasedItems::addPurchasedItems($purchasedItemsXml, $Items, $parentTag, $idTag, $ids);
?>
as a beginner, i am sure i did some mistake, but i am now stuck at point.I want to do this using the existing given class hierarchy.please help me with this code.Thanks
You can achive this by using SimpleXML:
$xml = new SimpleXMLElement($purchasedItemsXml);
Then access like this: echo $xml->purchasedItems->item[0]->name;
To access children elements of a tag do this:
foreach($xml->purchasedItems->item as $item)
{
echo $item->name; //and other properties like this.
//if not sure try var_dump($item) here it will tell you.
}
Common mistake is to reference root element in your code, don't do that, or it won't work, you need to omit root element, in your case customer.
EDIT: To add items, find the items like I showed above, and add them like this:
$item = $xml->purchasedItems->addChild('item');
$item->addChild('name', 'SimpleXML Rocks just like that');
$item->addChild('id', '3');
echo $xml->saveXML();
Your “core” code is fine, but the classes construction is wrong (parent::addItem doesn't exist and addPayHead echoes one document for each added item).
This code — without classes — will work:
$ids = array(1, 3);
$parentTag = 'purchasedItems';
$idTag = 'id';
$docSource = new DOMDocument();
$docSource->loadXML($Items);
$docDest = new DOMDocument();
$docDest->loadXML($purchasedItemsXml);
$xpath = new DOMXPath($docSource);
foreach( $ids as $id )
{
$query = "//{$idTag}[text()='{$id}']/parent::*";
$result = $xpath->query( $query );
$result = $docDest->importNode($result->item(0), true);
$items = $docDest->getElementsByTagName($parentTag)->item(0);
$items->appendChild($result);
}
echo $docDest->saveXML();

How to remove XML parent node based on child conditions PHP

Hi I am trying to clean up xml file out of positions I dont need. Here is my code so far:
<?php
$doc = new DOMDocument;
$doc->load('merg.xml');
$xpath = new DOMXPath($doc);
$products = $xpath->query('//offer/products/*');
printf('There is %d products<br /><br />', $products->length);
function findStopPointByName($xml, $query) {
$upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZĄŻŚĆŹĆÓŁ";
$lower = "abcdefghijklmnopqrstuvwxyzążśćźńół";
$arg_query = "translate('$query', '$upper', '$lower')";
return $xml->query("//offer/products/product/description/name[contains(text(),$arg_query)]");
}
foreach(findStopPointByName($xpath,'Skór') as $node)
{
$node->parentNode->removeChild($node);
}
$doc->save('merg_fixed.xml');
?>
Structure of XML:
<offer>
<products>
<product>
<description>
<name>Name of the product</name>
...
</name>
...
</description>
</product>
</products>
</offer>
I am trying to remove all PRODUCT where its NAME contains 'Skór' in any case (Skór, skór, SKÓR - is enough). Funcion findStopPointByName returns DOMNodeList of correct length, but nothing is removed from actual XML file, please help.
First, you can directly find node product with the condition
Second, to make search case insensitive, you can translate node text in any case but should use pattern in the same case. As the result, your code may be so
function findStopPointByName($xml, $query) {
$upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZĄŻŚĆŹĆÓŁ";
$lower = "abcdefghijklmnopqrstuvwxyzążśćźńół";
$arg_query = "translate(text(), '$upper', '$lower')";
$q = "//product[description/name[contains($arg_query, '$query')]]" ."\n";
return $xml->query($q);
}
$doc = new DOMDocument;
$doc->load('merg.xml');
$xpath = new DOMXPath($doc);
foreach(findStopPointByName($xpath,'skór') as $node)
$node->parentNode->removeChild($node);
echo $doc->saveXML();
Demo on eval.in

Categories