You are here:  » Loop through variants in a product xml and insert into db


Loop through variants in a product xml and insert into db

Submitted by bayuobie on Tue, 2012-08-14 16:21 in

I have a products xml with many variants of each product and nested elements. I want to find a way to loop through each variant, and other nested elements. Please see example below.

{file emailed to support}

Below is my code with magicparser: I want to use a foreach to loop through each variant, and identify the corresponding option/option/name from options array which is not in variants.So options are used to store the attribute names like size, age, but the value in variant will then be medium, 20, respectively.

{code saved}

Sorry for the long descriptions but it's just a way to make things clear. Really finding it difficult to get the variant/options/option values that match to options/option/name attribute.

Please any help is appreciated.

Thanks in advance.

Submitted by support on Wed, 2012-08-15 08:18

Hi,

Whilst Magic Parser isn't ideally suited to handing multiple levels of nested child elements there are a number of straight forward techniques using PHP's string handler / regular expression functions which can be used to loop through all items in $record and extract them into a more suitable data structure for processing - in this case an array of variants.

As you will have seen from studying the single $record as passed to your myRecordHandler function; the keys for the variant elements appear in the first instance as, for example:

VARIANTS/VARIANT/CREATED-AT

...and in subsequent instances with the duplicate resolution postfix, e.g.

VARIANTS/VARIANT/CREATED-AT@1

Since this is predictable, we can loop through each $record entry, see if it is part of a variant record, and if so, extract the n of the @n postfix using a regular expression; and use the resulting index to populate a $variants[] array. Here's the basic code to demonstrate the idea; which prints each variant for each product using print_r so that you can see what keys to use to index each each $variant in the foreach($variants as $variant) loop in your main code...

<?php
  header
("Content-Type: text/plain");
  require(
"MagicParser.php");
  function 
