siva2012
siva2012

Reputation: 459

Split attribute characters and output them using XSLT 1.0

I am in need to transform the below coding using XSLT 1.0 based on the separators attributes given. The text should be separated based on the separators given:

Input:

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

output required:

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

Also please note that if there are too many separator characters, the extra ones are ignored. If separator characters are given, but there are too few, the last one is repeated as necessary

I could not able to get the output only if the separator characters are lesser than the child elements.

XSLT 1.0 tried:

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

Upvotes: 1

Views: 504

Answers (1)

Pablo Pozo
Pablo Pozo

Reputation: 1920

The following solution is based on obtaining the position of each <m:mi> within the <m:fenced> elements to obtain the next operator to be outputted.

Note. I am assuming that the string length used to represent each operator is 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>

Upvotes: 3

Related Questions