Мне нужно транспонировать файл XML, такой как этот:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product id="10" name="Widget 1" price="15.99" category_code="T" category="Toys" manufacturer_code="SC1" manufacturer="Some Company 1" />
<product id="10" name="Widget 1" price="15.99" category_code="E" category="Electronics" manufacturer_code="SC1" manufacturer="Some Company 1" />
<product id="10" name="Widget 1" price="15.99" category_code="T" category="Toys" manufacturer_code="SC2" manufacturer="Some Company 2" />
<product id="10" name="Widget 1" price="15.99" category_code="E" category="Electronics" manufacturer_code="SC2" manufacturer="Some Company 2" />
<product id="10" name="Widget 1" price="15.99" category_code="T" category="Toys" manufacturer_code="SC3" manufacturer="Some Company 3" />
<product id="10" name="Widget 1" price="15.99" category_code="E" category="Electronics" manufacturer_code="SC3" manufacturer="Some Company 3" />
<product id="11" name="Widget 2" price="21.99" category_code="V" category="Video Games" manufacturer_code="SC4" manufacturer="Some Company 4" />
<product id="12" name="Widget 3" price="10.99" category_code="T" category="Toys" manufacturer_code="SC1" manufacturer="Some Company 2" />
</products>
в текстовый файл с разделителями-запятыми или в правильно отформатированную HTML-таблицу, содержащую только одну строку для каждого продукта, что-то вроде этого:
id,name,price,category_code_1,category_1,category_code_2,category_2,manufacturer_code_1,manufacturer_1,manufacturer_code_2,manufacturer_2,manufacturer_code_3,manufacturer_3
10, Widget 1, 15.99, T, Toys, E, Electronics, SC1, Some Company 1, SC2, Some Company 2, SC3, Some Company 3
11, Widget 2, 21.99, V, Video Games,,, SC4, Some Company 4,,,,
12, Widget 3, 10.99, T, Toys,,, SC1, Some Company 2,,,,
Как вы могли заметить, данные XML можно рассматривать как результат объединения трех таблиц: product, product_category и product_manufacturer. Каждый товар может принадлежать нескольким категориям и иметь несколько производителей. Конечно, реальные данные, с которыми я имею дело, более сложны и находятся в совершенно другой области, но этот пример правильно отображает проблему.
У меня очень ограниченные знания XSLT, и с помощью SO и других ресурсов в Interent я создал таблицу стилей, которая частично дает мне то, что мне нужно:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="key_product_group" match="product" use="@id"/>
<xsl:key name="key_category_group" match="product" use="concat(
@id,
@category_code,
@category)"/>
<xsl:key name="key_manufacturer_group" match="product" use="concat(
@id,
@manufacturer_code,
@manufacturer)"/>
<xsl:variable name="var_max_category_group" >
<xsl:for-each select="//product[generate-id(.) = generate-id(key('key_product_group',@id) )]">
<xsl:sort select="count(key('key_product_group',@id )[generate-id() = generate-id(key('key_category_group',
concat(@id,
@category_code,
@category)))])" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="count(key('key_product_group',@id )[generate-id() = generate-id(key('key_category_group',
concat(@id,
@category_code,
@category)))])"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="var_max_manufacturer_group">
<xsl:for-each select="//product[generate-id(.) = generate-id(key('key_product_group',@id) )]">
<xsl:sort select="count(key('key_product_group',@id )[generate-id() = generate-id(key('key_manufacturer_group',
concat(@id,
@category_code,
@category)))])" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="count(key('key_product_group',@id )[generate-id() = generate-id(key('key_manufacturer_group',
concat(@id,
@manufacturer_code,
@manufacturer)))])"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<xsl:text>id,</xsl:text>
<xsl:text>name,</xsl:text>
<xsl:text>price,</xsl:text>
<xsl:call-template name="loop_pcat">
<xsl:with-param name="count" select="$var_max_category_group"/>
</xsl:call-template>
<xsl:call-template name="loop_pmf">
<xsl:with-param name="count" select="$var_max_manufacturer_group"/>
</xsl:call-template>
<br></br>
<xsl:variable name="var_group"
select="//product[generate-id(.) = generate-id(key('key_product_group',@id)[1])]"/>
<xsl:for-each select="$var_group">
<xsl:sort order="ascending" select="@id"/>
<xsl:value-of select="@id"/>,
<xsl:value-of select="@name"/>,
<xsl:value-of select="@price"/>,
<xsl:for-each select="key('key_product_group',@id )[generate-id() = generate-id(key('key_category_group',
concat(@id,
@category_code,
@category)))]">
<xsl:value-of select="@category_code"/>,
<xsl:value-of select="@category"/>,
</xsl:for-each>
<xsl:for-each select="key('key_product_group',@id )[generate-id() = generate-id(key('key_manufacturer_group',
concat(@id,
@manufacturer_code,
@manufacturer)))]">
<xsl:value-of select="@manufacturer_code"/>,
<xsl:value-of select="@manufacturer"/>,
</xsl:for-each>
<br></br>
</xsl:for-each>
</xsl:template>
<xsl:template name="loop_pcat">
<xsl:param name="count" select="1"/>
<xsl:param name="limit" select="$count+1"/>
<xsl:if test="$count > 0">
<xsl:value-of select="concat('category_code_',$limit - $count)"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="concat('category_',$limit - $count)"/>
<xsl:text>,</xsl:text>
<xsl:call-template name="loop_pcat">
<xsl:with-param name="count" select="$count - 1"/>
<xsl:with-param name="limit" select="$limit"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="loop_pmf">
<xsl:param name="count" select="1"/>
<xsl:param name="limit" select="$count+1"/>
<xsl:if test="$count > 0">
<xsl:value-of select="concat('manufacturer_code_',$limit - $count)"/>
<xsl:text>,</xsl:text>
<xsl:value-of select="concat('manufacturer_',$limit - $count)"/>
<xsl:text>,</xsl:text>
<xsl:call-template name="loop_pmf">
<xsl:with-param name="count" select="$count - 1"/>
<xsl:with-param name="limit" select="$limit"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Приведенная выше таблица стилей дает следующие результаты:
id,name,price,category_code_1,category_1,category_code_2,category_2,manufacturer_code_1,manufacturer_1,manufacturer_code_2,manufacturer_2,manufacturer_code_3,manufacturer_3,
10, Widget 1, 15.99, T, Toys, E, Electronics, SC1, Some Company 1, SC2, Some Company 2, SC3, Some Company 3,
11, Widget 2, 21.99, V, Video Games, SC4, Some Company 4,
12, Widget 3, 10.99, T, Toys, SC1, Some Company 2,
Вывод имеет по крайней мере одну главную проблему: все столбцы не существуют в каждой строке, например, в строках 2 и 3 отсутствуют category_code_2 и category_2, а также factory_code и производитель 2 и 3. Я уверен, что есть другие проблемы с таблицей стилей, и я понятия не имею, как она будет работать с относительно большим XML-файлом, но сейчас я был бы очень признателен за вашу помощь в создании таблицы стилей для получения желаемого выходного формата.
Спасибо
1019 * MRSA *