从包含具有随机数量属性的产品的XML生成产品数据的CSV

时间:2011-12-27 04:11:58

标签: php xml magento csv xml-parsing

我很难弄清楚如何将产品数据列表从XML正确转换为CSV格式。

我的源代码是一个XML文件,其中包含具有颜色,大小,材质等属性的产品列表,其结构如下:

<?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>

每个产品都有许多元素,如名称,价格等,还有随机数量的属性(如颜色,大小,材料等),这些属性也有随机数量的选项。 每个选项都会影响产品的价格,所以订购XS大小的T恤比订购XL大小的T恤要便宜。

我想最终得到一个代表每行一个属性组合的CSV。

在我的例子中,这将导致T恤的3种颜色x 5尺寸= 15行,2种颜色x 3尺寸x 2材料=运动衫12条线和1条耳环没有任何属性:

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,,,

我已经设法为只有一个属性的耳环和产品等简单产品生成CSV输出,但我很难想出一种方法来为具有多个属性的产品生成所有可能的产品属性组合。

到目前为止,我对此的悲惨尝试产生了以下代码:

<?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);
        }       
    }
}

?>

我已经坚持这个问题几个小时无法找到解决方案。

有人可以提供一些提示或指针,以获得具有多个属性的产品的输出吗?

2 个答案:

答案 0 :(得分:0)

以下是有用的链接: link 1link 2

如果没有帮助。 在每个属性中,您有x个选项。例如,您有2种颜色和3种尺寸选项。总共有2x3 = 6个产品。 首先是循环,你可以计算到底你将拥有多少产品以及你将拥有多少属性。因此,您可以定义产品的外观。例如:

$products = array();
$product = array("size"=>,"color"=>); total 2 attributes
$products[] = $product;

这意味着您的每个产品都有2个属性。 那么,您应该跳过所有属性选项并收集所有可能的产品变体。理想情况下,通过这个简单的解决方案,你可能得到这样的东西 尺寸:XS S或1 2 颜色:Red Blue Gren或3 4 5然后我们会有这样的东西:

3 4 5 3 4 5

1 2 1 2 1 2

也许我的解决方案不是最好的。我甚至不知道它是否有效。但是你可以为你获得一些有用的信息。

$variant_count = 1;
$opts = array();
for($attributes->attribute as $attr){
    $variant_count *= count($attr->option);
    $opts[] = $attr->option;
}
$products = array();
for($i = 0; $i < $variant_count; $i++){
    $product = array();
    for($x = 0; $x < count($opts); $x++){
        $y = $i...;// here should be some function which counts proper $y
        $product[$x] = $opts[$x][$y];
    }
}

答案 1 :(得分:0)

在xsl中非常简单,这是一个可以满足您需求的XSL。

只需要考虑一些XSL技巧。

  • 使用此

    输出回车

  • 将输出方法设置为文本,没有任何约束

祝你好运!

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > 

<xsl:output method="text" indent="no"/>

<xsl:template match="/">
    <xsl:for-each select='store/products/product'>
        <!-- Store off the current product name and price -->
        <xsl:variable name='name' select='name'/>
        <xsl:variable name='price' select='price'/>
        <!-- Store off the material, colors and sizes-->
        <xsl:variable name='materials' select='attributes/attribute[name="Material"]/options/option/name'/>
        <xsl:variable name='colors' select='attributes/attribute[name="Color"]/options/option/name'/>
        <xsl:variable name='sizes' select='attributes/attribute[name="Size"]/options/option/name'/>

        <!-- If no colors (earrings), jump ahead -->
        <xsl:if test='$colors'>
            <!-- Iterate the colors -->
            <xsl:for-each select='$colors'>
                <!-- Store off the current color -->
                <xsl:variable name='color' select='.'/>
                <!-- Iterate the sizes -->
                <xsl:for-each select='$sizes'>
                    <xsl:variable name='size' select='.'/>
                    <!-- If materials, iterate through them too -->
                    <xsl:if test='$materials'>
                        <xsl:for-each select='$materials'>
                            <xsl:variable name='material' select='.'/>
                            <xsl:value-of select='$name'/>,<xsl:value-of select='$price'/>,<xsl:value-of select='$color'/>,<xsl:value-of select='$size'/>,<xsl:value-of select='$material'/>
                            <xsl:text>&#xA;</xsl:text>
                        </xsl:for-each>
                    </xsl:if>
                    <!-- If not materials, output what we've got -->
                    <xsl:if test='not($materials)'>
                        <xsl:value-of select='$name'/>,<xsl:value-of select='$price'/>,<xsl:value-of select='$color'/>,<xsl:value-of select='$size'/>
                        <xsl:text>&#xA;</xsl:text>
                    </xsl:if>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:if>
        <xsl:if test='not($colors)'>
            <xsl:value-of select='$name'/>,<xsl:value-of select='$price'/>,,,
            <xsl:text>&#xA;</xsl:text>
        </xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

如果您不知道如何使用XSL,这里有一个快速的小脚本可以帮助您入门。

<?php

    try {
        $xml = new DOMDocument();
        $strFileName = "att.xml";
        $xml->load($strFileName);

        $xsl = new DOMDocument();
        $strFileName = "att.xsl";
        $xsl->load($strFileName);

        $proc = new XSLTProcessor();
        $proc->importStylesheet($xsl);

        echo $proc->transformToXML($xml);
    } catch( Exception $e ) {
        echo $e->getMessage();
    }

?>