XSLT:将Muenchian分组与SVG条形图相结合

时间:2015-02-18 19:16:51

标签: xml xslt svg group-by bar-chart

我正在尝试创建一个SVG条形图,其中显示每日销售额。这意味着下面的xml数据必须按属性“date”分组。由于我必须使用XSLT 1.0,我必须做“Muenchian分组”或其他一些解决方法。

<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条形图。所以绘图部分不是问题。 Stackoverflow上有很多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>

1 个答案:

答案 0 :(得分:1)

最好从跨越多个日期的示例开始:

<强> 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