В этом преобразовании используется именованный шаблон, который при вызове с параметром row
, содержащим продукт, создает строку с полным описанием :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kFollowingDesc"
match="row[not(number(*[1])=number(*[1]))]"
use="generate-id(preceding-sibling::row[number(*[1])=number(*[1])][1])"/>
<xsl:template match="/">
<xsl:call-template name="constructDescription">
<xsl:with-param name="pRow" select="/*/*[1]"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="constructDescription">
<xsl:param name="pRow"/>
<xsl:for-each select=
"$pRow/*[position() >= 3
and
not(position() > count($pRow/*) -2)
]
">
<xsl:value-of select="concat(.,' ')"/>
</xsl:for-each>
<xsl:for-each select="key('kFollowingDesc', generate-id($pRow))">
<xsl:value-of select="concat(.,' ')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к следующему документу XML (ваш, но правильно сформированный и значительно усеченный):
<root>
<row>
<rowWords>6.00</rowWords>
<rowWords>PRODUCTCODE2</rowWords>
<rowWords>DESCRIPTIONWORD1</rowWords>
<rowWords>DESCRIPTIONWORD2</rowWords>
<rowWords>DESCRIPTIONWORD3</rowWords>
<rowWords>DESCRIPTIONWORD4</rowWords>
<rowWords>DESCRIPTIONWORD5</rowWords>
<rowWords>DESCRIPTIONWORD6</rowWords>
<rowWords>DESCRIPTIONWORD7</rowWords>
<rowWords>DESCRIPTIONWORD8</rowWords>
<rowWords>DESCRIPTIONWORD9</rowWords>
<rowWords>11.00</rowWords>
<rowWords>66.00</rowWords>
</row>
<row>
<rowWords>DESCRIPTIONWORD10</rowWords>
<rowWords>DESCRIPTIONWORD11</rowWords>
<rowWords>DESCRIPTIONWORD12</rowWords>
<rowWords>DESCRIPTIONWORD13</rowWords>
</row>
</root>
желаемое, правильное описание производится :
DESCRIPTIONWORD1 DESCRIPTIONWORD2 DESCRIPTIONWORD3 DESCRIPTIONWORD4 DESCRIPTIONWORD5 DESCRIPTIONWORD6 DESCRIPTIONWORD7 DESCRIPTIONWORD8 DESCRIPTIONWORD9 DESCRIPTIONWORD10 DESCRIPTIONWORD11 DESCRIPTIONWORD12 DESCRIPTIONWORD13
Объяснение : этот именованный шаблон не требует пояснений, кроме проверки, если какой-либо элемент является числом, а именно:
number($x) = number($x)
это оценивается как true()
именно тогда, когда $x
является числом (или значением любого типа, которое может быть успешно преобразовано в число).
Мы тестируем:
not(number(*[1])=number(*[1]))
, который оценивается в true()
только тогда, когда первый rowWords
дочерний элемент следующей строки не является числом - и это означает, что он содержит больше слов описания.
Наконец : Все это интегрировано в код ОП:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="something">
<xsl:output indent="yes"/>
<xsl:key name="kFollowingDesc"
match="row[not(number(*[1])=number(*[1]))]"
use="generate-id(preceding-sibling::row[number(*[1])=number(*[1])][1])"/>
<xsl:template match="/root">
<a:Invoice>
<Products>
<xsl:for-each select="row[number(*[1])=number(*[1])]">
<!-- With this if, i prevent create a product node with partial description-->
<xsl:if test="number(rowWords[1])">
<Product>
<xsl:attribute name="quantity">
<xsl:value-of select="rowWords[1]"/>
</xsl:attribute>
<xsl:attribute name="productCode">
<xsl:value-of select="rowWords[2]"/>
</xsl:attribute>
<!--Here is the problem (Thank you Dimitri) -->
<xsl:variable name="vDescriptions">
<xsl:call-template name="constructDescription">
<xsl:with-param name="pRow" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:attribute name="description">
<xsl:value-of select="normalize-space($vDescriptions)"/>
</xsl:attribute>
<xsl:attribute name="unitValue">
<xsl:value-of select="rowWords[last()-1]"/>
</xsl:attribute>
<xsl:attribute name="amount">
<xsl:value-of select="rowWords[last()]"/>
</xsl:attribute>
</Product>
</xsl:if>
</xsl:for-each>
</Products>
</a:Invoice>
</xsl:template>
<xsl:template name="constructDescription">
<xsl:param name="pRow"/>
<xsl:for-each select=
"$pRow/*[position() >= 3
and
not(position() > count($pRow/*) -2)
]
">
<xsl:value-of select="concat(.,' ')"/>
</xsl:for-each>
<xsl:for-each select="key('kFollowingDesc', generate-id($pRow))">
<xsl:value-of select="concat(.,' ')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к новому XML-документу, который он предоставил :
<root>
<row>
<rowWords>5.00</rowWords>
<rowWords>PRODUCTCODE1</rowWords>
<rowWords>DESCRIPTIONWORD1</rowWords>
<rowWords>DESCRIPTIONWORD2</rowWords>
<rowWords>DESCRIPTIONWORD3</rowWords>
<rowWords>DESCRIPTIONWORD4</rowWords>
<rowWords>DESCRIPTIONWORD5</rowWords>
<rowWords>11.28</rowWords>
<rowWords>56.40</rowWords>
</row>
<row>
<rowWords>DESCRIPTIONWORD6</rowWords>
</row>
<row>
<rowWords>6.00</rowWords>
<rowWords>PRODUCTCODE2</rowWords>
<rowWords>DESCRIPTIONWORD1</rowWords>
<rowWords>DESCRIPTIONWORD2</rowWords>
<rowWords>DESCRIPTIONWORD3</rowWords>
<rowWords>DESCRIPTIONWORD4</rowWords>
<rowWords>DESCRIPTIONWORD5</rowWords>
<rowWords>11.00</rowWords>
<rowWords>66.00</rowWords>
</row>
<row>
<rowWords>DESCRIPTIONWORD6</rowWords>
<rowWords>DESCRIPTIONWORD7</rowWords>
<rowWords>DESCRIPTIONWORD8</rowWords>
</row>
<row>
<rowWords>DESCRIPTIONWORD9</rowWords>
<rowWords>DESCRIPTIONWORD10</rowWords>
</row>
<row>
<rowWords>10.00</rowWords>
<rowWords>PRODUCTCODE3</rowWords>
<rowWords>DESCRIPTIONWORD1</rowWords>
<rowWords>DESCRIPTIONWORD2</rowWords>
<rowWords>10.00</rowWords>
<rowWords>100.00</rowWords>
</row> . . any amount of rows containing products .
</root>
желаемый, правильный результат получается :
<a:Invoice xmlns:a="something">
<Products>
<Product quantity="5.00" productCode="PRODUCTCODE1" description="DESCRIPTIONWORD1 DESCRIPTIONWORD2 DESCRIPTIONWORD3 DESCRIPTIONWORD4 DESCRIPTIONWORD5 DESCRIPTIONWORD6" unitValue="11.28" amount="56.40" />
<Product quantity="6.00" productCode="PRODUCTCODE2" description="DESCRIPTIONWORD1 DESCRIPTIONWORD2 DESCRIPTIONWORD3 DESCRIPTIONWORD4 DESCRIPTIONWORD5 DESCRIPTIONWORD6 DESCRIPTIONWORD7 DESCRIPTIONWORD8 DESCRIPTIONWORD9 DESCRIPTIONWORD10" unitValue="11.00" amount="66.00" />
<Product quantity="10.00" productCode="PRODUCTCODE3" description="DESCRIPTIONWORD1 DESCRIPTIONWORD2" unitValue="10.00" amount="100.00" />
</Products>
</a:Invoice>