XSLT:结合 Muenchian 分组和 SVG 条形图
XSLT: Combining Muenchian grouping with SVG bar chart
我正在尝试创建一个显示每日销售额的 SVG 条形图。这意味着下面的 xml-数据必须按属性 "date" 分组。由于我必须使用 XSLT 1.0,因此我必须执行 "Muenchian grouping" 或其他一些解决方法。
<orders>
<order id="01" date="2015-01-01">
<product price="20">Apple</product>
<product price="5">Pear</product>
</order>
<order id="02" date="2015-01-01">
<product price="20">Pear</product>
<product price="40">Plum</product>
</order>
</orders>
我能够在不对条目进行分组的情况下绘制 SVG 条形图。所以绘图部分不是问题。 Whosebug 上有很多 Muenchian 分组示例,但我无法使其正常工作。谢谢您的帮助。
XSL:
<xsl:variable name="baseline" select="480"/>
<xsl:key name="order-by-date" match="order" use="@date" />
<xsl:template match="orders">
<svg:svg>
<xsl:apply-templates select="order[generate-id(.)=generate-id(key('order-by-date',@date)[1])]" />
</svg:svg>
</xsl:template>
<xsl:template match="order">
<xsl:for-each select="key('order-by-date', @date)">
<!-- draw the Rectangles (bars) for each group -->
<xsl:variable name="x-offset" select="40 + position() * 40" />
<xsl:variable name="y-offset" select="$baseline"/>
<xsl:variable name="y" select="$y-offset - sum(current()/product/@price)"/>
<!-- attributes of the rectangle -->
<svg:path>
<xsl:attribute name="style">
<xsl:text>fill:</xsl:text>
<xsl:value-of select="blue"/>
</xsl:attribute>
<xsl:attribute name="d">
<!-- move to the lower left corner of the rectangle -->
<xsl:text>M </xsl:text>
<xsl:value-of select="$x-offset - 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y-offset"/>
<!-- draw line to the upper left corner of the rectangle -->
<xsl:text> L </xsl:text>
<xsl:value-of select="$x-offset - 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y"/>
<!-- draw line to the upper right corner of the rectangle -->
<xsl:text> L </xsl:text>
<xsl:value-of select="$x-offset + 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y"/>
<!-- draw line to the lower right corner of the rectangle -->
<xsl:text> L </xsl:text>
<xsl:value-of select="$x-offset + 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y-offset"/>
<!-- close path and fill the rectangle -->
<xsl:text> Z</xsl:text>
</xsl:attribute>
</svg:path>
<!-- write Date underneath each bar -->
<svg:text style="writing-mode:tb" x="{position()*30 + 50}" y="{$baseline + 20}">
<xsl:value-of select="substring(@datum,9,2)" />
</svg:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
最好从一个跨越多个日期的例子开始:
XML
<orders>
<order id="01" date="2015-01-01">
<product price="20">Apple</product>
<product price="5">Pear</product>
</order>
<order id="02" date="2015-01-01">
<product price="20">Pear</product>
<product price="40">Plum</product>
</order>
<order id="03" date="2015-01-02">
<product price="20">Apple</product>
<product price="40">Plum</product>
</order>
</orders>
然后您可以按照以下行构建样式表:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/2000/svg">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="order-by-date" match="order" use="@date" />
<xsl:template match="/orders">
<svg version="1.0">
<xsl:apply-templates select="order[generate-id()=generate-id(key('order-by-date',@date)[1])]" />
</svg>
</xsl:template>
<xsl:template match="order">
<xsl:variable name="y" select="sum(key('order-by-date',@date)/product/@price)"/>
<!-- create a svg object here, using the y dimension -->
</xsl:template>
</xsl:stylesheet>
我自己的偏好是使用矩形作为创建对象,例如:
<rect x="{40 * position()}" width="30" height="{$y}"/>
另请参阅:
Using XSLT to create SVG
我正在尝试创建一个显示每日销售额的 SVG 条形图。这意味着下面的 xml-数据必须按属性 "date" 分组。由于我必须使用 XSLT 1.0,因此我必须执行 "Muenchian grouping" 或其他一些解决方法。
<orders>
<order id="01" date="2015-01-01">
<product price="20">Apple</product>
<product price="5">Pear</product>
</order>
<order id="02" date="2015-01-01">
<product price="20">Pear</product>
<product price="40">Plum</product>
</order>
</orders>
我能够在不对条目进行分组的情况下绘制 SVG 条形图。所以绘图部分不是问题。 Whosebug 上有很多 Muenchian 分组示例,但我无法使其正常工作。谢谢您的帮助。
XSL:
<xsl:variable name="baseline" select="480"/>
<xsl:key name="order-by-date" match="order" use="@date" />
<xsl:template match="orders">
<svg:svg>
<xsl:apply-templates select="order[generate-id(.)=generate-id(key('order-by-date',@date)[1])]" />
</svg:svg>
</xsl:template>
<xsl:template match="order">
<xsl:for-each select="key('order-by-date', @date)">
<!-- draw the Rectangles (bars) for each group -->
<xsl:variable name="x-offset" select="40 + position() * 40" />
<xsl:variable name="y-offset" select="$baseline"/>
<xsl:variable name="y" select="$y-offset - sum(current()/product/@price)"/>
<!-- attributes of the rectangle -->
<svg:path>
<xsl:attribute name="style">
<xsl:text>fill:</xsl:text>
<xsl:value-of select="blue"/>
</xsl:attribute>
<xsl:attribute name="d">
<!-- move to the lower left corner of the rectangle -->
<xsl:text>M </xsl:text>
<xsl:value-of select="$x-offset - 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y-offset"/>
<!-- draw line to the upper left corner of the rectangle -->
<xsl:text> L </xsl:text>
<xsl:value-of select="$x-offset - 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y"/>
<!-- draw line to the upper right corner of the rectangle -->
<xsl:text> L </xsl:text>
<xsl:value-of select="$x-offset + 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y"/>
<!-- draw line to the lower right corner of the rectangle -->
<xsl:text> L </xsl:text>
<xsl:value-of select="$x-offset + 10"/>
<xsl:text> </xsl:text>
<xsl:value-of select="$y-offset"/>
<!-- close path and fill the rectangle -->
<xsl:text> Z</xsl:text>
</xsl:attribute>
</svg:path>
<!-- write Date underneath each bar -->
<svg:text style="writing-mode:tb" x="{position()*30 + 50}" y="{$baseline + 20}">
<xsl:value-of select="substring(@datum,9,2)" />
</svg:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
最好从一个跨越多个日期的例子开始:
XML
<orders>
<order id="01" date="2015-01-01">
<product price="20">Apple</product>
<product price="5">Pear</product>
</order>
<order id="02" date="2015-01-01">
<product price="20">Pear</product>
<product price="40">Plum</product>
</order>
<order id="03" date="2015-01-02">
<product price="20">Apple</product>
<product price="40">Plum</product>
</order>
</orders>
然后您可以按照以下行构建样式表:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/2000/svg">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="order-by-date" match="order" use="@date" />
<xsl:template match="/orders">
<svg version="1.0">
<xsl:apply-templates select="order[generate-id()=generate-id(key('order-by-date',@date)[1])]" />
</svg>
</xsl:template>
<xsl:template match="order">
<xsl:variable name="y" select="sum(key('order-by-date',@date)/product/@price)"/>
<!-- create a svg object here, using the y dimension -->
</xsl:template>
</xsl:stylesheet>
我自己的偏好是使用矩形作为创建对象,例如:
<rect x="{40 * position()}" width="30" height="{$y}"/>
另请参阅: Using XSLT to create SVG