Reputation: 1002
I have the below xml
<R N="14" MIME="application/pdf">
<RK>7</RK>
<MT N="Abstract"
V="Lorem Ipsum is simply dummy text of the printing " />
<MT N="Abstract1"
V="and typesetting industry. Lorem Ipsum has been the industry's standard "/>
<MT N="Author" V="Bernard Shaw;" />
<MT N="Author1" V="Mark Twain" />
<MT N="Abstract2"
V="dummy text ever since the 1500s, when an unknown printer took a galley"/>
<LANG>en</LANG>
</R>
When transforming with an XSLT, I need to concatenate the Abstract and Author fields, and show it like
Abstract: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley
Author: Bernard Shaw;Mark Twain
The Abstract, Abstract1, Abstract2 may appear in any order in the xml.
I am trying to use something like below, but stuck on the condition & concatenation of string when Abstract, Abstract1 doesn't appear in the same order
<xsl:template match="MT">
<xsl:if test="(some generic condition to display Title)">
<br/>
<span class="f">
<xsl:value-of select="@N"/>
</span>
</xsl:if>
<xsl:value-of select="@V"/>
</xsl:template>
Appreciate any help.
Upvotes: 1
Views: 2364
Reputation: 243449
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
Abstract: <xsl:text/>
<xsl:for-each select="*/MT[starts-with(@N, 'Abstract')]">
<xsl:value-of select="@V"/>
</xsl:for-each>
Author: <xsl:text/>
<xsl:for-each select="*/MT[starts-with(@N, 'Author')]">
<xsl:value-of select="@V"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<R N="14" MIME="application/pdf">
<RK>7</RK>
<MT N="Abstract" V="Lorem Ipsum is simply dummy text of the printing " />
<MT N="Abstract1" V="and typesetting industry. Lorem Ipsum has been the industry's standard " />
<MT N="Author" V="Bernard Shaw;" />
<MT N="Author1" V="Mark Twain" />
<MT N="Abstract2" V="dummy text ever since the 1500s, when an unknown printer took a galley" />
<LANG>en</LANG>
</R>
produces the wanted result:
Abstract: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley
Author: Bernard Shaw;Mark Twain
Further refactoring:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
Abstract: <xsl:text/>
<xsl:call-template name="concatAttributes"/>
Author: <xsl:text/>
<xsl:call-template name="concatAttributes">
<xsl:with-param name="pKeyStartString" select="'Author'"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="concatAttributes">
<xsl:param name="pKeyAttribName" select="'N'"/>
<xsl:param name="pKeyStartString" select="'Abstract'"/>
<xsl:param name="pValueAttribName" select="'V'"/>
<xsl:for-each select=
"*/MT[starts-with(@*[name()=$pKeyAttribName], $pKeyStartString)]">
<xsl:value-of select="@*[name()=$pValueAttribName]"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
A second refactoring (requested by the OP):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vAbstract">
<xsl:apply-templates mode="retrieve" select="//MT"/>
</xsl:variable>
<xsl:variable name="vAuthors">
<xsl:apply-templates mode="retrieve" select="//MT">
<xsl:with-param name="pKeyStartString" select="'Author'"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:template match="/">
Abstract: <xsl:value-of select="$vAbstract"/>
Authors:: <xsl:value-of select="$vAuthors"/>
</xsl:template>
<xsl:template match="MT" mode="retrieve">
<xsl:param name="pKeyAttribName" select="'N'"/>
<xsl:param name="pKeyStartString" select="'Abstract'"/>
<xsl:param name="pValueAttribName" select="'V'"/>
<xsl:if test="starts-with(@*[name()=$pKeyAttribName], $pKeyStartString)">
<xsl:value-of select="@*[name()=$pValueAttribName]"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
EDIT: The OP has requested that "all processing should be done within the template matching MT
". While this is possible in simple cases (see @Alejandro's answer), doing all the processing in a single template matching MT
opens big gaps of unknowns. For example, it may be required to process other MT
elements in a different way and in this case such processing will not be done at all.
In more complex cases (such as when the elements and attributes come in any order, but the output must be sorted -- Abstract1, Abstract2, ..., Abstract-N), then the sort has to be specified explicitly and this has to be outside the template matching MT
. Therefore, in the general case, it is not possible to produce the required output with code only within the template matching MT
.
I would recommend that the single template matching MT
be in a named mode and that it should be used in "pull style" -- applied explicitly by the caller.
Upvotes: 2
Reputation:
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kMtByAlphaN"
match="MT"
use="concat(generate-id(..),'+',translate(@N,'1234567890',''))"/>
<xsl:template match="MT[count(.|key('kMtByAlphaN',
concat(
generate-id(..),'+',
translate(@N,'1234567890','')
)
)[1]
) = 1
]">
<xsl:variable name="vName"
select="translate(@N,'1234567890','')"/>
<xsl:value-of select="concat($vName,': ')"/>
<xsl:apply-templates select="key('kMtByAlphaN',
concat(generate-id(..),'+',$vName)
)/@V"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Output:
Abstract: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley
Author: Bernard Shaw;Mark Twain
Note: Grouping by @N alphabetic content and parent generated id because I would expect several R
elements.
Upvotes: 0
Reputation: 77107
<xsl:for-each select="MT[starts-with(@N, 'Abstract')]">
<xsl:if test="position() = 1">
<xsl:value-of select="@N"/>:
</xsl:if>
<xsl:value-of select="@V"/>
</xsl:for-each>
Upvotes: 0