Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
518 views
in Technique[技术] by (71.8m points)

xslt - Turn XML attribute with 2 or more values into SVG x/y coordinates using XSL

I need to turn the values in a xml attribute through xsl into a svg rect pos x and y

Therefore need to parse from

Examples

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

parse each item value attribute following some rules (that's the part I'm not sure about, how to extract the numbers into separate variables)

like

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

Extract X (20) in var1 and Y (40) in var2

into

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

(if I want the first and third value in this case)

Basically I need to understand how to parse any TWO of a series of multiple values contained within the attribute VALUE and pass them into the rect vars as var1 and var2 separately.

From my research so far, I have found out 2 methods but not sure how to apply in this case, either substring-before and after or tokenize, please note this needs to work loaded directly in a browser.

Edit1

I have found an ugly solution so far to extract the data for a case of 3 numbers

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, ' '), ' ')"/>

Result

Value 1    20
Value 2    10
Value 3    40

So looking for something cleaner, perhaps recursive that accept any amount of numbers in the string and parse all.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Extracting values from a delimited list in XSLT 1.0 is awkward, since it has no tokenize() function.

If the number of values in the list is small (like in your example), you can use nested substring-before() and substring-after() calls, as shown (now) in your question.

A more generic solution, which is also more suitable to handle larger lists, would use a recursive named template, for example:

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

Example of call:

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

Demo:http://xsltransform.net/ncdD7mh


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...