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
CodePudding user response:
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();
CodePudding user response:
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.