myRecordHandler($record)
  {
    
$variants = array();
    foreach(
$record as $key => $value)
    {
      if (
strpos($key,"VARIANTS/VARIANT")===FALSE) continue;
      
preg_match('/(.*)(@[0-9]*)(.*)/',$key,$matches);
      
$variantIndex = (isset($matches[2])?intval(substr($matches[2],1)):0);
      
$keyParts explode("/",$key);
      if (!isset(
$keyParts[2])) continue;
      
$variantKey $keyParts[2];
      if (
$variantIndex$variantKey str_replace("@".$variantIndex,"",$variantKey);
      
$variants[$variantIndex][$variantKey] = $value;
    }
    
// here you can access main product level elements e.g
    // print $record["PRODUCT-TYPE"];
    // and loop through each variant using foreach e.g.
    // foreach($variants as $variant)
    // {
    //   print $variant["TITLE"];
    // }
    // following code will display each variant using print_r
    // to show available keys for each $variant...
    
print_r($variants);
  }
  
MagicParser_parse("Products1.xml","myRecordHandler","xml|PRODUCTS/PRODUCT/");
?>

Hope this helps!
Cheers,
David
--
MagicParser.com

Submitted by bayuobie on Wed, 2012-08-15 10:20

Hi David,

This partly solved the problem of looping through variants and getting the values. But there is the other part of matching the values. This example if for the first product:
[OPTION1] => brown color (want to know if this is color)

[OPTION2] => small (if this is size)

[OPTION3] => blaci (if this is age)
to their attribute keys which are given outside the Variants/variant nested element. So each product has the
options/option/name, options/option/name@1 in that sequence and you use those values to tell what the variants/variant/option1, variants/variant/option@2,should be.

For instance, the options/option/name could be color, options/option/name@2 is size, so for each variant, how do i know if variants/variant/option1, should be saved as Color, and variants/variant/option@2 should be Size. Since the positions of the attributes are not static.

Thank you for helping solve the first part. I appreciate it.

Submitted by support on Wed, 2012-08-15 10:41

Hi,

Ah I see, a very similar trick can be used. First of all, before looping for each variant, loop through $record to find every OPTIONS/OPTION field, and put the name of each option into a $optionNames array; keyed by "OPTION1", "OPTION2", etc. exactly as they are named in each variant element.

Then, when constructing each $variant, if the key is one of the option values (e.g. OPTION1), instead of simply inserting into the $variant array; insert it as $variant[n]["OPTIONS"]["Option Name"]. I've demonstrated this in the following code;

<?php
  header
("Content-Type: text/plain");
  require(
"MagicParser.php");
  function 
myRecordHandler($record)
  {
    
// construct options names array
    
$optionNames = array();
    
$i 0;
    foreach(
$record as $key => $value)
      {
      if (
strpos($key,"OPTIONS/OPTION/NAME")===FALSE) continue;
      
$i++;
      
$optionNames["OPTION".$i] = $value;
    }
    
$variants = array();
    foreach(
$record as $key => $value)
      {
      if (
strpos($key,"VARIANTS/VARIANT")===FALSE) continue;
      
preg_match('/(.*)(@[0-9]*)(.*)/',$key,$matches);
      
$variantIndex = (isset($matches[2])?intval(substr($matches[2],1)):0);
      
$keyParts explode("/",$key);
      if (!isset(
$keyParts[2])) continue;
      
$variantKey $keyParts[2];
      if (
$variantIndex$variantKey str_replace("@".$variantIndex,"",$variantKey);
      if (
strpos($variantKey,"OPTION")!==FALSE)
      {
        
$variants[$variantIndex]["OPTIONS"][$optionNames[$variantKey]] = $value;
      }
      else
      {
        
$variants[$variantIndex][$variantKey] = $value;
      }
    }
    
// here you can access main product level elements e.g
    // print $record["PRODUCT-TYPE"];
    // and loop through each variant using foreach e.g.
    // foreach($variants as $variant)
    // {
    //   print $variant["TITLE"];
    // }
    // following code will display each variant using print_r
    // to show available keys for each $variant...
    
print_r($variants);
  }
  
MagicParser_parse("Products1.xml","myRecordHandler","xml|PRODUCTS/PRODUCT/");
?>

...and in the case of the first record; the output array is as follows:

Array
(
    [0] => Array
        (
            [COMPARE-AT-PRICE] =>
            [COMPARE-AT-PRICE-TYPE] => decimal
            [COMPARE-AT-PRICE-NIL] => true
            [CREATED-AT] => 2010-06-02T15:13:35+01:00
            [CREATED-AT-TYPE] => datetime
            [FULFILLMENT-SERVICE] => manual
            [GRAMS] => 0
            [GRAMS-TYPE] => integer
            [ID] => 47863442
            [ID-TYPE] => integer
            [PRODUCT-ID] => 20198752
            [PRODUCT-ID-TYPE] => integer
            [INVENTORY-MANAGEMENT] => shopify
            [INVENTORY-POLICY] => deny
            [OPTIONS] => Array
                (
                    [Title] => brown color
                    [Size] => small
                    [google] => blaci
                )
            [POSITION] => 1
            [POSITION-TYPE] => integer
            [PRICE] => 520.0
            [PRICE-TYPE] => decimal
            [REQUIRES-SHIPPING] => true
            [REQUIRES-SHIPPING-TYPE] => boolean
            [SKU] =>
            [TAXABLE] => true
            [TAXABLE-TYPE] => boolean
            [TITLE] => brown color / small / blaci
            [UPDATED-AT] => 2011-08-10T22:41:11+01:00
            [UPDATED-AT-TYPE] => datetime
            [INVENTORY-QUANTITY] => 20
            [INVENTORY-QUANTITY-TYPE] => integer
        )
    [1] => Array
        (
            [COMPARE-AT-PRICE] => 550.0
            [COMPARE-AT-PRICE-TYPE] => decimal
            [CREATED-AT] => 2011-07-12T18:10:33+01:00
            [CREATED-AT-TYPE] => datetime
            [FULFILLMENT-SERVICE] => manual
            [GRAMS] => 0
            [GRAMS-TYPE] => integer
            [ID] => 107478942
            [ID-TYPE] => integer
            [PRODUCT-ID] => 20198752
            [PRODUCT-ID-TYPE] => integer
            [INVENTORY-MANAGEMENT] =>
            [INVENTORY-POLICY] => deny
            [OPTIONS] => Array
                (
                    [Title] => green color laptop
                    [Size] => small
                    [google] => brown
                )
            [POSITION] => 2
            [POSITION-TYPE] => integer
            [PRICE] => 520.02
            [PRICE-TYPE] => decimal
            [REQUIRES-SHIPPING] => true
            [REQUIRES-SHIPPING-TYPE] => boolean
            [SKU] =>
            [TAXABLE] => true
            [TAXABLE-TYPE] => boolean
            [TITLE] => green color laptop / small / brown
            [UPDATED-AT] => 2011-08-10T22:35:58+01:00
            [UPDATED-AT-TYPE] => datetime
            [INVENTORY-QUANTITY] => 1
            [INVENTORY-QUANTITY-TYPE] => integer
        )
)

...where you will see the OPTIONS array per variant...

Hope this helps!
Cheers,
David.

Submitted by bayuobie on Wed, 2012-08-15 12:16

That helps a lot, but i got stuck in trying to get the values of the OPTIONS key so i can check if it's equal to size, then I assign say $color=brown, please see explanations in they code you sent me:

<?php
  header
("Content-Type: text/plain");
  require(
"MagicParser.php");
  function 
myRecordHandler($record)
  {
    
// construct options names array
    
$optionNames = array();
    
$i 0;
    foreach(
$record as $key => $value)
      {
      if (
strpos($key,"OPTIONS/OPTION/NAME")===FALSE) continue;
      
$i++;
      
$optionNames["OPTION".$i] = $value;
    }
    
$variants = array();
    foreach(
$record as $key => $value)
      {
      if (
strpos($key,"VARIANTS/VARIANT")===FALSE) continue;
      
preg_match('/(.*)(@[0-9]*)(.*)/',$key,$matches);
      
$variantIndex = (isset($matches[2])?intval(substr($matches[2],1)):0);
      
$keyParts explode("/",$key);
      if (!isset(
$keyParts[2])) continue;
      
$variantKey $keyParts[2];
      if (
$variantIndex$variantKey str_replace("@".$variantIndex,"",$variantKey);
      
// Array for a product variant.
          
[OPTIONS] => Array
                (
                    [
Title] => green color laptop
                    
[Size] => small
                    
[google] => brown
                
)
    
i want to do an if condition like this below.
      if ([
OPTIONS]->KEY ==Size)
      {
       
then grab value of Size == Small
      
}
      if ([
OPTIONS]->KEY==google){
      {
        
$google corresponding value of google=brown;
        
Now see foreach($variants as $variantbelow to see what i want to do
      }
    }
    
// here you can access main product level elements e.g
    // print $record["PRODUCT-TYPE"];
    // and loop through each variant using foreach e.g.
     
foreach($variants as $variant)
     {
     
insert into table (titlegooglesizevalues('$variant["TITLE"]','$google','$sze');
     }
    
// following code will display each variant using print_r
    // to show available keys for each $variant...
    
print_r($variants);
  }
  
MagicParser_parse("Products1.xml","myRecordHandler","xml|PRODUCTS/PRODUCT/");
?>

I hope this will be my last question. Thank you.

Submitted by support on Wed, 2012-08-15 12:26

Hi,

Assuming that your `table` has fields for all possible options; then what I would do is simply to construct the SQL for all possible values - it won't be any less efficient than any other method = using something like this...

     foreach($variants as $variant)
     {
       $sql = "INSERT INTO `table` SET
         `title` = '".mysql_real_escape_string($variant["TITLE"])."',
         `price` = '".mysql_real_escape_string($variant["PRICE"])."',
         `google` = '".mysql_real_escape_string($variant["OPTIONS"]["google"])."',
         `size` = '".mysql_real_escape_string($variant["SIZE"]["size"])."'
       ";
       mysql_query($sql,$result);
     }

Hope this helps!
Cheers,
David.

Submitted by bayuobie on Wed, 2012-08-15 15:34

Hi David,

I have tried this but the Size,google,Color values are empty. But everything is correct and should work. I don't understand why

Submitted by support on Wed, 2012-08-15 15:48

Hi,

The keys to PHP associative arrays are case sensitive - I just notices I used "size" in the above which I think should actually be "Size" - for example based on the record print_r'd above, containing

          [OPTIONS] => Array
                (
                    [Title] => green color laptop
                    [Size] => small
                    [google] => brown
                )

...the equivalent SQL construction would contain:

  `size` = '".mysql_real_escape_string($variant["OPTIONS"]["Size"])."',
  `google` = '".mysql_real_escape_string($variant["OPTIONS"]["google"])."'

(assuming all lowercase in the database, but not the variance in the case in the keys into the $variant["OPTIONS"] array. My apologies - I notice that that I $variant["SIZE"] by mistake in the previous post instead of $variant["OPTIONS"])

Having constructed your SQL, to invoke but also display the MySQL error message which may help debug, use:

  mysql_query($sql) or die(mysql_error());

Cheers,
David.

Submitted by bayuobie on Wed, 2012-08-15 16:16

Hi Dave,

I have tried all those cases sensitive options before but never worked. For instance if I try to echo those variables in the foreach statement for variants, nothing echos. See below

{code saved}

Submitted by support on Wed, 2012-08-15 16:35

Hi,

I'll folllow up by email - i've created a couple of test scripts for you to try...

Cheers,
David.