Как превратить XML-файл в SVG с помощью XSL?
дано
<root>
<item>
<detail>100</detail>
<detail>200</detail>
</item>
<item>
<detail>50</detail>
<detail>100</detail>
</item>
</root>
Как я мог бы сделать эти данные в простую гистограмму SVG? (ничего необычного, просто четыре бара, представляющие отношение между числами в некотором роде)
что-то вроде этого: (Я знаю, что нет разделения между двумя элементами, но давайте просто скажем, что я сделаю их разными цветами, первые два бара синими, а второй красный)
Я думаю, я не уверен, что синтаксис внутри шаблона xsl:будет генерировать SVG код? Лучший ответ принимается!
2 ответов
вот пример с еще несколькими колокольчиками и свистками:
- она автоматически масштабируется до максимальной высоты
- он использует CSS для элементов стиля
- он имеет настраиваемые параметры для ширины и расстояния между барами
- он использует более идиоматический XSLT, чем просто кучу вложенных для каждого цикла
С вашим вводом этот код:
<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 > .)][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 - это просто особый вид xml, проверьте ссылку наhttp://www.w3.org/TR/SVG/intro.html
вы начинаете с <svg>
tag и начать вложенность.
xsl-это совершенно другой мир. Я использовал ссылочный пример вhttp://www.carto.net/svg/samples/xslt/#basic и изменил его для работы с xml, чтобы продемонстрировать, как использовать xsl для вложенных данных. В принципе, я просто добавил внутренний цикл для каждого цикла.
здесь пример начальной точки:
<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>