使用XSL

时间:2015-11-21 01:02:57

标签: xml xslt svg

我需要将xml属性中的值通过xsl转换为svg rect pos x和y

因此需要从

解析

实施例

<item value="20 10 40" />
<item value="200 0 100" />
<item value="2666 10 40 95" />

按照一些规则解析每个项目值属性(“我不确定的部分,如何将数字提取到单独的变量中”)

 <item value="20 10 40" />
              X  Z  Y

在var1中提取X(20),在var2中提取Y(40)

<rect x="{$var1}" y="{$var2}" />

(如果我想在这种情况下使用第一个和第三个值)

基本上我需要了解如何解析属性VALUE中包含的一系列多个值中的任何两个值,并将它们分别作为var1和var2传递到rect变量中。

从我目前的研究中,我发现了2种方法但不确定如何应用这种情况,无论是子串 - 前后还是令牌化,请注意这需要直接在浏览器中加载。

EDIT1

到目前为止,我找到了一个丑陋的解决方案来提取3个数字

的数据

XML

<item value="20 10 40" />

XSL

Value 1    <xsl:value-of select="substring-before (@value, ' ')"/>
Value 2    <xsl:value-of select="substring-before(substring-after (@value, ' '), ' ')"/>
Value 3    <xsl:value-of select="substring-after(substring-after (@value, ' '), ' ')"/>

结果

Value 1    20
Value 2    10
Value 3    40

所以寻找更清洁的东西,也许是递归的,接受字符串中的任意数量的数字并解析所有数字。

2 个答案:

答案 0 :(得分:1)

从XSLT 1.0中的分隔列表中提取值很尴尬,因为它没有tokenize()函数。

如果列表中的值数量很小(如您的示例所示),则可以使用嵌套的substring-before()substring-after()调用,如您在问题中所示(现在)。

更通用的解决方案,也更适合处理更大的列表,将使用递归命名模板,例如:

<xsl:template name="get-Nth-value">
    <xsl:param name="list"/>
    <xsl:param name="N"/>
    <xsl:param name="delimiter" select="' '"/>
    <xsl:choose>
        <xsl:when test="$N = 1">
            <xsl:value-of select="substring-before(concat($list, $delimiter), $delimiter)"/>
        </xsl:when>
        <xsl:when test="contains($list, $delimiter) and $N > 1">
            <!-- recursive call -->
            <xsl:call-template name="get-Nth-value">
                <xsl:with-param name="list" select="substring-after($list, $delimiter)"/>
                <xsl:with-param name="N" select="$N - 1"/>
                <xsl:with-param name="delimiter" select="$delimiter"/>
            </xsl:call-template>
        </xsl:when>
    </xsl:choose>
</xsl:template>

电话示例:

<xsl:template match="item">
    <rect>
        <xsl:attribute name="x">
            <xsl:call-template name="get-Nth-value">
                <xsl:with-param name="list" select="@value"/>
                <xsl:with-param name="N" select="1"/>
            </xsl:call-template>                
        </xsl:attribute>
        <xsl:attribute name="y">
            <xsl:call-template name="get-Nth-value">
                <xsl:with-param name="list" select="@value"/>
                <xsl:with-param name="N" select="2"/>
            </xsl:call-template>                
        </xsl:attribute>
    </rect>
</xsl:template>

演示:http://xsltransform.net/ncdD7mh

答案 1 :(得分:1)

以下是使用EXSLT扩展程序的示例,在http://xsltransform.net/bnnZW2在线,代码为

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
  xmlns:exsl="http://exslt.org/common" xmlns:str="http://exslt.org/strings" exclude-result-prefixes="exsl str">

    <xsl:include href="http://exslt.org/str/functions/tokenize/str.tokenize.template.xsl"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="item">
      <xsl:copy>
        <xsl:variable name="tokens-rtf">
            <xsl:call-template name="str:tokenize">
                <xsl:with-param name="string" select="@value"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="tokens" select="exsl:node-set($tokens-rtf)/token"/>
        <x>
            <xsl:value-of select="$tokens[1]"/>
        </x> 
        <y>
            <xsl:value-of select="$tokens[2]"/>
        </y>
      </xsl:copy>

    </xsl:template>
</xsl:transform>

输入

<root>
    <item value="20 10 40" />
    <item value="200 0 100" />
    <item value="2666 10 40 95" />
</root>

输出

<root>
    <item><x>20</x><y>10</y></item>
    <item><x>200</x><y>0</y></item>
    <item><x>2666</x><y>10</y></item>
</root>

应该清楚如何根据位置访问其他令牌,当然您也可以for-eachapply-templates超过$tokens

请注意,浏览器中的XSLT处理器可能不允许您从其他域导入或包含样式表模块,因此您需要确保将引用的样式表模块(str.tokenize.template.xsl)放在您自己的服务器上并引用从那里开始。