我有一个像这样的 xml 文件:
<products>
<cars>
<car>
<brand>Audi</brand>
<type>S3</type>
<attribs>
<attrib>
<color>1</color>
<price>45000</price>
</attrib>
<attrib>
<color>2</color>
<price>75000</price>
</attrib>
<attrib>
<color>4</color>
<price>35000</price>
</attrib>
</attribs>
</car>
<!-- Many cars following -->
</cars>
<colors>
<color>
<id>1</id>
<shortdesc>Blue</shortdesc>
<description>Blue Lagoon</description>
</color>
<color>
<id>2</id>
<shortdesc>Red</shortdesc>
<description>Red Sport</description>
</color>
<color>
<id>3</id>
<shortdesc>Green</shortdesc>
<description>Green Forest</description>
</color>
<color>
<id>4</id>
<shortdesc>Yellow</shortdesc>
<description>Yellow</description>
</color>
<!-- many colors -->
</colors>
</products>
我正在一个 excel 交叉表中转换这个 XML,其中我有垂直的汽车和水平的颜色,如下所示:
Brand / Model 1/Blue 2/Red 3/Green 4/Yellow
Audi S3 45000 75000 - 35000
Audi S6 66000 68000 59000 -
Jaguar x-type 98000 - 99500 -
并且 xslt 看起来像:
<ss:Table>
<ss:Row>
<!-- This is the header row -->
<ss:Cell>
<ss:Data ss:Type="String">Brand / Model</ss:Data>
</ss:Cell>
<xsl:for-each select="colors/color">
<ss:Cell>
<ss:Data ss:Type="String">
<xsl:value-of select="id"/>/<xsl:value-of select="shortdesc"/>
</ss:Data>
</ss:Cell>
</xsl:for-each>
</ss:Row>
<xsl:for-each select="cars/car">
<ss:Row>
<ss:Cell>
<ss:Data ss:Type="String">
<xsl:value-of select="brand"/> <xsl:value-of select="type"/>
</ss:Data>
</ss:Cell>
<xsl:for-each select="attribs/attrib">
<!-- I Know this is incorrect, but what to put in the if ? -->
<xsl:if test="color = /colors/color/id">
<ss:Cell>
<ss:Data ss:Type="String">
<xsl:value-of select="price"/>
</ss:Data>
</ss:Cell>
</xsl:if>
<xsl:if test="color != /colors/color/id">
<ss:Cell>
<ss:Data ss:Type="String">-</ss:Data>
</ss:Cell>
</xsl:if>
</xsl:for-each>
</ss:Row>
</xsl:for-each>
</ss:Table>
我正在寻找在右栏中比较/写入价格的方法。
该模板引用节点/products 以便能够访问汽车和颜色。
一种可能的方法是在我在标题中写入颜色的同时创建一个数组,并在我处理汽车时与它进行比较;
这是一种可能的方法还是可能有更好的方法?
另一个细节:我无法更改 XML,因为它已经是这样设计的(实际上它不是我正在处理的汽车,只是为了让它更简单)
最佳答案
您可以使用复合 key 按品牌、类型和颜色收集汽车:
<xsl:output indent="yes"/>
<xsl:key name="k_cars"
match="/products/cars/car/attribs/attrib"
use="concat(../../brand,../../type,color)"/>
然后迭代
cars/car
并且,因为您需要检查所有颜色的价格(有些汽车可能会漏掉一种颜色),请在 colors/color
上进行子迭代并使用 xsl:choose
对 key 进行测试。如果key返回一个节点,则打印对应的价格;否则打印 -
:<xsl:variable name="car" select="."/>
<xsl:for-each select="/products/colors/*">
<xsl:variable name="v_CarColor"
select="key('k_cars',concat($car/brand,$car/type,id))"/>
<xsl:choose>
<xsl:when test="$v_CarColor">
<ss:Cell>
<ss:Data ss:Type="String">
<xsl:value-of select="$v_CarColor/price"/>
</ss:Data>
</ss:Cell>
</xsl:when>
<xsl:otherwise>
<ss:Cell>
<ss:Data ss:Type="String">-</ss:Data>
</ss:Cell>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
您的最终转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ss="excel.xml">
<xsl:output indent="yes"/>
<xsl:key name="k_cars"
match="/products/cars/car/attribs/attrib"
use="concat(../../brand,../../type,color)"/>
<xsl:template match="/products">
<ss:Table>
<ss:Row>
<!-- This is the header row -->
<ss:Cell>
<ss:Data ss:Type="String">Brand / Model</ss:Data>
</ss:Cell>
<xsl:for-each select="colors/color">
<ss:Cell>
<ss:Data ss:Type="String">
<xsl:value-of select="id"/>/<xsl:value-of select="shortdesc"/>
</ss:Data>
</ss:Cell>
</xsl:for-each>
</ss:Row>
<xsl:for-each select="cars/car">
<ss:Row>
<ss:Cell>
<ss:Data ss:Type="String">
<xsl:value-of select="brand"/> <xsl:value-of select="type"/>
</ss:Data>
</ss:Cell>
<xsl:variable name="car" select="."/>
<xsl:for-each select="/products/colors/*">
<xsl:variable name="v_CarColor"
select="key('k_cars',concat($car/brand,$car/type,id))"/>
<xsl:choose>
<xsl:when test="$v_CarColor">
<ss:Cell>
<ss:Data ss:Type="String">
<xsl:value-of select="$v_CarColor/price"/>
</ss:Data>
</ss:Cell>
</xsl:when>
<xsl:otherwise>
<ss:Cell>
<ss:Data ss:Type="String">-</ss:Data>
</ss:Cell>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</ss:Row>
</xsl:for-each>
</ss:Table>
</xsl:template>
</xsl:stylesheet>
关于xml - XSL : create a cross tab under Excel with XSLT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6958734/