0

I have xml file like:

<SWIAT>
<KRAINA_GEOG TYP="Pobrzeze">
    <NAZWA>Południowobałtyckie</NAZWA>
    <POWIERZCHNIA>19000</POWIERZCHNIA>
    <OPADY_MIN>400</OPADY_MIN>
    <OPADY_MAX>800</OPADY_MAX>
</KRAINA_GEOG>
<KRAINA_GEOG TYP="Nizina">
    <NAZWA>Środkowoeuropejska</NAZWA>
    <POWIERZCHNIA>540000</POWIERZCHNIA>
    <OPADY_MIN>400</OPADY_MIN>
    <OPADY_MAX>750</OPADY_MAX>
    <KRAINA_GEOG TYP="Nizina">
        <NAZWA>Holenderska</NAZWA>
        <POWIERZCHNIA>24915</POWIERZCHNIA>
        <OPADY_MIN>550</OPADY_MIN>
        <OPADY_MAX>700</OPADY_MAX>
    </KRAINA_GEOG>
    <KRAINA_GEOG TYP="Nizina">
        <NAZWA>Południowowielkopolska</NAZWA>
        <POWIERZCHNIA>17000</POWIERZCHNIA>
        <OPADY_MIN>500</OPADY_MIN>
        <OPADY_MAX>650</OPADY_MAX>
        <KRAINA_GEOG TYP="Kotlina">
            <NAZWA>Szczercowska</NAZWA>
            <POWIERZCHNIA>1203</POWIERZCHNIA>
            <OPADY_MIN>500</OPADY_MIN>
            <OPADY_MAX>600</OPADY_MAX>
        </KRAINA_GEOG>
        <KRAINA_GEOG TYP="Rownina">
            <NAZWA>Rychwalska</NAZWA>
            <POWIERZCHNIA>1186</POWIERZCHNIA>
        </KRAINA_GEOG>
    </KRAINA_GEOG>
</KRAINA_GEOG>

And I want to make SVG bar chart with values from <POWIERZCHNIA>. How to do this? I want to use it in Exist- db. Any ideas? Thanks for help.

helderdarocha
  • 23,209
  • 4
  • 50
  • 65

1 Answers1

0

You can generate SVG using XSLT, although you might find some chart library that might not require that you learn XSLT. With XSLT you select the nodes you want using XPath, and can manipulate them any way you like. You can even generate it dynamically on-the-fly in browsers (there are version limitations, though).

I wrote a tutorial about SVG chart generation using XSLT 1.0. Unfortunately it's in Portuguese and I never had the time to translate it. But I adapted your source XML and wrote a small XSLT stylesheet that will generate a simple SVG bar chart with the numbers in all POWIERZCHNIA field (not considering the nesting).

I defined some variables with fixed values for the dimensions. The $max-powierzchnia variable selects the largest value which will be used to calculate the length of the bar using the value in POWIERZCHNIA * $max-bar-length / $max-powierzchnia. The SWIAT XSL template defines the root elements of the SVG, then sorts in (by descending order of POWIERZCHNIA) and processes all the KRAINA_GEOG nodes, which are transformed in the KRAINA_GEOG template.

This is the stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
    version="1.0">

    <xsl:output indent="yes"/>

    <xsl:variable name="svg-width" select="1200" />
    <xsl:variable name="svg-height" select="900" />
    <xsl:variable name="max-bar-length" select="$svg-width - 400" />

    <xsl:variable name="bar-height" select="20" />
    <xsl:variable name="bar-spacing" select="10" />
    <xsl:variable name="bar-start" select="200" />

    <xsl:variable name="max-powierzchnia" select="//POWIERZCHNIA[not(. &lt; //POWIERZCHNIA)]" />

    <xsl:template match="SWIAT">
        <svg viewBox="0 0 {$svg-width} {$svg-height}" width="{$svg-width}px" height="{$svg-height}px">
            <g id="bar-chart" font-size="16" transform="translate(20,100)">
                <xsl:apply-templates select="//KRAINA_GEOG">
                    <xsl:sort order="descending" select="POWIERZCHNIA" />
                </xsl:apply-templates>
            </g>
        </svg>
    </xsl:template>

    <xsl:template match="KRAINA_GEOG">
        <xsl:variable name="bar-width" select="POWIERZCHNIA * $max-bar-length div $max-powierzchnia" />
        <g id="bar_{position()}" 
            transform="translate(0, {(position() - 1) * ($bar-height + $bar-spacing)})">
            <text x="0" y="{($bar-height + $bar-spacing) div 2}"><xsl:number format="1. " value="position()"/>
                <xsl:value-of select="NAZWA"/></text>
            <rect x="{$bar-start}" y="0" width="{$bar-width}" height="{$bar-height}" fill="lightgray"/>
            <text x="{$bar-width + $bar-start + 5}" y="{($bar-height + $bar-spacing) div 2}"><xsl:value-of select="POWIERZCHNIA"/></text>
        </g>
    </xsl:template>

</xsl:stylesheet>

And this is the resulting SVG you get when you run your source XML + this XSL stylesheet through a XSLT processor: http://codepen.io/helderdarocha/pen/iJrFb

You might also try generating it on the fly, saving the XSLT stylesheet above in a file (svg-graph.xsl), adding a <?xml-stylesheet processing instruction to your XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="svg-graph.xsl"?>
<SWIAT>
    <KRAINA_GEOG TYP="Pobrzeze">
        <NAZWA>Południowobałtyckie</NAZWA>
        <POWIERZCHNIA>19000</POWIERZCHNIA>
...

And loading it in a browser such as FireFox.

helderdarocha
  • 23,209
  • 4
  • 50
  • 65
  • I have also a second question to this XML. I want to make bar chart with 4 bars and its values in brackets: KOTLINA(1), NIZINA(3) POBRZEZE(1), ROWNINA(1). But their values may change, because I want to make filter to choose for example NIZINA with POWIERZCHNIA less than: "some value". Could You help me? – user3383347 Mar 05 '14 at 16:53
  • And also to generate this svg I must use xquery function. – user3383347 Mar 05 '14 at 17:04
  • You can select any node you want in a XML file using XPath. You can navigate up and down the XML tree, and it has functions and operators to convert, format and perform operations. XPath is for *locating* and *extracting* data. It's used in XSLT, which can generate a new document. Search for a XPath tutorial. There are plenty of them around. You can also test if you are locating the right nodes using a XPath tester. There are some online, like this one: http://www.xpathtester.com/xpath – helderdarocha Mar 05 '14 at 17:04
  • If you need a solution in XQuery, I suggest you present your second question explaining what you need to do, and tag it with `xquery`. – helderdarocha Mar 05 '14 at 17:07
  • @user3383347 Actually in eXist-db you can execute an XSLT directly from XQuery by using the `transform:transform#3` extension function. See http://www.exist-db.org/exist/apps/fundocs/view.html?uri=http://exist-db.org/xquery/transform&location=java:org.exist.xquery.functions.transform.TransformModule – adamretter Mar 06 '14 at 00:10