Given
<root>
<item>
<detail>100</detail>
<detail>200</detail>
</item>
<item>
<detail>50</detail>
<detail>100</detail>
</item>
</root>
How I would I make this data into a simple SVG bar chart? (nothing fancy, just four bars representing the relation between numbers in some fashion)
Something like this: (I know there is no separation between the two items, but lets just say I will make them different colors, the first two bars blue the second red)
I guess I am not sure what the syntax inside the xsl:template would be to generate the SVG code? Best answer gets accepted!
Execute an XSLT transformation from an XML file Associate an XSLT style sheet with the XML document. Add an xml-stylesheet processing instruction to the XML document. For example, add the following line to the document prolog: <? xml-stylesheet type='text/xsl' href='filename.
XSLT is used to transform XML document from one form to another form. XSLT uses Xpath to perform matching of nodes to perform these transformation . The result of applying XSLT to XML document could be an another XML document, HTML, text or any another document from technology perspective.
An XSLT stylesheet is an XML document that consists of a combination of XHTML markup, XSLT template rules, and XPath statements that work together. XHTML markup defines the display environment that XML data is presented in.
Here is an example with some more bells & whistles:
With your input this code:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/2000/svg"
>
<xsl:output indent="yes" cdata-section-elements="style" />
<xsl:param name="width" select="40" /><!-- width of bars -->
<xsl:param name="space" select="10" /><!-- space between bars and items -->
<xsl:variable name="max-y" select="//detail[not(//detail > .)][1]" />
<xsl:template match="root">
<svg>
<defs>
<style type="text/css"><![CDATA[
g.bar text {
font-family: Arial;
text-anchor: middle;
fill: white;
}
g.bar rect {
fill: black;
}
]]></style>
</defs>
<g transform="translate(10, 10)">
<xsl:apply-templates select="item" />
</g>
</svg>
</xsl:template>
<xsl:template match="item">
<xsl:variable name="prev-item" select="preceding-sibling::item" />
<g class="item" id="item-{position()}" transform="translate({
count($prev-item/detail) * ($width + $space)
+ count($prev-item) * $space
})">
<xsl:apply-templates select="detail" />
</g>
</xsl:template>
<xsl:template match="detail">
<xsl:variable name="idx" select="count(preceding-sibling::detail)" />
<xsl:variable name="pos" select="$idx * ($width + $space)" />
<g class="bar">
<rect x="{$pos}" y="{$max-y - .}" height="{.}" width="{$width}" />
<text x="{$pos + $width div 2.0}" y="{$max-y - $space}">
<xsl:value-of select="."/>
</text>
</g>
</xsl:template>
</xsl:stylesheet>
produces
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<style type="text/css"><![CDATA[
g.bar text {
font-family: Arial;
text-anchor: middle;
fill: white;
}
g.bar rect {
fill: black;
}
]]></style>
</defs>
<g transform="translate(10, 10)">
<g class="item" id="item-1" transform="translate(0)">
<g class="bar">
<rect x="0" y="100" height="100" width="40"/>
<text x="20" y="190">100</text>
</g>
<g class="bar">
<rect x="50" y="0" height="200" width="40"/>
<text x="70" y="190">200</text>
</g>
</g>
<g class="item" id="item-2" transform="translate(110)">
<g class="bar">
<rect x="0" y="150" height="50" width="40"/>
<text x="20" y="190">50</text>
</g>
<g class="bar">
<rect x="50" y="100" height="100" width="40"/>
<text x="70" y="190">100</text>
</g>
</g>
</g>
</svg>
which renders like this
on my machine.
SVG is just a special kind of xml, check the reference at http://www.w3.org/TR/SVG/intro.html
You start with the <svg>
tag and start nesting.
XSL is a whole different world. I used a reference example at http://www.carto.net/svg/samples/xslt/#basic and modified it to work with your xml to demonstrate how to use xsl for your nested data. Basically, I just added an inner for-each loop.
Here is an example starting point:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="root">
<svg width="200px" height="500px" xmlns="http://www.w3.org/2000/svg">
<g id="bar" transform="translate(0,200)">
<xsl:for-each select="item">
<xsl:variable name="item_position" select="(position()-1) * 100"/>
<xsl:for-each select="detail">
<xsl:variable name="val" select="."/>
<rect x="{$item_position + position()*40}" y="-{$val}" height="{$val}" width="35" style="fill:{@fill};"/>
<text x="{$item_position + position()*40 + 15}" y="-{($val div 2.0) - 5}" style="font-family:arial;text-anchor:middle;baseline-shift:-15;fill:white">
<xsl:value-of select="."/>
</text>
</xsl:for-each>
</xsl:for-each>
</g>
</svg>
</xsl:template>
</xsl:transform>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With