Reputation: 2980
I'm transforming one XML file to another XML format.
Here is sample source file:
<xml>
<title>Pride and Prejudice</title>
<subtitle>Love Novel</subtitle>
</xml>
And here is xsl file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Product>
<xsl:apply-templates/>
</Product>
</xsl:template>
<xsl:template match="title">
<TitleDetail>
<TitleType>01</TitleType>
<TitleElement>
<TitleElementLevel>01</TitleElementLevel>
<TitleText><xsl:value-of select="current()"/></TitleText>
<!--Here Problem!!!-->
<xsl:if test="subtitle">
<Subtitle>123</Subtitle>
</xsl:if>
</TitleElement>
</TitleDetail>
</xsl:template>
Idea is that if source file contains subtitle tag I need to insert "Subtitle" node to the "TitleDetail", but 'if' condition returns false. How to check if source file has subtitle information?
Upvotes: 0
Views: 8856
Reputation: 122414
I would define another template
<xsl:template match="subtitle">
<Subtitle><xsl:value-of select="."/></Subtitle>
</xsl:template>
then in the main title
template apply templates to ../subtitle
(i.e. navigate from the title
element to the corresponding subtitle
)
<TitleText><xsl:value-of select="."/></TitleText>
<xsl:apply-templates select="../subtitle" />
You don't need the if
test, as the apply-templates
will do nothing if its select
doesn't find any matching nodes.
You will also need to exclude the subtitle
element when applying templates to the children of the xml
element, otherwise you will get a second copy of the Subtitle
output element after the TitleDetail
as well as the one inside it. The easiest way is to replace your match="/"
template with the following match="/*"
one instead
<xsl:template match="/*">
<Product>
<xsl:apply-templates select="*[not(self::subtitle)]/>
</Product>
</xsl:template>
If you have similar special handling for other elements in other templates you can add those to the not()
, i.e. select="*[not(self::subtitle | self::somethingelse)]"
.
Alternatively you could make use of template modes
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Product>
<xsl:apply-templates/>
</Product>
</xsl:template>
<xsl:template match="title">
<TitleDetail>
<TitleType>01</TitleType>
<TitleElement>
<TitleElementLevel>01</TitleElementLevel>
<TitleText><xsl:value-of select="."/></TitleText>
<xsl:apply-templates select="../subtitle" mode="in-title" />
</TitleElement>
</TitleDetail>
</xsl:template>
<!-- in "in-title" mode, add a Subtitle element -->
<xsl:template match="subtitle" mode="in-title">
<Subtitle><xsl:value-of select="."/></Subtitle>
</xsl:template>
<!-- in normal mode, do nothing -->
<xsl:template match="subtitle" />
Upvotes: 1
Reputation: 21609
If I understand the question correctly, you can try this:
<xsl:if test="following-sibling::subtitle">
<Subtitle>123</Subtitle>
</xsl:if>
Upvotes: 0