skip to Main Content

I have an XML as:

<?xml version="1.0" encoding="UTF-8"?>
<products currency="EUR">
<product id="457654754" vat="13.0">
    <price gross="0.09" net="0.07"/>
    <sizes>
        <size id="0"  name="gfdgfdgfdg" panel_name="dfgfdgfdgfd" code_producer="fgdfgfdg"  
         iaiext:code_external="457547547547"  code="354643643643"  weight="4"  iaiext:weight_net="10" >
        <stock id="1" quantity="333"/>
        </size>
    </sizes>
</product>
</products>

when I parse it as:

<?php
$xml = new XMLReader;
$xml->open('XML_URL');
while ($xml->read()) {
if ($xml->nodeType === XMLReader::ELEMENT && $xml->name == 'product')
    echo $xml->getAttribute('id').'<br />';
if ($xml->nodeType === XMLReader::ELEMENT && $xml->name == 'price')
    echo $xml->getAttribute('net').'<br />';
if ($xml->nodeType === XMLReader::ELEMENT && $xml->name == 'size')
    echo $xml->getAttribute('iaiext:code_external').'<br />';
    if ($xml->nodeType === XMLReader::ELEMENT && $xml->name == 'stock')
    echo $xml->getAttribute('quantity').'<br />';
 }

 ?>

I get the values displayed correctly.
But How can I insert them into a mysql table?
I tried it inside the same while loop and I got instead of e.g 2500 rows over 48000 rows as duplicates.
How can I achieve it?

database

CREATE TABLE `table` (
`auto_increm` int(11) NOT NULL,
`un_id` int(11) NOT NULL,
`price` decimal(15,2) NOT NULL,
`quantity` int(11) NOT NULL,
`ean` varchar(255) NOT NULL
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

 ALTER TABLE `table`
 ADD PRIMARY KEY (`auto_increm`);

 ALTER TABLE `table`
 MODIFY `auto_increm` int(11) NOT NULL AUTO_INCREMENT;
 COMMIT;

id attribute in php = un_id in mysql table

net attribute in php = price in mysql table

iaiext:code_external attribute in php = ean in mysql table

quantity attribute in php = quantity in mysql table.


In a flat XML I was always able to perform the insert into, such as:

<?php    
$doc = new DOMDocument();
$doc->load('feed.xml');
$arrFeeds = array();
foreach ($doc->getElementsByTagName('item') as $node) {
$itemRSS = array ( 
 'sku' => $node->getElementsByTagName('itemcode')->item(0)->nodeValue,
  'stock' => $node->getElementsByTagName('stock')->item(0)->nodeValue,
     'price' => $node->getElementsByTagName('price_eur')->item(0)->nodeValue
   );
   array_push($arrFeeds, $itemRSS);

  }


  $counter = 0;
  foreach( $arrFeeds as $RssItem){
  $sku = $RssItem["sku"];
  $stock = $RssItem["stock"];
  $price = $RssItem["price"];
  $sql = "INSERT INTO table(sku,stock,price) VALUES ('" . $sku . "','" . 
  $stock . "','" . $price . "')";
  $counter++;
  $result = mysqli_query($conn, $sql);

  }

  echo $counter;

  mysqli_close($conn);


   ?>

2

Answers


  1. Chosen as BEST ANSWER

    To answer my question I finally imported the XML structure via xpath

      <?xml version="1.0" encoding="UTF-8"?>
      <products currency="EUR">
      <product id="457654754" vat="13.0">
      <price gross="0.09" net="0.07"/>
      <sizes>
        <size id="0"  name="gfdgfdgfdg" panel_name="dfgfdgfdgfd" 
         code_producer="fgdfgfdg"  
         iaiext:code_external="457547547547"  code="354643643643"  weight="4"  
      iaiext:weight_net="10" >
        <stock id="1" quantity="333"/>
        </size>
     </sizes>
     </product>
     </products>
    

    as

         <?php
         $conn = mysqli_connect("xxx","xxx","xxx","xxx")
          $context  = stream_context_create(array('http' => array('header' => 
      'Accept: 
        application/xml')));
        $xml_file = 'FULL_URL_OF_XML_FILE';
        $xmlsss = file_get_contents($xml_file, false, $context);
        $xml = simplexml_load_string($xmlsss);
        $count = count($xml->xpath('/products/product'));
       for($i = 1; $i <= $count; $i++){
        $id = $xml->xpath('/products/product['.$i.']/@id')[0];
            $stock = $xml->xpath('/products/product['.$i.']/sizes/size/stock/@quantity')[0];
        $price = $xml->xpath('/products/product['.$i.']/price/@net')[0];
        $ean = $xml->xpath('/products/product['.$i.']/sizes/size/@iaiext:code_external')[0];
    
        $sql = "INSERT INTO table(id,price,quantity,ean) VALUES ('" . $id . "','" 
     . $price . "','" . $stock . "','" . $ean . "')";
      mysqli_query($conn, $sql);
     }
     mysqli_close($conn);
     ?>
    

  2. This is a the kind of tasks where you really want to use some sort of SQL query builder. I will post (the untested) code with the Laravel’s one. You might choose any other, or build the query manually.
    So, what we do – is accumulate the data for every product in a temporary array and push it to the DB every time we meet the next product.
    Note: your XML might have several sizes for one product. The approach below will utilize only the last one, since you don’t have tables for product sizes.

    <?php
    use IlluminateSupportFacadesDB;
    
    $xml = new XMLReader;
    $xml->open('XML_URL');
    
    // We will collect single product data here
    $product_data = [];
    while ($xml->read()) {    
    
        if ($xml->nodeType === XMLReader::ELEMENT && $xml->name == 'product'){
    
            // This is the key block
            // For a non-empty product data we insert a new row
            if( !empty( $product_data ) ){
    
                // Using Laravel query builder.
                // Any other will do the trick, i just dont want to mess
                // with building SQL manually
                DB::table('table')->insert($product_data);
    
                // Reinit product data with empty array
                $product_data = [];
            }
    
            $product_data['un_id'] = $xml->getAttribute('id');
            
        }
    
        if ($xml->nodeType === XMLReader::ELEMENT && $xml->name == 'price')
            $product_data['price'] = $xml->getAttribute('net');
    
        /*
        ... and so on ...
    
        I'd recommend making an external map of some sort like:
        [
            'size' => [
                'attribute' => 'iaiext:code_external',
                'target_db_field' => 'ean'
            ]
        ]
    
        And fill in the product_data using this map
    
        */    
    
    }
    
    // At this point we might have a non empty product data that was not inserted yet
    // coz we will never meet another <product> tag.. just insert what we have:
    if( !empty( $product_data ) )
        DB::table('table')->insert($product_data);
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search