2011-11-08 22 views
9

Dado¿Cómo convertir un archivo XML en SVG usando XSL?

<root> 
    <item> 
     <detail>100</detail> 
     <detail>200</detail> 
    </item> 
    <item> 
     <detail>50</detail> 
     <detail>100</detail> 
    </item> 
</root> 

Cómo me puedo hacer estos datos en un gráfico de barras simple SVG? (Nada especial, sólo cuatro barras que representan la relación entre los números de alguna manera)

Algo como esto: enter image description here (sé que no hay separación entre los dos elementos, pero digamos que yo les haga diferentes colores, las primeras dos barras azules la segunda roja)

Supongo que no estoy seguro de cuál sería la sintaxis dentro de la plantilla xsl: para generar el código SVG? La mejor respuesta es aceptada!

+0

Proporcione un ejemplo de la salida deseada, a menos que esté buscando personas que conozcan SVG y XSLT, que podrían ser lo suficientemente angostas como para desearles buena suerte. ;) – Tomalak

+0

Este sitio puede ser un buen lugar para comenzar: http://www.carto.net/svg/samples/xslt/ – david

+0

@antonpug: con "salida de ejemplo" quise decir el código SVG real, no una imagen. – Tomalak

Respuesta

12

Aquí se muestra un ejemplo con algunos más campanas & silbatos:

  • se ajusta automáticamente a la altura máxima
  • que utiliza CSS para el estilo elementos
  • tiene parámetros configurables para ancho y espaciado de las barras
  • que utiliza XSLT más idiomática que un montón de anidado para-cada bucles

Con su entrada de este código:

<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 &gt; .)][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> 

produce

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

que hace como esto

SVG rendering result

en mi máquina.

+0

¡Muchas gracias! Gran ayuda – antonpug

+0

@antonpug: De nada. Algún código SVG para empezar hubiera sido bueno porque conozco XSLT bastante bien, pero no sabía casi nada sobre SVG. – Tomalak

+0

Mucho mejor que mi sugerencia, felicitaciones. – 3martini

6

SVG es sólo un tipo especial de XML, compruebe la referencia al http://www.w3.org/TR/SVG/intro.html

Se empieza con la etiqueta <svg> y empiezan a anidar.

XSL es un mundo completamente diferente. Usé un ejemplo de referencia en http://www.carto.net/svg/samples/xslt/#basic y lo modifiqué para que funcione con tu xml para demostrar cómo usar xsl para tus datos anidados. Básicamente, acabo de agregar un ciclo interno para cada uno.

Aquí es un ejemplo punto de partida:

<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> 
Cuestiones relacionadas