【问题标题】:How to turn an XML file into SVG using XSL?如何使用 XSL 将 XML 文件转换为 SVG?
【发布时间】:2011-11-08 20:26:28
【问题描述】:

给定

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

如何将这些数据制作成简单的 SVG 条形图? (没什么花哨的,只是以某种方式表示数字之间的关系的四个条形)

类似这样的: (我知道这两个项目之间没有分隔,但可以说我会让它们变成不同的颜色,前两个条是蓝色的,第二个是红色的)

我想我不确定 xsl:template 中的语法是什么来生成 SVG 代码?最佳答案被接受!

【问题讨论】:

  • 请提供所需输出的示例,除非您正在寻找既了解 SVG 又了解 XSLT 的人,这可能只是一个足够狭窄的领域来祝您好运。 ;)
  • 这个网站可能是一个不错的起点:carto.net/svg/samples/xslt
  • @antonpug:“示例输出”是指实际的 SVG 代码,而不是图像。
  • 您的问题是什么:决定 SVG 应该是什么样子,或者从您的 XML 输入生成 SVG?换句话说,您问的是 SVG 问题还是 XSLT 问题?
  • 嗯,我不知道如何使用 XSL 生成 SVG 代码,比如如何设置模板

标签: xml xslt svg


【解决方案1】:

这是一个带有更多花里胡哨的示例:

  • 它会自动缩放到最大高度
  • 它使用 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>

这样渲染

在我的机器上。

【讨论】:

  • @antonpug:不客气。一些 SVG 代码开始会很好,因为我非常了解 XSLT,但我对 SVG 几乎一无所知。
  • 比我的建议好多了,赞。
  • @3martini 如果没有您的解决方案,这将不复存在。
【解决方案2】:

SVG 只是一种特殊的 xml,请查看 http://www.w3.org/TR/SVG/intro.html 的参考

您从&lt;svg&gt; 标记开始并开始嵌套。

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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-01
    • 2013-09-06
    • 1970-01-01
    • 2013-06-23
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 2011-02-19
    相关资源
    最近更新 更多