Генерация CSV данных продукта из XML, содержащего продукты со случайным количеством атрибутов - PullRequest
0 голосов
/ 27 декабря 2011

У меня проблемы с выяснением того, как правильно преобразовать список данных о товарах из 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 может быть дешевле, чем заказ футболки размера XL.

Я бы хотел, чтобы CSV представлял одну комбинацию атрибутов накаждая строка.

В моем примере это даст 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 голосов
/ 20 января 2012

Довольно просто в 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();
    }

?>
0 голосов
/ 27 декабря 2011

Вот полезные ссылки: ссылка 1 или ссылка 2

Если не помогло.В каждом атрибуте у вас есть x вариантов.Так, например, у вас есть 2 варианта цвета и 3 размера.Итого у вас будет 2х3 = 6 товаров.Сначала с циклом вы можете посчитать, сколько продуктов у вас будет в итоге и сколько у вас будет атрибутов.Таким образом, вы можете определить, как будет выглядеть ваш продукт.Например, вот так:

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

Это означает, что каждый из ваших продуктов будет иметь ровно 2 атрибута.Итак, вы должны перепрыгнуть через все параметры атрибутов и собрать все возможные варианты продуктов.Так что в идеале этим простым решением вы могли бы получить что-то вроде этого: Размер: XS S или 1 2 Цвет: Красный Синий Грен или 3 4 5 Тогда у нас будет что-то вроде этого:1012 *

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];
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...