2011-11-08 21 views
9

BiorącJak zmienić plik XML w SVG przy użyciu XSL?

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

Jak ja robię te dane w prosty wykres słupkowy SVG? (Nic nadzwyczajnego, po prostu cztery bary reprezentujące zależność pomiędzy numerami w jakiś sposób)

coś takiego: enter image description here (wiem, nie ma rozdziału między tymi dwoma rzeczami, ale pozwala tylko powiedzieć, abym im różne kolory, pierwsze dwa paski niebieskie drugie czerwone)

Chyba nie jestem pewien, jaka jest składnia wewnątrz xsl: template, aby wygenerować kod SVG? Najlepsza odpowiedź zostaje zaakceptowana!

+0

Podaj przykład pożądanego wyniku, chyba że szukasz osób, które znają zarówno SVG, jak i XSLT, które mogą być na tyle wąskie, aby życzyć powodzenia. ;) – Tomalak

+0

Ta strona może być dobrym miejscem do rozpoczęcia: http://www.carto.net/svg/samples/xslt/ – david

+0

@antonpug: Z "przykładowym wyjściem" rozumiałem rzeczywisty kod SVG, a nie obraz. – Tomalak

Odpowiedz

12

Oto przykład z jakichś bardziej dzwony & gwizdków:

  • skaluje się automatycznie do maksymalnej wysokości
  • to używa CSS do stylu elementy
  • ma konfigurowalne parametry szerokości i odstępu między kreskami
  • używa więcej idiomatyczne XSLT niż tylko kilka zagnieżdżonych for-each pętle

Dzięki swoim wejściu ten kod:

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

produkuje

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

który renderuje jak ten

SVG rendering result

na moim komputerze.

+0

Dziękuję bardzo! Wielka pomoc – antonpug

+0

@antonpug: Nie ma za co. Jakiś kod SVG na początku byłby fajny, ponieważ znam XSLT całkiem dobrze, ale nie wiedziałem prawie nic o SVG. – Tomalak

+0

Znacznie lepiej niż moja sugestia, kudos. – 3martini

6

SVG jest tylko szczególnym rodzajem xml, sprawdź odniesienie w http://www.w3.org/TR/SVG/intro.html

Zaczynasz z tagiem <svg> i rozpocząć gniazdowania.

XSL to zupełnie inny świat. Użyłem przykładu referencyjnego pod numerem http://www.carto.net/svg/samples/xslt/#basic i zmodyfikowałem go, aby działał z twoim xml, aby zademonstrować, jak używać xsl do danych zagnieżdżonych. Zasadniczo właśnie dodałem wewnętrzną pętlę.

Oto przykład punkt wyjścia:

<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> 
Powiązane problemy