I have xml file.
<shop>
<categories>
<category id="132">kids</category>
<category id="62" parentId="133">women</category>
<category id="172" parentId="1">men</category>
</categories>
<materials>
<material id="1">one</material>
<material id="2">two</material>
<material id="3">soon</material>
</materials>
<offers>
<offer id="41850" available="true">
<price>3220</price>
<currencyId>EUR</currencyId>
<date>2015-02-05</date>
</offer>
<offer id="41850" available="true">
<price>3220</price>
<currencyId>EUR</currencyId>
<date>2015-02-05</date>
</offer>
<offer id="41850" available="true">
<price>3220</price>
<currencyId>EUR</currencyId>
<date>2015-02-05</date>
</offer>
<offer id="77777" available="true">
<price>3250</price>
<currencyId>EUR</currencyId>
<date>2015-02-05</date>
</offer>
<offer id="41340" available="true">
<price>3120</price>
<currencyId>EUR</currencyId>
<date>2015-02-05</date>
</offer>
I need delete categories and materials. After that i need delete all offers which are not unique and write it to new xml file.
My problem. I can't delete not unique offers. Please help me! Thx. Here is my code.
$url = 'test.xml';
$yml = simplexml_load_file($url);
unset($yml->shop->categories);
unset($yml->shop->materials);
$itemid = '0';
foreach ($yml->shop->offers->offer as $item){
$sravnit = $item['id'];
if("$sravnit" == "$itemid") {
echo "$sravnit eq $itemid delete<br>";
unset($yml->shop->offers->offer[$sravnit]);
continue;
else {echo "$sravnit not eq $itemid ";
$itemid = $sravnit;
echo "itemid to - $itemid <br>";
}
}
$yml->asXML('odd.xml');
This syntax doesn't make sense in multiple ways:
unset($yml->shop->offers->offer[$sravnit]);
<shop>
is your root node and that is represented by $yml
.
So the path is $yml->offers->offer
you can't select the <offer>
with the id of $sravnit
like this. It is wrong.
Instead SimpleXml
will select the nth node in a list like this:
<drinks>
<drink id="2">beer</drink>
<drink id="5">wine</drink>
<drink id="0">water</drink>
</drinks>
echo $xml->drink[2];
is water
, I'm sorry. Check it: https://eval.in/464564
http://php.net/manual/en/simplexml.examples-basic.php is a recommended read.
use of unset()
: see this answer Remove a child with a specific attribute, in SimpleXML for PHP for a good in-depth demonstration on how to combine xpath()
and unset()
to delete specific nodes with SimpleXml
.
In your case, you might first check for non-unique id-attributes in the <offer>
nodes, and delete those in a second step.
step #1: list of non-unique id
Create an array of all id values with xpath()
like this:
$ids = $yml->xpath("//offer/@id");
$ids
is an array of SimpleXml
-elements, use array_map()
to convert to integer values:
$ids = array_map("intval", $ids);
To get the non-unique values of the array $ids
:
$ids = array_count_values($ids);
will return an array with index = id and value = count:
array(3) {
[41850]=>int(3)
[77777]=>int(1)
[41340]=>int(1)
}
a unique id has the value of 1, so let us delete all those:
$ids = array_diff($ids, array(1));
Now you have an array with all non-unique id, let's flip index and value:
$ids = array_flip($ids);
This is the result:
array(1) {
[3]=>int(41850)
}
Summary: let's write all previous steps in two lines:
$ids = $yml->xpath("//offer/@id");
$ids = array_flip(array_diff(array_count_values(array_map("intval", $ids)), array(1)));
step #2: delete all <offer>
with their id
attribute in $ids
:
I will use xpath()
to select the node, and unset()
to delete it:
foreach ($ids as $id) {
foreach ($xml->xpath("//offer[@id='$id']") as $item)
unset ($item[0]);
}
See it in action: https://eval.in/464608