#xml #xslt-1.0
#xml #xslt-1.0
Вопрос:
мне нужно объединить продукты магазина, размер которых указан в названии. Как вы можете видеть, я должен вырезать размер из названия продукта и поместить его в новый элемент внутри группы-элемент «РАЗМЕРЫ», то же самое с PARTNO и STOCK, которые необходимы для определения продукта, его размеров и количества. Я создал некоторый xslt с шаблоном и циклом foreach, но я не знаю, как проверить, был ли создан какой-либо узел ранее.
Это очень важно для меня, потому что xslt — это моя новая возможность в моей работе, я новичок в xslt, поэтому мой код очень простой и уродливый.
вот пример xml:
<?xml version="1.0" encoding="Windows-1250"?>
<SHOP xmlns="http://www.b2b.abisaltest.pl">
<SHOPITEM>
<PRODUCT>ZBRS180 CZERWONA BRAMKA PIŁKARSKA</PRODUCT>
<PRICE>167.01</PRICE>
<PARTNO>5907695527654</PARTNO>
<STOCK>177</STOCK>
</SHOPITEM>
<SHOPITEM>
<PRODUCT>NJ2117 A NIEBIESKO-RÓŻOWE SIZE. M (34-37) ŁYŻWOROLKI NILS
EXTREME</PRODUCT>
<PRICE>113.01</PRICE>
<PARTNO>5907695510333</PARTNO>
<STOCK>158</STOCK>
</SHOPITEM>
<SHOPITEM>
<PRODUCT>NJ2117 A NIEBIESKO-RÓŻOWE SIZE. L (38-41) ŁYŻWOROLKI NILS
EXTREME</PRODUCT>
<PRICE>113.01</PRICE>
<PARTNO>5907695510334</PARTNO>
<STOCK>35</STOCK>
</SHOPITEM>
</SHOP>
**Output file should looks like that:**
<?xml version="1.0" encoding="Windows-1250"?>
<SHOP>
<SHOPITEM>
<PRODUCT>ZBRS180 CZERWONA BRAMKA PIŁKARSKA</PRODUCT>
<PRICE>167.01</PRICE>
<PARTNO>5907695527654</PARTNO>
<STOCK>177</STOCK>
</SHOPITEM>
<SHOPITEM>
<PRODUCT>NJ2117 A NIEBIESKO-RÓŻOWE ŁYŻWOROLKI NILS EXTREME</PRODUCT>
<SIZES>
<SIZE>M (34-37)</SIZE>
<SIZE>L (38-41)</SIZE>
</SIZES>
<PARTNOS>
<PARTNO>5907695510333</PARTNO>
<PARTNO>5907695510334</PARTNO>
</PARTNOS>
<STOCKS>
<STOCK>158</STOCK>
<STOCK>35</STOCK>
</STOCKS>
<PRICE>113.01</PRICE>
</SHOPITEM>
</SHOP>
Вот мой xsl-код:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abi="http://www.b2b.abisaltest.pl">
<xsl:output method="xml" indent="yes" version="1.0" encoding="iso-8859-2"/>
<xsl:template match="abi:SHOP">
<xsl:element name="SHOP">
<xsl:apply-templates select="abi:SHOPITEM">
<xsl:with-param name="pNodeset" select="abi:SHOPITEM"/>
</xsl:apply-templates>
</xsl:element>
</xsl:template>
<xsl:template match="abi:SHOPITEM">
<xsl:param name="pNodeset" />
<xsl:element name="SHOPITEM" >
<xsl:choose>
<xsl:when test="contains(abi:PRODUCT/text(), 'SIZE.')">
<!-- Creating variable with node name -->
<xsl:variable name="currentCuttedNodeName">
<xsl:value-of select="substring-before(abi:PRODUCT/text(), 'SIZE.')"/>
</xsl:variable>
<!-- Looking for SIZES -->
<xsl:element name="SIZES">
<xsl:for-each select="$pNodeset">
<xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
<xsl:element name="SIZE">
<xsl:choose>
<xsl:when test="contains(abi:PRODUCT/text(),')')">
<xsl:variable name="from">
<xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), '(')) 1"/>
</xsl:variable>
<xsl:variable name="to">
<xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), ')'))"/>
</xsl:variable>
<xsl:value-of select="substring(abi:PRODUCT/text(),$from,7)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="from">
<xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), 'SIZE.'))"/>
</xsl:variable>
<xsl:value-of select="substring(abi:PRODUCT/text(),$from 7, 2)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<!-- Looking for EANS -->
<xsl:element name="EANS">
<xsl:for-each select="$pNodeset">
<xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
<xsl:element name="EAN">
<xsl:value-of select="abi:PARTNO/text()"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<!-- Looking for external codes -->
<xsl:element name="CODES">
<xsl:for-each select="$pNodeset">
<xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
<xsl:element name="CODE">
<xsl:value-of select="abi:PRODUCTNO/text()"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<!-- Looking for stocks -->
<xsl:element name="STOCKS">
<xsl:for-each select="$pNodeset">
<xsl:if test="contains(abi:PRODUCT/text(), $currentCuttedNodeName)">
<xsl:element name="STOCK">
<xsl:value-of select="abi:STOCK/text()"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<xsl:element name="NAME">
<xsl:choose>
<xsl:when test="contains(abi:PRODUCT/text(),')')">
<xsl:variable name="from">
<xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), 'SIZE.'))"/>
</xsl:variable>
<xsl:variable name="to">
<xsl:value-of select="string-length(substring-before(abi:PRODUCT/text(), ')'))"/>
</xsl:variable>
<xsl:variable name="firstPart">
<xsl:value-of select="substring-before(abi:PRODUCT/text(),'SIZE.')"/>
</xsl:variable>
<xsl:variable name="secondPart">
<xsl:value-of select="substring-after(abi:PRODUCT/text(),')')"/>
</xsl:variable>
<xsl:value-of select="concat($firstPart,$secondPart)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="firstPart">
<xsl:value-of select="substring-before(abi:PRODUCT/text(), 'SIZE.')"/>
</xsl:variable>
<xsl:variable name="fromNumber">
<xsl:value-of select="string-length(substring-after(abi:PRODUCT/text(), 'SIZE.')) 10"/>
</xsl:variable>
<xsl:variable name="secondPart">
<xsl:value-of select="substring(abi:PRODUCT/text(), $fromNumber, string-length(abi:PRODUCT/text()) - $fromNumber)"/>
</xsl:variable>
<xsl:value-of select="concat($firstPart, $secondPart)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
<xsl:element name="ID">
<xsl:value-of select="position()"/>
</xsl:element>
<xsl:element name="DESC">
<xsl:value-of select="abi:DESCRIPTION/text()"/>
</xsl:element>
<xsl:element name="IMGURL">
<xsl:value-of select="abi:IMGURL"/>
</xsl:element>
<xsl:element name="BRAND">
<xsl:value-of select="abi:BRAND"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<!-- Filling elements to no size item -->
<xsl:element name="SIZES">
<xsl:element name="SIZE">
<xsl:value-of select="'Uniwersalny'"/>
</xsl:element>
</xsl:element>
<xsl:element name="EANS">
<xsl:element name="EAN">
<xsl:value-of select="abi:PARTNO/text()"/>
</xsl:element>
</xsl:element>
<xsl:element name="CODES">
<xsl:element name="CODE">
<xsl:value-of select="abi:PRODUCTNO/text()"/>
</xsl:element>
</xsl:element>
<xsl:element name="STOCKS">
<xsl:element name="STOCK">
<xsl:value-of select="abi:STOCK/text()"/>
</xsl:element>
</xsl:element>
<xsl:element name="NAME">
<xsl:value-of select="abi:PRODUCT/text()"/>
</xsl:element>
<xsl:element name="ID">
<xsl:value-of select="position()"/>
</xsl:element>
<xsl:element name="DESC">
<xsl:value-of select="abi:DESCRIPTION/text()"/>
</xsl:element>
<xsl:element name="IMGURL">
<xsl:value-of select="abi:IMGURL"/>
</xsl:element>
<xsl:element name="BRAND">
<xsl:value-of select="abi:BRAND"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
</xsl:transform>
Комментарии:
1. Начните отсюда: jenitennison.com/xslt/grouping/muenchian.html — P.S. Правильно ли было бы предположить, что первое слово в
PRODUCT
является уникальным идентификатором продукта?2. Да, первое слово PRODUCT имеет только уникальное значение.
Ответ №1:
Вы можете попробовать это:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:abi="http://www.b2b.abisaltest.pl"
exclude-result-prefixes="abi">
<xsl:output method="xml" indent="yes" version="1.0" encoding="iso-8859-2"/>
<xsl:key name="qualifierKey" match="/abi:SHOP/abi:SHOPITEM" use="concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')'))" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="abi:SHOP">
<xsl:element name="SHOP">
<xsl:for-each select="abi:SHOPITEM[generate-id(.) = generate-id(key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))[1])]">
<xsl:apply-templates select="." />
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template match="abi:SHOPITEM">
<SHOPITEM>
<xsl:choose>
<xsl:when test="contains(abi:PRODUCT, 'SIZE.')">
<xsl:element name="PRODUCT">
<xsl:value-of select="concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')'))" />
</xsl:element>
<!-- Looking for SIZES -->
<xsl:element name="SIZES">
<xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
<xsl:element name="SIZE">
<xsl:value-of select="normalize-space(concat(substring-after(substring-before(abi:PRODUCT,')'),'SIZE.'), ')'))" />
</xsl:element>
</xsl:for-each>
</xsl:element>
<!-- Looking for EANS -->
<xsl:element name="PARTNOS">
<xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
<xsl:if test="abi:PARTNO != ''">
<xsl:element name="PARTNO">
<xsl:value-of select="abi:PARTNO/text()" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<!-- Looking for stocks -->
<xsl:element name="STOCKS">
<xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
<xsl:if test="abi:STOCK != ''">
<xsl:element name="STOCK">
<xsl:value-of select="abi:STOCK/text()" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<!-- Looking for external codes -->
<xsl:element name="CODES">
<xsl:for-each select="key('qualifierKey', concat(substring-before(abi:PRODUCT,'SIZE.'),substring-after(abi:PRODUCT,')')))">
<xsl:if test="abi:PRODUCTNO != ''">
<xsl:element name="CODE">
<xsl:value-of select="abi:PRODUCTNO/text()" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
<xsl:element name="PRICE">
<xsl:value-of select="abi:PRICE" />
</xsl:element>
<xsl:element name="ID">
<xsl:value-of select="position()" />
</xsl:element>
<xsl:element name="DESC">
<xsl:value-of select="abi:DESCRIPTION/text()" />
</xsl:element>
<xsl:element name="IMGURL">
<xsl:value-of select="abi:IMGURL" />
</xsl:element>
<xsl:element name="BRAND">
<xsl:value-of select="abi:BRAND" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="PRODUCT">
<xsl:value-of select="abi:PRODUCT/text()" />
</xsl:element>
<xsl:element name="PRICE">
<xsl:value-of select="abi:PRICE" />
</xsl:element>
<xsl:element name="PARTNO">
<xsl:value-of select="abi:PARTNO/text()" />
</xsl:element>
<xsl:element name="STOCK">
<xsl:value-of select="abi:STOCK/text()" />
</xsl:element>
<xsl:element name="SIZE">
<xsl:value-of select="'Uniwersalny'" />
</xsl:element>
<xsl:element name="CODE">
<xsl:value-of select="abi:PRODUCTNO/text()" />
</xsl:element>
<xsl:element name="ID">
<xsl:value-of select="position()" />
</xsl:element>
<xsl:element name="DESC">
<xsl:value-of select="abi:DESCRIPTION/text()" />
</xsl:element>
<xsl:element name="IMGURL">
<xsl:value-of select="abi:IMGURL" />
</xsl:element>
<xsl:element name="BRAND">
<xsl:value-of select="abi:BRAND" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</SHOPITEM>
</xsl:template>
</xsl:transform>
Ответ №2:
Это не совсем просто — но я думаю, что это могло бы быть намного проще, чем то, что вы пытаетесь сделать:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:abi="http://www.b2b.abisaltest.pl"
exclude-result-prefixes="abi">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="item" match="abi:SHOPITEM" use="substring-before(abi:PRODUCT, ' ')" />
<xsl:template match="/abi:SHOP">
<SHOP>
<!-- MUENCHIAN GROUPING -->
<xsl:for-each select="abi:SHOPITEM[count(. | key('item', substring-before(abi:PRODUCT, ' '))[1]) = 1]">
<xsl:variable name="current-group" select="key('item', substring-before(abi:PRODUCT, ' '))" />
<xsl:choose>
<xsl:when test="count($current-group) > 1">
<SHOPITEM>
<PRODUCT>
<xsl:value-of select="substring-before(abi:PRODUCT, 'SIZE.')"/>
<xsl:value-of select="substring-after(substring-after(abi:PRODUCT, 'SIZE. '), ')')"/>
</PRODUCT>
<SIZES>
<xsl:for-each select="$current-group">
<SIZE>
<xsl:value-of select="substring-before(substring-after(abi:PRODUCT, 'SIZE. '), ')')"/>
<xsl:text>)</xsl:text>
</SIZE>
</xsl:for-each>
</SIZES>
<PARTNOS>
<xsl:apply-templates select="$current-group/abi:PARTNO"/>
</PARTNOS>
<STOCKS>
<xsl:apply-templates select="$current-group/abi:STOCK"/>
</STOCKS>
</SHOPITEM>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$current-group"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</SHOP>
</xsl:template>
<xsl:template match="abi:*">
<xsl:element name="{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>