拆分属性字符并使用XSLT 1.0输出它们

时间:2013-02-22 10:54:05

标签: xslt

我需要根据给定的分隔符属性使用XSLT 1.0转换下面的编码。应根据给定的分隔符分隔文本:

输入:

<chapter xmlns="http://www.w3.org/1998/Math/MathML">
<math display="inline"><mfenced separators=", : . ;"><mn>1</mn><mtext>b</mtext><mo>%</mo><mi>d</mi><mi>e</mi></mfenced></math>
<math display="inline"><mfenced separators=", ;"><mi>a</mi><mi>b</mi><mi>c</mi><mi>d</mi><mi>e</mi></mfenced></math>
<math display="inline"><mfenced separators=", : . ; ; : . ;"><mi>a</mi><mi>b</mi><mi>c</mi><mi>d</mi><mi>e</mi></mfenced></math>
</chapter>

需要输出:

1,b:%.d;e
a,b;c;d;e
a,b:c.d;e

另请注意,如果分隔符太多,则会忽略额外的分隔符。如果给出分隔符,但是太少,则根据需要重复最后一个

仅当分隔符字符小于子元素时才能获取输出。

XSLT 1.0尝试:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://www.w3.org/1998/Math/MathML">

<xsl:template match="m:mfenced">
<xsl:variable name="text" select="@separators"/>
<xsl:for-each select="child::*">
<xsl:apply-templates/>
<xsl:choose>
<xsl:when test="contains($text,' ')">
<xsl:variable name="attr" select="string-length(translate($text, ' ', ''))"/>
<xsl:variable name="ch" select="count(parent::*/child::*)-1"/>
<xsl:if test="$ch=$attr"><xsl:value-of select="substring($text,count(preceding-sibling::*)+position(),1)"/></xsl:if>

<xsl:if test="$ch gt $attr">
<xsl:if test="not(substring($text,count(preceding-sibling::*)+position(),1)='')"><xsl:value-of select="substring($text,count(preceding-sibling::*)+position(),1)"/></xsl:if>
<xsl:if test="(substring($text,count(preceding-sibling::*)+position(),1)='')"><xsl:value-of select="substring($text,count(preceding-sibling::*)+1,1)"/></xsl:if>
</xsl:if>

<xsl:if test="$ch lt $attr and count(following-sibling::*)>0"><xsl:value-of select="substring($text,count(preceding-sibling::*)+position(),1)"/></xsl:if>
</xsl:when>
<xsl:otherwise><xsl:if test="count(following-sibling::*)>0"><xsl:value-of select="$text"/></xsl:if></xsl:otherwise></xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:3)

以下解决方案基于获得每个&lt; m:mi&gt;的位置。在&lt; m:fenced&gt;内获取下一个要输出的运算符的元素。

请注意。我假设用于表示每个运算符的字符串长度为1。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://www.w3.org/1998/Math/MathML">

    <xsl:output method="text" />

    <!-- Ignore all text nodes (just for demo) -->
    <xsl:template match="text()" />

    <xsl:template match="m:mfenced">
        <!-- Print children values and operators -->
        <xsl:apply-templates select="*" mode="list-op">
            <xsl:with-param name="separator-str" select="@separators" />
            <xsl:with-param name="separator-len" select="string-length(@separators)" />
        </xsl:apply-templates>
        <!-- Print new line -->
        <xsl:text>&#xA;</xsl:text>
    </xsl:template>

    <!-- Last m:mi elements for each m:mfenced are just printed -->
    <xsl:template match="*[last()]" mode="list-op">
        <xsl:value-of select="."/>
    </xsl:template>

    <!-- In this template we use the position() function to calculate the next
         operator that is going to be outputted -->
    <xsl:template match="*" mode="list-op">
        <xsl:param name="separator-str" />
        <!-- This parameter is not required, but allows us to cache
             the length of the separators string instead of calculating it
             for each m:mi element -->
        <xsl:param name="separator-len" />

        <!-- Print current value -->
        <xsl:value-of select="." />

        <!-- Calculate the separator position within the string -->
        <xsl:variable name="string-position" select="2*position() - 1" />

        <!-- Check if the position oveflows the position in the array, and
             if it does, print the last separator in the string. -->
        <xsl:choose>
            <xsl:when test="$separator-len >= $string-position">
                <xsl:value-of select="substring($separator-str, $string-position, 1)" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="substring($separator-str, $separator-len)" />
            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>
</xsl:stylesheet>