Page 1 of 1

Generating CSV of product data from XML containing products

Posted: Mon Dec 26, 2011 10:23 pm
by doobiedugger
I have a trouble figuring out how to properly convert a list of product data from XML into CSV format.

My source is a XML file containing a list of products with attributes like color, size, material etc. with the following structure:

Code: Select all

    <?xml version="1.0" encoding="utf-8" ?>
	<store>
        <products>
            <product>
                <name>T-Shirt</name>
                <price>19.00</price>
                <attributes>
                    <attribute>
                        <name>Color</name>
                        <options>
                            <option>
                                <name>White</name>
                                <price>0.00</price>
                            </option>
                            <option>
                                <name>Black</name>
                                <price>0.00</price>
                            </option>
                            <option>
                                <name>Blue</name>
                                <price>0.00</price>
                            </option>
                        </options>
                    </attribute>
                    <attribute>
                        <name>Size</name>
                        <options>
                            <option>
                                <name>XS</name>
                                <price>-5.00</price>
                            </option>
                            <option>
                                <name>S</name>
                                <price>-5.00</price>
                            </option>
                            <option>
                                <name>M</name>
                                <price>0.00</price>
                            </option>
                            <option>
                                <name>L</name>
                                <price>0.00</price>
                            </option>
                            <option>
                                <name>XL</name>
                                <price>5.00</price>
                            </option>
                        </options>
                    </attribute>
                </attributes>
            </product>
            <product>
                <name>Sweatshirt</name>
                <price>49.00</price>
                <attributes>
                    <attribute>
                        <name>Color</name>
                        <options>
                            <option>
                                <name>White</name>
                                <price>0.00</price>
                            </option>
                            <option>
                                <name>Black</name>
                                <price>0.00</price>
                            </option>
                        </options>
                    </attribute>
                    <attribute>
                        <name>Size</name>
                        <options>
                            <option>
                                <name>XS</name>
                                <price>-10.00</price>
                            </option>
                            <option>
                                <name>M</name>
                                <price>0.00</price>
                            </option>
                            <option>
                                <name>XL</name>
                                <price>10.00</price>
                            </option>
                        </options>
                    </attribute>
                    <attribute>
                        <name>Material</name>
                        <options>
                            <option>
                                <name>Cotton</name>
                                <price>10.00</price>
                            </option>
                            <option>
                                <name>Polyester</name>
                                <price>0.00</price>
                            </option>
                        </options>
                    </attribute>				
                </attributes>
            </product>
            <product>
                <name>Earrings</name>
                <price>29.00</price>
            </product>
        </products>
    </store>
Each product has a number of elements like name, price etc. but also a random number of attributes (like color, size, material etc.) that also have a random number of options.
Each option can affect the price of the product, so ordering a XS sized t-shirt can be cheaper than ordering a XL sized t-shirt.

I would like to end up with a CSV representing one attribute combination on each line.

In my example that would result in 3 colors x 5 sizes = 15 lines for the T-Shirt , 2 colors x 3 sizes x 2 materials = 12 lines for the Sweatshirt and 1 line for the Earrings without any attributes:

Code: Select all

   name,price,color,size,material
	T-Shirt,14.00,White,XS,
	T-Shirt,14.00,Black,XS,
	T-Shirt,14.00,Blue,XS,
	T-Shirt,14.00,White,S,
	T-Shirt,14.00,Black,S,
	T-Shirt,14.00,Blue,S,
	T-Shirt,19.00,White,M,
	T-Shirt,19.00,Black,M,
	T-Shirt,19.00,Blue,M,
	T-Shirt,19.00,White,L,
	T-Shirt,19.00,Black,L,
	T-Shirt,19.00,Blue,L,
	T-Shirt,24.00,White,XL,
	T-Shirt,24.00,Black,XL,
	T-Shirt,24.00,Blue,XL,
    Sweatshirt,49.00,White,XS,Cotton
	Sweatshirt,49.00,Black,XS,Cotton
	Sweatshirt,59.00,White,M,Cotton
	Sweatshirt,69.00,Black,M,Cotton
	Sweatshirt,69.00,White,XL,Cotton
	Sweatshirt,69.00,Black,XL,Cotton
	Sweatshirt,39.00,White,XS,Polyester
	Sweatshirt,39.00,Black,XS,Polyester
	Sweatshirt,49.00,White,M,Polyester
	Sweatshirt,49.00,Black,M,Polyester
	Sweatshirt,59.00,White,XL,Polyester
	Sweatshirt,59.00,Black,XL,Polyester
	Earrings,29.00,,,

