Saturday, December 31, 2011

XSLT: Axis and Predicate power!

This blog shows you about how to take advantage of axis and predicate in xpath expression: axis::test[predicate].
For example you have this XML:

<Projects>
<Project>
<ProjectName> Teach my toddler computer </ProjectName>

<ProjectActivities>
<ProjectActivity>
<ActivityName> Install Qimo Linux </ActivityName>
</ProjectActivity>
<ProjectActivity>
<ActivityName> Teach mouse game for mouse training </ActivityName >
</ProjectActivity>
</ProjectActivities>

<Elements>
<ProjectElement>
<ElementName>mouse skills</ElementName>
</ProjectElement>
<ProjectElement>
<ElementName>menu navigation</ElementName>
</ProjectElement>
</Elements>
</Project>

<Project>

<ProjectName> Make my wife happy</ProjectName>

<ProjectActivities>
<ProjectActivity>
<ActivityName> Buying flowers </ActivityName>
</ProjectActivity>
<ProjectActivity>
<ActivityName> Morning kiss </ActivityName >
</ProjectActivity>
</ProjectActivities>

<Elements>
<ProjectElement>
<ElementName>love</ElementName>
</ProjectElement>
</Elements>
</Project>

<Projects>

you want to transform this XML to this text:

Project: Teach my toddler computer
*Activities: Install Qimo Linux
**Elements: mouse skills, menu navigation
*Activities: Teach mouse game for mouse
**Elements: mouse skills, menu navigation
Project: Make my wife happy
*Activities: Buying flowers
**Elements: love
*Activities: Morning kiss
**Elements: love

using this xslt:


<xsl:for-each select="//Projects/Project">
<xsl:variable name="nuproj" select="ProjectName"/>
Project:<xsl:value-of select="ActivityName"/>,
<xsl:for-each select="ProjectActivities/ProjectActivity">
*Activities:<xsl:value-of select="ActivityName"/>,
<xsl:text></xsl:text>
<xsl:for-each select="following::Elements[parent::Project/ProjectName=$nuproj]/ProjectElement">
**Elements:<xsl:value-of select="ElementName"/> ,
</xsl:for-each>
<xsl:text></xsl:text>
</xsl:for-each>
<xsl:text></xsl:text>
</xsl:for-each>



In this xsl we iterate over ProjectActivity within each Project. So during this iteration the current context is in a ProjectActivity, while you want also to iterate over each Elements/ProjectElement. We solve this using xpath expression in the form of axis::test[predicate] :

following::Elements[parent::Project/ProjectName=$nuproj]/ProjectElement

so the "following" is the axis which tells that we select the Elements/ProjectElement located following the current context ProjectActivity. There many as other axis expression such as preceding, parents, descendants, etc which specifies the location relative to the current context.

[parent::Project/ProjectName=$nuproj] is the predicate, which specifies the condition of which Elements node to be selected (since there are more than one Elements nodes located following the current context ProjectActivity. In this case we specify that the Elements node to be selected should have a parent Project which has Project/ProjectName node with value equal to the variable $nuproj, i.e. the Elements node that belongs to the same Project with the current context ProjectActivity.

Source: Steve's blogs http://soa-java.blogspot.com/

Any comments are welcome :)




References:


Jesper Tverskov's axis tutorial
XSLT 2.0 and XPath 2.0 Programmer's Reference

No comments: