Reputation: 359
My task is to create XSLT transformation. In procedural language solution would look like this:
foreach( Book book in set)
{
int importanceIndicator = 0;
foreach( Page page in book )
{
if(page.name == "important_page")
{
importanceIndicator = 1;
break;
}
}
book.newField.importanceIndicator = importanceIndicator;
}
How can I solve this problem in XSLT (which is very different from procedural languages)?
Sample XML files:
Input:
<set>
<book>
<page name="important_page"></page>
<page name="first_page"></page>
<page name="important_page"></page>
<page name="second_page"></page>
<page name="important_page"></page>
</book>
<book>
<page name="another_page"></page>
<page name="first_page"></page>
<page name="3_page"></page>
<page name="second_page"></page>
<page name="another_page"></page>
</book>
<book>
<page name="important_page"></page>
<page name="first_page"></page>
<page name="important_page"></page>
<page name="second_page"></page>
<page name="another_page"></page>
</book>
</set>
Output:
<set>
<book>
<newField importance_indicator="1"></newField>
</book>
<book>
<newField importance_indicator="0"></newField>
</book>
<book>
<newField importance_indicator="1"></newField>
</book>
</set>
Upvotes: 0
Views: 253
Reputation: 359
I found the answer, it can be done like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<set>
<xsl:for-each select="set">
<xsl:for-each select="book">
<book>
<xsl:variable name="importanceIndicatorTmp">
<xsl:choose>
<xsl:when test= "page/@name = 'important_page'">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<newField importanceIndicator="{$importanceIndicatorTmp}"></newField>
</book>
</xsl:for-each>
</xsl:for-each>
</set>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 70618
First start off with the identity template (which in this case will just copy the set
node)
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
Then, as you are transforming book
elements, you need a new template that matches book
, where you can copy the book
element and add a newField
element
<xsl:template match="book">
<xsl:copy>
<newField>
<!-- Add code for attribute -->
</newField>
</xsl:copy>
</xsl:template>
And to create the attribute, you can use xsl:attribute
with an xsl:choose
containing your condition to check
<xsl:attribute name="importance_indicator">
<xsl:choose>
<xsl:when test="page[@name='important_page']">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="book">
<xsl:copy>
<newField>
<xsl:attribute name="importance_indicator">
<xsl:choose>
<xsl:when test="page[@name='important_page']">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</newField>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that the template matching "book" can be simplified, by using Attribute Value Templates (indicated by the { }
symbols which cause the expression inside to be evaluated, rather than output literally)
<xsl:template match="book">
<xsl:copy>
<newField importance_indicator="{number(boolean(page[@name='important_page']))}"/>
</xsl:copy>
</xsl:template>
So page[@name='important_page'])
will select the page
if it is an "important_page". boolean()
will return true or false depending if that page exists, and number will then convert "true" to "1" or "false" to "0".
Upvotes: 1
Reputation: 2125
In XSLT, you don't need a loop to accomplish this. When you process the book node, you can examine the contents of its children.
<xsl:template match="book">
<newfield>
<xsl:choose>
<xsl:when test="page/@name='important page'">
<xsl:attribute name="importance_indicator" select="1">
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="importance_indicator" select="0">
</xsl:otherwise>
Upvotes: 2