2011-11-08 24 views
9

ChoLàm thế nào để biến một tệp XML thành SVG bằng XSL?

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

Làm cách nào để làm cho dữ liệu này thành biểu đồ thanh SVG đơn giản? (Không có gì lạ mắt, chỉ cần bốn thanh đại diện cho mối quan hệ giữa các số trong một số thời trang)

Something như thế này: enter image description here (Tôi biết không có sự tách biệt giữa hai mặt hàng, nhưng cho phép chỉ nói rằng tôi sẽ làm cho họ màu sắc khác nhau, hai thanh đầu tiên màu xanh đỏ thứ hai)

Tôi đoán tôi không chắc cú pháp bên trong xsl: template sẽ là gì để tạo mã SVG? Câu trả lời hay nhất được chấp nhận!

+0

Vui lòng cung cấp ví dụ về đầu ra mong muốn, trừ khi bạn đang tìm kiếm những người biết cả SVG và XSLT, có thể chỉ đủ hẹp để thích bạn chúc may mắn. ;) – Tomalak

+0

Trang web này có thể là một nơi tốt để bắt đầu: http://www.carto.net/svg/samples/xslt/ – david

+0

@antonpug: Với "đầu ra ví dụ", tôi có nghĩa là mã SVG thực tế chứ không phải hình ảnh. – Tomalak

Trả lời

12

Dưới đây là một ví dụ với một số chuông hơn & còi:

  • nó tự động quy mô với chiều cao tối đa
  • nó sử dụng CSS để phong cách các yếu tố
  • nó có thông số có thể định cấu hình cho chiều rộng và khoảng cách của các thanh
  • nó sử dụng XSLT ngữ nhiều hơn chỉ là một loạt các lồng for-each vòng

Với đầu vào của bạn mã này:

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

sản xuất

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

mà ám như

này

SVG rendering result

trên máy của tôi.

+0

Cảm ơn rất nhiều! Trợ giúp tuyệt vời – antonpug

+0

@antonpug: Bạn được chào đón. Một số mã SVG để bắt đầu với sẽ được tốt đẹp bởi vì tôi biết XSLT khá tốt, nhưng tôi đã biết bên cạnh không có gì về SVG. – Tomalak

+0

Tốt hơn nhiều so với đề nghị của tôi, kudo. – 3martini

6

SVG chỉ là một loại đặc biệt của xml, kiểm tra các tài liệu tham khảo tại http://www.w3.org/TR/SVG/intro.html

Bạn bắt đầu với thẻ <svg> và bắt đầu làm tổ.

XSL là một thế giới hoàn toàn khác. Tôi đã sử dụng một ví dụ tham chiếu tại http://www.carto.net/svg/samples/xslt/#basic và sửa đổi nó để làm việc với xml của bạn để chứng minh cách sử dụng xsl cho dữ liệu lồng nhau của bạn. Về cơ bản, tôi chỉ cần thêm một vòng lặp cho mỗi vòng lặp.

Dưới đây là một ví dụ điểm bắt đầu:

<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> 
Các vấn đề liên quan