使用XSL将具有2个或更多值的XML属性转换为SVG x/y坐标

使用XSL将具有2个或更多值的XML属性转换为SVG x/y坐标,xml,xslt,svg,Xml,Xslt,Svg,我需要通过xsl将xml属性中的值转换为svg rect pos x和y 因此需要从 例子 <item value="20 10 40" /> <item value="200 0 100" /> <item value="2666 10 40 95" /> 因此,在XSLT 1.0中寻找更干净的、可能是递归的、可以接受字符串中任意数量的数字并解析所有的值。从分隔列表中提取值是一件棘手的事情,因为它没有标记化()函数 如果列表中的值数量较少(如示例中所示),

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

因此需要从

例子

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

因此,在XSLT 1.0中寻找更干净的、可能是递归的、可以接受字符串中任意数量的数字并解析所有的值。

从分隔列表中提取值是一件棘手的事情,因为它没有
标记化()
函数

如果列表中的值数量较少(如示例中所示),则可以使用嵌套的
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>


演示:

这里是一个使用EXSLT扩展的示例,在线,代码是

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

2010
2000
266610
应该清楚如何按位置访问其他令牌,当然,您也可以为每个令牌
应用模板
超过
$tokens


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

您是说要从3个
项目
映射到1个
rect
?1
项目
到1
rect
?到底是怎么回事?您还没有清楚地解释您想做什么,我们可以提供帮助。您好,我正在寻找一个灵活的解决方案,这样我就可以在value属性中解析任意两个由空格分隔的数字(如从左到右的第一个和第三个数字)并通过xsl将它们放入rect中的两个单独的x和y变量中。请说明是使用XSLT 1.0还是2.0。正在寻找一个干净的解决方案,可以在chrome或firefox等现代浏览器中加载xml(并应用xsl样式表),所以我认为是1.0,正如我所读到的,浏览器不支持2.0。如果您需要对大量输入数据执行此操作,那么我的第一个建议是更改XML格式,将任何单个值放在单个元素中。如果你不能做到这一点,那么就看看XSLT实现是在哪里提供的。谢谢Michael,你是否介意修改代码以使用XML,使其更清晰,并指出如果我只想呈现特定的值,如何专门针对每个值?@Onetyper查看我答案中的补充内容。
<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>
<?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>