- From: Panie, Edouard (MED) <Edouard.Panie@med.ge.com>
- Date: Mon, 16 Jul 2001 17:25:57 +0200
- To: "'www-svg@w3.org'" <www-svg@w3.org>
Hello, I'm learning SVG and I found DougTidwell "XML to SVG tutorial" on the developersworks page. http://www-106.ibm.com/developerworks/education/transforming-xml/xmltosvg/in dex.html#3 It's a great tutorial! Unfortunately I have a little problem when I try the sales histogram example. I copied the sales.xml, sales.dtd and sales.xsl files. It almost works but not perfectly: it works a little bit because I do get a graph with the axes and columns with the good height but all the columns are on top one another, it seems to me that the position() function doesn't work. Do I need to install something special in order for the position() function to work or to include a package in the header of the xsl doc??? What I did until now: I downloaded the xalan-j_2_2_D6, I set the classpath as showed below, then in a DOS command window, I go to the directory where I stored the .xml, .dtd and .xsl files and call: D:\mySamplesFolder>java org.apache.xalan.xslt.Process -in sales.xml -xsl sales.xsl -out theResult.svg CLASSPATH=c:\Program Files\Exceed.nt;d:\tools\xalan-j_2_2_D6\bin\xerces.jar;d:\tools\xalan-j_2_2_ D6\bin\xalan.jar;c:\jdk1.1.8\lib\classes.zip;d:\tools\xalan-j_2_2_D6\bin\xal ansamples.jar Thanks a lot for your help Edouard Panié Here is the xsl file I use and the svg output: //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// / sales.xsl //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// / <?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes" doctype-system="svg-19991203.dtd" version="1.0" encoding="ISO-8859-1" /> <xsl:strip-space elements="*"/> <!--================================================================--> <!-- Root Element Template --> <!-- This template specifies what creates the root element of the --> <!-- result tree. In this case, it tells the XSL processor to --> <!-- start with the <sales> element. --> <!--================================================================--> <xsl:template match="/"> <xsl:apply-templates select="sales"/> </xsl:template> <!--================================================================--> <!-- <sales> template --> <!-- --> <!-- This template creates the entire SVG bar chart. The title of --> <!-- the chart comes from the <heading> element, and the size and --> <!-- position of the bars in the graph are calculated by adding the --> <!-- <product> elements inside each <region> element. In addition, --> <!-- the labels in the graph legend are generated from the text of --> <!-- the <name> element inside each <region> element. --> <!-- --> <!-- To simplify the stylesheet, we hardcoded the scale, the dashed --> <!-- lines behind the graph, and other assumptions about how much --> <!-- space we'll need, etc. You could certainly add more variables --> <!-- and parameters to the templates to make the stylesheet more --> <!-- robust.... --> <!--================================================================--> <xsl:template match="sales"> <svg width="400" height="300"> <!--================================================================--> <!-- Create the title for the bar chart. We'll use the text of the --> <!-- <heading> element for this. Before we output the text, we'll --> <!-- set up the SVG <text> element with the appropriate style, x, --> <!-- and y attributes. We hardcoded the x and y values to simplify --> <!-- things; it would complicate the stylesheet significantly to --> <!-- figure out how wide the entire chart needed to be, then anchor --> <!-- the title in the middle. --> <!--================================================================--> <text style="font-size:18; text-anchor:middle" x="120" y="20"> <xsl:value-of select="caption/heading"/> </text> <!--================================================================--> <!-- Now we print the subtitle of the bar chart. This text doesn't --> <!-- change, so we just hardcode the SVG element here. --> <!--================================================================--> <text style="font-size:12; text-anchor:middle" y="33" x="120">(in millions of dollars)</text> <!--================================================================--> <!-- We hardcode the X and Y axis and the grid lines. Note that we --> <!-- use a gray color and the stroke-dasharray properties to make --> <!-- the lines lighter. Also, because all SVG drawing operations --> <!-- are opaque by default, we draw the grid lines first. That --> <!-- means everything we draw later will appear on top of the grid --> <!-- lines. --> <!-- --> <!-- A note about the d attribute of the <path> elements: --> <!-- The values here contain move (M) commands, lineto (L) commands,--> <!-- and closepath (Z) commands. The first <path> element here --> <!-- tells the SVG rendering engine to move to x,y coordinate --> <!-- (40, 200), draw a line to (40, 30), then close the path. We'll --> <!-- use this syntax throughout the stylesheet. See the SVG spec --> <!-- for more information about paths and other drawing commands. --> <!--================================================================--> <g style="stroke-width:2; stroke:black"> <path d="M 40 220 L 40 30 L 40 220 L 200 220 Z"/> </g> <g style="fill:none; stroke:#B0B0B0; stroke-width:1; stroke-dasharray:2 4"> <path d="M 42 200 L 198 200 Z"/> <path d="M 42 180 L 198 180 Z"/> <path d="M 42 160 L 198 160 Z"/> <path d="M 42 140 L 198 140 Z"/> <path d="M 42 120 L 198 120 Z"/> <path d="M 42 100 L 198 100 Z"/> <path d="M 42 80 L 198 80 Z"/> <path d="M 42 60 L 198 60 Z"/> <path d="M 42 40 L 198 40 Z"/> </g> <!--================================================================--> <!-- We hardcoded the labels here as well. Each one is written to --> <!-- the left of the grid lines, and is right-justified (that's --> <!-- what text-anchor:end does). --> <!--================================================================--> <g style="text-anchor:end; font-size:9"> <text x="36" y="203">20</text> <text x="36" y="183">40</text> <text x="36" y="163">60</text> <text x="36" y="143">80</text> <text x="36" y="123">100</text> <text x="36" y="103">120</text> <text x="36" y="83">140</text> <text x="36" y="63">160</text> <text x="36" y="43">$180</text> </g> <!--================================================================--> <!-- Now it's time to get to work. For each region we're going to --> <!-- represent in the bar chart, we'll need several things: --> <!-- --> <!-- 1) The x-coordinate where the bar should start --> <!-- 2) The y-coordinate where the bar should start --> <!-- 3) The color we should use to fill in the bar --> <!-- 4) The y-coordinate where the legend entry should start. --> <!-- --> <!-- We'll use the variables $x-offset, $y-offset, $color, and --> <!-- $y-legend-offset to represent these things. We'll update --> <!-- these variables during each iteration of the <xsl:for-each> --> <!-- element. --> <!--================================================================--> <!--================================================================--> <!-- We use the <for-each> element to loop through all of the --> <!-- instances of the <region> tag. --> <!--================================================================--> <xsl:for-each select="region"> <!--================================================================--> <!-- Now that we've set up all the variables we'll need, we'll --> <!-- invoke the template for the <region> element. --> <!--================================================================--> <xsl:apply-templates select="."> <!--================================================================--> <!-- We use the position of this region element to determine the --> <!-- color. The combination of the position() function from XPath --> <!-- and the mod operator lets us cycle through five different --> <!-- colors. --> <!--================================================================--> <xsl:with-param name="color"> <xsl:choose> <xsl:when test="(position() mod 5) = 1"> <xsl:text>red</xsl:text> </xsl:when> <xsl:when test="(position() mod 5) = 2"> <xsl:text>yellow</xsl:text> </xsl:when> <xsl:when test="(position() mod 5) = 3"> <xsl:text>purple</xsl:text> </xsl:when> <xsl:when test="(position() mod 5) = 4"> <xsl:text>blue</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>green</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:with-param> <xsl:with-param name="y-legend-offset"> <xsl:value-of select="60 + (position() * 30)"/> </xsl:with-param> <!--================================================================--> <!-- For the $x-offset, we use the position of the current region. --> <!--================================================================--> <xsl:with-param name="x-offset"> <xsl:value-of select="30 + (position() * 30)"/> </xsl:with-param> <!--================================================================--> <!-- Notice that we just hardcoded $y-offset.... --> <!--================================================================--> <xsl:with-param name="y-offset" select="220"/> </xsl:apply-templates> </xsl:for-each> </svg> </xsl:template> <!--================================================================--> <!-- <region> template --> <!-- --> <!-- This template generates the bar chart data for each region. --> <!-- For each region, we have to output four things: --> <!-- --> <!-- 1) The bar itself. The bar's height is determined by the --> <!-- sales data from the XML document, and it's fill color is --> <!-- passed in on the $color parameter. --> <!-- 2) The sales total. This is drawn as text, centered just --> <!-- above the bar. The value is calculated from the XML. --> <!-- 3) The text of the legend. This is the <name> element. It --> <!-- is drawn based on the $y-legend-offset. --> <!-- 4) The color bar for the legend. This is a block filled in --> <!-- based on the $color parameter. Its position is based on --> <!-- the $y-legend-offset. --> <!--================================================================--> <xsl:template match="region"> <!--================================================================--> <!-- Our four parameters are the x- and y-offsets where the bar --> <!-- should start, the color used to fill in the bar, and the --> <!-- y-offset where the legend entry for this <region> should start.--> <!--================================================================--> <xsl:param name="x-offset" select="'60'"/> <xsl:param name="y-offset" select="'220'"/> <xsl:param name="color" select="'red'"/> <xsl:param name="y-legend-offset" select="'90'"/> <!--================================================================--> <!-- We'll calculate the y value for the top of the bar based on --> <!-- the total sales for this <region>. This value is subtracted --> <!-- from the y-offset from which we started. --> <!--================================================================--> <xsl:variable name="y"> <xsl:value-of select="$y-offset - sum(product)"/> </xsl:variable> <!--================================================================--> <!-- Task 1: Draw the bar --> <!-- --> <!-- For this task, we'll create an SVG <path> element. We'll set --> <!-- the fill property so the bar will be filled with the correct --> <!-- color. Notice that fill is a property set with the XML style --> <!-- attribute; SVG does this to be consistent with CSS, even --> <!-- though it creates some confusion as to which things are --> <!-- attributes and which things are properties set in the text of --> <!-- attributes. --> <!-- --> <!-- Once we've created the style attribute and set the fill --> <!-- property correctly, we'll create the d attribute. The d --> <!-- attribute contains five commands: --> <!-- --> <!-- 1) Move to the origin of the bar. --> <!-- 2) Draw a line to the upper left corner of the bar. --> <!-- 3) Draw a line to the upper right corner of the bar. --> <!-- 4) Draw a line to the lower right corner of the bar. --> <!-- 5) Close the path. This draws a line from wherever we are --> <!-- to the start of the path. --> <!-- --> <!-- The move command is M, the lineto command is L, and the --> <!-- closepath command is Z. --> <!--================================================================--> <path> <xsl:attribute name="style"> <xsl:text>stroke-width:2; stroke:black; fill:</xsl:text> <xsl:value-of select="$color"/> </xsl:attribute> <xsl:attribute name="d"> <!--================================================================--> <!-- Move to the origin of the bar. The $x-offset parameter is the --> <!-- center of the bar, so it begins 10 units to the left of --> <!-- $x-offset ($x-offset - 10), and ends 10 units to the right --> <!-- ($x-offset + 10). The $y-offset is used as is. --> <!--================================================================--> <xsl:text>M </xsl:text> <xsl:value-of select="$x-offset - 10"/> <xsl:text> </xsl:text> <xsl:value-of select="$y-offset"/> <!--================================================================--> <!-- Move to the upper left corner of the bar. The x dimension is --> <!-- ($x-offset - 10), and the y dimension is the $y variable we --> <!-- calculated earlier. --> <!--================================================================--> <xsl:text> L </xsl:text> <xsl:value-of select="$x-offset - 10"/> <xsl:text> </xsl:text> <xsl:value-of select="$y"/> <!--================================================================--> <!-- Move to the upper right corner of the bar. The x dimension is --> <!-- ($x-offset + 10), and the y dimension is the $y variable we --> <!-- calculated earlier. --> <!--================================================================--> <xsl:text> L </xsl:text> <xsl:value-of select="$x-offset + 10"/> <xsl:text> </xsl:text> <xsl:value-of select="$y"/> <!--================================================================--> <!-- Move to the lower right corner of the bar. The x dimension is --> <!-- ($x-offset + 10), and the y dimension is the $y-offset value --> <!-- that was passed in. --> <!--================================================================--> <xsl:text> L </xsl:text> <xsl:value-of select="$x-offset + 10"/> <xsl:text> </xsl:text> <xsl:value-of select="$y-offset"/> <!--================================================================--> <!-- Close the path. All we need is a Z command. --> <!--================================================================--> <xsl:text> Z</xsl:text> </xsl:attribute> </path> <!--================================================================--> <!-- Task 2: Draw the sales total. --> <!-- --> <!-- For this task, we'll create an SVG <text> element. It will be --> <!-- centered (text-anchor:middle, a property we inherit from an --> <!-- earlier <g> element) and drawn just above the top of the bar. --> <!-- The center of the bar is $x-offset, which we received as a --> <!-- parameter, and the top of the bar is $y. We'll subtract 5 --> <!-- units from $y to calculate its starting point. The value we --> <!-- print is based on the sum of all <product> elements contained --> <!-- inside this <region>. --> <!--================================================================--> <text style="font-size:10; text-anchor:middle"> <xsl:attribute name="x"> <xsl:value-of select="$x-offset"/> </xsl:attribute> <xsl:attribute name="y"> <xsl:value-of select="$y - 5"/> </xsl:attribute> <xsl:value-of select="sum(product)"/> </text> <!--================================================================--> <!-- Task 3: Draw the text of the legend. --> <!-- --> <!-- For this task, we'll use the <name> element contained inside --> <!-- this <region>. We create an SVG <text> element to do this. --> <!-- The x coordinate of the text is 240, while the y coordinate is --> <!-- based on the $y-legend-offset. We simply fill in the style, --> <!-- x, and y attributes of the <text> tag, then use the value of --> <!-- the <name> element as the text of the new tag. --> <!--================================================================--> <text style="font-size:14; text-anchor:start" x="240"> <xsl:attribute name="y"> <xsl:value-of select="$y-legend-offset"/> </xsl:attribute> <xsl:value-of select="name"/> </text> <!--================================================================--> <!-- Task 4. Draw the color bar for the legend. --> <!-- --> <!-- For this task, we'll draw a small box that is filled in with --> <!-- the correct color. The position of the box is based on the --> <!-- hardcoded x coordinate of 220, and the $y-legend-offset we got --> <!-- as a parameter. The box is 10 x 10 units. --> <!--================================================================--> <path> <xsl:attribute name="style"> <xsl:text>stroke:black; stroke-width:2; fill:</xsl:text> <xsl:value-of select="$color"/> </xsl:attribute> <xsl:attribute name="d"> <xsl:text>M 220 </xsl:text> <xsl:value-of select="$y-legend-offset - 10"/> <xsl:text> L 220 </xsl:text> <xsl:value-of select="$y-legend-offset"/> <xsl:text> L 230 </xsl:text> <xsl:value-of select="$y-legend-offset"/> <xsl:text> L 230 </xsl:text> <xsl:value-of select="$y-legend-offset - 10"/> <xsl:text> Z</xsl:text> </xsl:attribute> </path> </xsl:template> </xsl:stylesheet> //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// / theResult.svg //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// / <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE svg SYSTEM "svg-19991203.dtd"> <svg height="300" width="400"> <text y="20" x="120" style="font-size:18; text-anchor:middle">3Q 2000 Sales Figures</text> <text x="120" y="33" style="font-size:12; text-anchor:middle">(in millions of dollars)</text> <g style="stroke-width:2; stroke:black"> <path d="M 40 220 L 40 30 L 40 220 L 200 220 Z"/> </g> <g style="fill:none; stroke:#B0B0B0; stroke-width:1; stroke-dasharray:2 4"> <path d="M 42 200 L 198 200 Z"/> <path d="M 42 180 L 198 180 Z"/> <path d="M 42 160 L 198 160 Z"/> <path d="M 42 140 L 198 140 Z"/> <path d="M 42 120 L 198 120 Z"/> <path d="M 42 100 L 198 100 Z"/> <path d="M 42 80 L 198 80 Z"/> <path d="M 42 60 L 198 60 Z"/> <path d="M 42 40 L 198 40 Z"/> </g> <g style="text-anchor:end; font-size:9"> <text y="203" x="36">20</text> <text y="183" x="36">40</text> <text y="163" x="36">60</text> <text y="143" x="36">80</text> <text y="123" x="36">100</text> <text y="103" x="36">120</text> <text y="83" x="36">140</text> <text y="63" x="36">160</text> <text y="43" x="36">$180</text> </g> <path style="stroke-width:2; stroke:black; fill:green" d="M 20 220 L 20 75.80000000000001 L 40 75.80000000000001 L 40 220 Z"/> <text style="font-size:10; text-anchor:middle" x="30" y="70.80000000000001">144.2</text> <text x="240" style="font-size:14; text-anchor:start" y="60">Southeast</text> <path style="stroke:black; stroke-width:2; fill:green" d="M 220 50 L 220 60 L 230 60 L 230 50 Z"/> <path style="stroke-width:2; stroke:black; fill:green" d="M 20 220 L 20 116.2 L 40 116.2 L 40 220 Z"/> <text style="font-size:10; text-anchor:middle" x="30" y="111.2">103.8</text> <text x="240" style="font-size:14; text-anchor:start" y="60">Northeast</text> <path style="stroke:black; stroke-width:2; fill:green" d="M 220 50 L 220 60 L 230 60 L 230 50 Z"/> <path style="stroke-width:2; stroke:black; fill:green" d="M 20 220 L 20 133.7 L 40 133.7 L 40 220 Z"/> <text style="font-size:10; text-anchor:middle" x="30" y="128.7">86.30000000000001</text> <text x="240" style="font-size:14; text-anchor:start" y="60">Southwest</text> <path style="stroke:black; stroke-width:2; fill:green" d="M 220 50 L 220 60 L 230 60 L 230 50 Z"/> <path style="stroke-width:2; stroke:black; fill:green" d="M 20 220 L 20 171.1 L 40 171.1 L 40 220 Z"/> <text style="font-size:10; text-anchor:middle" x="30" y="166.1">48.9</text> <text x="240" style="font-size:14; text-anchor:start" y="60">Midwest</text> <path style="stroke:black; stroke-width:2; fill:green" d="M 220 50 L 220 60 L 230 60 L 230 50 Z"/> <path style="stroke-width:2; stroke:black; fill:green" d="M 20 220 L 20 198.6 L 40 198.6 L 40 220 Z"/> <text style="font-size:10; text-anchor:middle" x="30" y="193.6">21.400000000000002</text> <text x="240" style="font-size:14; text-anchor:start" y="60">Northwest</text> <path style="stroke:black; stroke-width:2; fill:green" d="M 220 50 L 220 60 L 230 60 L 230 50 Z"/> </svg>
Received on Monday, 16 July 2001 11:28:38 UTC