Sneharghya Pathak
Sneharghya Pathak

Reputation: 1060

Optimize XSLT code by eliminating repeating code

This XSLT transformation works, but I am repeating the same code multiple times, which makes it very redundant!

How can I optimize this?

<xsl:for-each select="RVWT">
    <xsl:variable name="rvwt" select="tokenize(., '\|')"/>
    <TextTypeCode>08</TextTypeCode>
    <Text textformat="05">
        <xsl:value-of select="$rvwt[1]"/>
    </Text>
    <TextSourceTitle>
        <xsl:value-of select="normalize-space(substring($rvwt[2], 3))"/>
    </TextSourceTitle>
</xsl:for-each>
<xsl:if test="not(RVWT)">
    <xsl:for-each select="RVW">
        <xsl:variable name="rvwt" select="tokenize(., '\|')"/>
        <TextTypeCode>08</TextTypeCode>
        <Text textformat="05">
            <xsl:value-of select="$rvwt[1]"/>
        </Text>
        <TextSourceTitle>
            <xsl:value-of select="normalize-space(substring($rvwt[2], 3))"/>
        </TextSourceTitle>
    </xsl:for-each>
</xsl:if>

Thanks!

Upvotes: 0

Views: 106

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

I. I would use the best that XSLT 2.0 can offer: creating a function:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 
  <xsl:template match="/*">
     <xsl:sequence select=
      "my:Extract(RVW[not(../RVWT)] | RVWT)"/>
  </xsl:template>

  <xsl:function name="my:Extract">
    <xsl:param name="pItems" as="item()+"/>
    <xsl:for-each select="$pItems">
        <xsl:variable name="vItemTokens" select="tokenize(., '\|')"/>
        <TextTypeCode>08</TextTypeCode>
        <Text textformat="05">
            <xsl:value-of select="$vItemTokens[1]"/>
        </Text>
        <TextSourceTitle>
            <xsl:value-of select="normalize-space(substring($vItemTokens[2], 3))"/>
        </TextSourceTitle>
    </xsl:for-each>
  </xsl:function>
</xsl:stylesheet>

when this transformation is applied on the following XML document:

<t>
    <RVWT>a|bbbTail|c</RVWT>
    <RVWT>d|eeeTail|f</RVWT>
    <RVWT>g|hhhTail|i</RVWT>
    
    <RVW>p|qqqTail|r</RVW>
</t>

the wanted, correct result is produced:

<TextTypeCode>08</TextTypeCode>
<Text textformat="05">a</Text>
<TextSourceTitle>bTail</TextSourceTitle>
<TextTypeCode>08</TextTypeCode>
<Text textformat="05">d</Text>
<TextSourceTitle>eTail</TextSourceTitle>
<TextTypeCode>08</TextTypeCode>
<Text textformat="05">g</Text>
<TextSourceTitle>hTail</TextSourceTitle>

when applied on this document:

<t>
    <RVWTX>a|bbbTail|c</RVWTX>
    <RVWTX>d|eeeTail|f</RVWTX>
    <RVWTX>g|hhhTail|i</RVWTX>
    
    <RVW>p|qqqTail|r</RVW>
</t>

again the wanted, correct result is produced:

<TextTypeCode>08</TextTypeCode>
<Text textformat="05">p</Text>
<TextSourceTitle>qTail</TextSourceTitle>

II. Do note:

With this approach we have the added benefit that the function accepts any sequence of items, not only elements.

For example, one could call the function like this:

my:Extract(('a|bbbTail|c', 'd|eeeTail|f'))

and still get the wanted result:

<TextTypeCode>08</TextTypeCode>
<Text textformat="05">a</Text>
<TextSourceTitle>bTail</TextSourceTitle>
<TextTypeCode>08</TextTypeCode>
<Text textformat="05">d</Text>
<TextSourceTitle>eTail</TextSourceTitle>

Upvotes: 4

michael.hor257k
michael.hor257k

Reputation: 116959

I am guessing you could do:

<xsl:for-each select="RVWT | RVW[not(../RVWT)]">
    <xsl:variable name="rvwt" select="tokenize(., '\|')"/>
    <TextTypeCode>08</TextTypeCode>
    <Text textformat="05">
        <xsl:value-of select="$rvwt[1]"/>
    </Text>
    <TextSourceTitle>
        <xsl:value-of select="normalize-space(substring($rvwt[2], 3))"/>
    </TextSourceTitle>
</xsl:for-each>

Upvotes: 3

Martin Honnen
Martin Honnen

Reputation: 167426

You can write a template

<xsl:template match="RVWT | RVW">
    <xsl:variable name="rvwt" select="tokenize(., '\|')"/>
    <TextTypeCode>08</TextTypeCode>
    <Text textformat="05">
        <xsl:value-of select="$rvwt[1]"/>
    </Text>
    <TextSourceTitle>
        <xsl:value-of select="normalize-space(substring($rvwt[2], 3))"/>
    </TextSourceTitle>
</xsl:template>

and then in the parent you process <xsl:apply-templates select="if (RVWT) then RVWT else RVW"/>.

Upvotes: 3

Related Questions