'Match a value with an XML et un CSV et change it
I need to change a value in a XML (is a value of a price). I get this XML in the same repository of my file PHP.
For do that, i have 1 file XML where there is the value that i want change (there are multiple products), and a .CSV with three columns (this CSV also is in the same repository of the index.php):
- Column A and Column B rapresent a range of weight
- Column C is the price that i want take for change the value in XML.
Example:
XML
<weight>2.5</weight>
<price>5</price>
CSV
| COLUMN A| COLUMN B| COLUMN C|
|:---- |:------:| -----:|
| 2 | 3 | 5 |
So in that case i need to add 5 from column C in the value of XML "price".
Now, i need to convert the XML (but also the CSV ) in a multidimensional array like that:
[1]
COLUMN A => 1
COLUMN B => 2
COLUMN C => 5
[2]
COLUMN A => 2
COLUMN B => 3
COLUMN C => 10
...
The idea is doin a loop in the XML multidimensional array and a second loop in the CSV array and get the COLUMN C if the weight is beetween COLUMN A and COLUMN B.
The problem is that i son't know how convert the XML and the CSV into the array with KEY (COLUMN A) => VALUE (1).
I used simplexml_load_file for the XML and fgetcsv for the CSV, but is not what i need.
Can you help me on doing that Thank you !
That s my code:
<?php
function getXmlToArray (string $xmlName) {
$xml=simplexml_load_file($xmlName) or die("<br/>Errore di caricamento<br/>");
return $xml;
}
function getDeliveryPrice(){
$csv = 'prezzi_spedizione_francia.csv';
$file = fopen($csv, 'r');
while (!feof($file) ) {
$arrayCsv[] = fgetcsv($file, 1024);
}
fclose($file);
return $arrayCsv;
}
$xml = getXmlToArray("pre-FR_1.xml");
$listaPrezzi = getDeliveryPrice();
XML
<?xml version="1.0" encoding="utf-8"?>
<Products>
<Product>
<sku>35</sku>
<sku_manufacturer>FIN 260182300000</sku_manufacturer>
<manufacturer>Finder</manufacturer>
<ean>8012823238074</ean>
<title><![CDATA[Finder interrupteur à impulsion relais 230v 26018230]]></title>
<description><![CDATA[<p>Finder 230v relais <span>électromécanique à impulsion avec circuit bobine et contacts séparés avec 1 contact NO</span>.</p><p><strong>Caractéristiques :</strong></p>
<ul><li>Nombre de contacts 1NO</li>
<li>Courant nominal/ Courant instantané max. 10/20A</li>
<li>Tension nominale/Tension maximale de commutation 250/400 VAC</li>
<li>Charge nominale en AC1 2500VA</li>
<li>Charge nominale en AC15 (230 V AC) 500VA</li>
<li>Charge de commutation minimale 1000 (10/10) mW (V/mA)</li>
<li>Matériau de contact standard AgNi</li>
<li>Tension d'alimentation nominale (UN) 230 V AC (50 Hz)</li>
<li>Isolation entre la bobine et les contacts (1,2/50 μs) 4 kV</li>
<li>Température ambiante -40...+40 degrés</li>
<li>Degré de protection IP20</li>
</ul><p><strong>Capacité de la lampe</strong></p>
<ul><li>Incandescent/halogène 230 V 800 W</li>
<li>Fluorescents avec ballast électronique 400W</li>
<li>Fluorescents avec ballast électromagnétique déphasé 360W</li>
<li>CFL 200W</li>
<li>LED 230 V 200W</li>
<li>Halogène ou BT LED avec transformateur électronique 200W</li>
<li>Halogène ou LED BT avec transformateur électromagnétique de 400W</li>
</ul><p></p><ul><li><b>Typologie </b> : Relais</li><li><b>Type</b> : Interrupteur</li><li><b>Installation</b> : Encastré</li></ul>]]></description>
<product_price_vat_inc>10.08</product_price_vat_inc>
<shipping_price_vat_inc>0</shipping_price_vat_inc>
<quantity>3233</quantity>
<brand><![CDATA[Finder]]></brand>
<merchant_category><![CDATA[Accueil/Automatisation/Automatisation domestique]]></merchant_category>
<product_url><![CDATA[https://www.elettronew.com/fr/automatisation-domestique/finder-interrupteur-a-impulsion-relais-230v-26018230-35.html]]></product_url>
<image_1><![CDATA[https://www.elettronew.com/35872/finder-interrupteur-a-impulsion-relais-230v-26018230.jpg]]></image_1>
<image_2><![CDATA[]]></image_2>
<image_3><![CDATA[]]></image_3>
<image_4><![CDATA[]]></image_4>
<image_5><![CDATA[]]></image_5>
<retail_price_vat_inc/>
<product_vat_rate>22</product_vat_rate>
<shipping_vat_rate>20</shipping_vat_rate>
<manufacturer_pdf/>
<ParentSKU/>
<parent_title/>
<Cross_Sell_Sku/>
<ManufacturerWarrantyTime/>
<use_grid>1</use_grid>
<carrier>Courrier DHL Standard (FR)</carrier>
<shipping_time>2#4</shipping_time>
<carrier_grid_1>Courrier DHL Standard (FR)</carrier_grid_1>
<shipping_time_carrier_grid_1>2#5</shipping_time_carrier_grid_1>
<carrier_grid_2/>
<shipping_time_carrier_grid_2/>
<carrier_grid_3/>
<shipping_time_carrier_grid_3/>
<carrier_grid_4/>
<shipping_time_carrier_grid_4/>
<carrier_grid_5/>
<shipping_time_carrier_grid_5/>
<DisplayWeight>0.050000</DisplayWeight>
<free_return/>
<min_quantity>1</min_quantity>
<increment>1</increment>
<sales>0</sales>
<eco_participation>0</eco_participation>
<shipping_price_supplement_vat_inc>0</shipping_price_supplement_vat_inc>
<Unit_count>-1.000000</Unit_count>
<Unit_count_type/>
</Product>
CSV
COLUMN A;COLUMN B;COLUMN C
0;1;14,5
1;2;20
2;3;21
3;4;22
4;5;23
5;6;23,5
6;7;23,5
7;8;25
8;9;26
9;10;27
Solution 1:[1]
I hope that I have understood correctly that you wish to update the XML file ( specifically the shipping_price_vat_inc node value ) if the weight ( DisplayWeight ) value lies between the low & high values found within the CSV file.
Ignoring SimpleXML ( never used it ) and instead using DOMDocument, DOMXPath and SplFileObject with the following source files.
xmlsource.xml
<?xml version="1.0" encoding="utf-8"?>
<Products>
<Product>
<sku>35</sku>
<sku_manufacturer>FIN 260182300000</sku_manufacturer>
<manufacturer>Finder</manufacturer>
<ean>8012823238074</ean>
<product_price_vat_inc>10.08</product_price_vat_inc>
<quantity>3233</quantity>
<!-- weight & price -->
<shipping_price_vat_inc>0</shipping_price_vat_inc>
<DisplayWeight>0.050000</DisplayWeight>
<!-- -->
<Unit_count>-1.000000</Unit_count>
<Unit_count_type/>
</Product>
<Product>
<sku>36</sku>
<sku_manufacturer>FIN 260752300870</sku_manufacturer>
<manufacturer>Finder</manufacturer>
<ean>803453238074</ean>
<product_price_vat_inc>13.68</product_price_vat_inc>
<quantity>7833</quantity>
<!-- weight & price -->
<shipping_price_vat_inc>0</shipping_price_vat_inc>
<DisplayWeight>5.0850000</DisplayWeight>
<!-- -->
<Unit_count>-1.000000</Unit_count>
<Unit_count_type/>
</Product>
<Product>
<sku>37</sku>
<sku_manufacturer>FIN 2601978970000</sku_manufacturer>
<manufacturer>Finder</manufacturer>
<ean>80128234674374</ean>
<product_price_vat_inc>199.44</product_price_vat_inc>
<quantity>32543</quantity>
<!-- weight & price -->
<shipping_price_vat_inc>0</shipping_price_vat_inc>
<DisplayWeight>6.0650000</DisplayWeight>
<!-- -->
<Unit_count>-1.000000</Unit_count>
<Unit_count_type/>
</Product>
</Products>
csvsource.csv
low;high;cost
0;1;20,5
1;2;20
2;3;21
3;4;22
4;5;23
5;6;23,5
6;7;24,5
7;8;25
8;9;26
9;10;27
Note that the CSV has been slightly modified but remains virtually identical in all important respects and the XML has been streamlined to remove elements that play no part in the following process and only serve to add clutter to the demo.
The PHP code will load the XML file and then find all Product elements within. For each Product we are interested in only two items - ( the weight and the price ) so we scan every line in the CSV file to compare the weight value in the XML to the low/high values in the csv - if the weight falls between these two values we use the cost associated to populate the XML price node.
# these are saved in same directory as test script - adjust to suit own environment & names.
$xmlfile='xmlsource.xml';
$csvfile='csvsource.csv';
# create DOMDocument & XPath objects
$dom=new DOMDocument;
$dom->load( $xmlfile );
$xp=new DOMXPath( $dom );
# create CSV Parser & set the delimiter to semi-colon
$csv=new SplFileObject( $csvfile );
$csv->setFlags( SplFileObject::READ_CSV );
$csv->setCsvControl(';');
# Find all Product nodes & iterate through each
$col=$dom->getElementsByTagName('Product');
foreach( $col as $node ){
# Find the nodes of interest per product - weight & price
$weight=floatval( $xp->query('DisplayWeight',$node)->item(0)->nodeValue );
$price=$xp->query('shipping_price_vat_inc',$node)->item(0);
# process each row in the CSV file to find items in the XML whose
# weight falls between the values low,high in the CSV file.
foreach( $csv as $i => $row ){
if( $i > 0 ){
list( $low, $high, $cost )=$row;
if( $weight > floatval( $low ) && $weight < floatval( $high ) ) {
$price->nodeValue=strval( $cost );
break;
}
}
}
}
$dom->save($xmlfile);
The resultant XML:
<?xml version="1.0" encoding="utf-8"?>
<Products>
<Product>
<sku>35</sku>
<sku_manufacturer>FIN 260182300000</sku_manufacturer>
<manufacturer>Finder</manufacturer>
<ean>8012823238074</ean>
<product_price_vat_inc>10.08</product_price_vat_inc>
<quantity>3233</quantity>
<!-- weight & price -->
<shipping_price_vat_inc>20,5</shipping_price_vat_inc><!-- UPDATED -->
<DisplayWeight>0.050000</DisplayWeight>
<!-- -->
<Unit_count>-1.000000</Unit_count>
<Unit_count_type/>
</Product>
<Product>
<sku>36</sku>
<sku_manufacturer>FIN 260752300870</sku_manufacturer>
<manufacturer>Finder</manufacturer>
<ean>803453238074</ean>
<product_price_vat_inc>13.68</product_price_vat_inc><!-- UPDATED -->
<quantity>7833</quantity>
<!-- weight & price -->
<shipping_price_vat_inc>23,5</shipping_price_vat_inc>
<DisplayWeight>5.0850000</DisplayWeight>
<!-- -->
<Unit_count>-1.000000</Unit_count>
<Unit_count_type/>
</Product>
<Product>
<sku>37</sku>
<sku_manufacturer>FIN 2601978970000</sku_manufacturer>
<manufacturer>Finder</manufacturer>
<ean>80128234674374</ean>
<product_price_vat_inc>199.44</product_price_vat_inc>
<quantity>32543</quantity>
<!-- weight & price -->
<shipping_price_vat_inc>24,5</shipping_price_vat_inc><!-- UPDATED -->
<DisplayWeight>6.0650000</DisplayWeight>
<!-- -->
<Unit_count>-1.000000</Unit_count>
<Unit_count_type/>
</Product>
</Products>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
