Reputation: 1060
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
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
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
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