Как превратить файл XML в SVG с помощью XSL? - PullRequest
9 голосов
/ 09 ноября 2011

Учитывая

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

Как мне сделать эти данные в простой гистограмме SVG?(ничего особенного, просто четыре столбца, представляющие какое-то отношение между числами)

Примерно так: enter image description here (Я знаю, что между этими двумя пунктами нет разделения, но позвольте мне сказать, что я сделаю их разнымицвета, первые два столбца - синий, второй - красный)

Наверное, я не уверен, какой будет синтаксис внутри шаблона xsl: для генерации кода SVG?Лучший ответ принят!

Ответы [ 2 ]

13 голосов
/ 09 ноября 2011

Вот пример с еще несколькими прибамбасами:

  • автоматически масштабируется до максимальной высоты
  • он использует CSS для оформления элементов
  • имеет настраиваемые параметры для ширины и расстояния между стержнями
  • он использует больше идиоматического XSLT, чем просто набор вложенных циклов for-each

С вашим вводом этого кода:

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

производит

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

который выглядит так

SVG rendering result

на моей машине.

6 голосов
/ 09 ноября 2011

SVG - это просто особый вид XML, проверьте ссылку на http://www.w3.org/TR/SVG/intro.html

Вы начинаете с тега <svg> и начинаете вложение.

XSL - это совершенно другой мир.Я использовал справочный пример на http://www.carto.net/svg/samples/xslt/#basic и изменил его для работы с вашим xml, чтобы продемонстрировать, как использовать xsl для ваших вложенных данных.По сути, я просто добавил внутренний цикл for-each.

Вот пример начальной точки:

<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...