I already managed to generate the CSV Output for simple products like the Earrings and products with just one attribute, but am struggling to come up with a way to generate all possible product attribute combinations for products with more than one attribute.

My miserable attempts at this so far have produced following code:

Code: Select all

    <?php
    mb_internal_encoding("UTF-8");
    header('Content-Type: text/html; charset=utf-8');

    $source = "example.xml";
    $handle = fopen($source, "r");
    $fp = fopen('export.csv', 'w');
    $xml = simplexml_load_file($source);

    // Generate list of attributes (for csv header etc.)
    $header_attributes = array();
    foreach ($xml->products->product as $product) {
        if(isset($product->attributes)) {
            foreach($product->attributes->attribute as $attribute) {
                array_push($header_attributes, $attribute->name);
            }
        }
    }
    $header_attributes = array_unique($header_attributes);

    $csvheader = array(
        'name','price' // these exist for all products, could also include weight, image, description, special price etc...
    );

    $static_csvheadercount = count($csvheader);

    foreach($header_attributes as $attribute) {
        array_push($csvheader, $attribute); // add variable number of attribute fields to csv header
    }

    fputcsv($fp, $csvheader);

    foreach ($xml->products->product as $product) {  // loop through each product
        if(isset($product->attributes)) $simple = 0;
        else $simple = 1;
        if($simple == 1) { // if product is a simple product with no attributes
            $output=array();
            array_push($output,(string)$product->name);
            array_push($output,(string)$product->price);
            for($i = $static_csvheadercount + $attribute_position; $i < count($csvheader); $i++) {
                        array_push($output, '');
            }
            fputcsv($fp, $output);
        }
        else { // is a configurable product with attributes
            $json = json_encode($product->attributes);
            $attributes = json_decode($json, TRUE);
            $attributes_number = count($product->attributes->attribute);
            if($attributes_number > 1) { // if product has more than 1 attributes so we have to generate each attribute combination
                //
                //	I'm trying to figure out what should happen here
                //
            }		
            else { // if product has only one attribute
                $attributename =  (string)$product->attributes->attribute->name;
                $attribute_position = array_search($attributename, $header_attributes);
                $options_number = count($product->attributes->options->option);
                $pos = 1;
                foreach($attributes['attribute']['options']['option'] as $option) { 
                    $output=array();
                    array_push($output,(string)$product->name);
                    array_push($output,(string)$product->price);
                    for($i = $static_csvheadercount - 1; $i < ($static_csvheadercount + $attribute_position); $i++) {
                        array_push($output, '');
                    }

                    $output[$static_csvheadercount + $attribute_position] = $option['name'];
                    for($i = $static_csvheadercount + $attribute_position; $i < count($csvheader) - 1 ; $i++) {
                        array_push($output, '');
                    }
                    fputcsv($fp, $output);
                    $pos++;
                }
                $output=array();
                array_push($output,(string)$product->name);
                array_push($output,(string)$product->price);
                for($i = $static_csvheadercount; $i < count($csvheader); $i++) {
                    array_push($output, '');
                }
                fputcsv($fp, $output);
            }		
        }
    }

    ?>

I've been stuck at this problem for hours unable to figure out a solution.

Can someone give a few tips or pointer how to achieve the output for products with multiple attributes?

Re: Generating CSV of product data from XML containing produ

Posted: Tue Dec 27, 2011 12:26 am
by s.dot
Hmm, seems like you could use the simplexmliterator hasChildren()/getChildren() methods and then if there are children, loop through them and append to the csv

http://us2.php.net/manual/en/simplexmli ... ildren.php