0

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'); 
Preshan Pradeepa
  • 698
  • 14
  • 31
  • Just build an array of IDs in the loop. If the ID is already in the array, you can delete it. – rjdown Nov 06 '15 at 01:10
  • when i use unset($yml->shop->categories); it's work great, but when i use unset($yml->shop->offers->offer[$sravnit]); nothing works... ( – Golden Bribe Nov 06 '15 at 01:13

1 Answers1

0

This syntax doesn't make sense in multiple ways:

unset($yml->shop->offers->offer[$sravnit]); 
  1. <shop> is your root node and that is represented by $yml.
    So the path is $yml->offers->offer

  2. 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.

  3. 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

  1. Create an array of all id values with xpath() like this:

    $ids = $yml->xpath("//offer/@id");
    
  2. $idsis an array of SimpleXml-elements, use array_map() to convert to integer values:

    $ids = array_map("intval", $ids);
    
  3. 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)
    }
    
  4. a unique id has the value of 1, so let us delete all those:

    $ids = array_diff($ids, array(1));
    
  5. 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)
    }
    
  6. 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

Community
  • 1
  • 1
michi
  • 6,565
  • 4
  • 33
  • 56