Failed to create nested elements in XML using XLST
I have 开发者_运维百科a flat XML which looks like this:
<objectDataList>
<objectData>
<equipment>
<name>Chassis-One</name>
<type>Chassis</type>
</equipment>
</objectData>
<objectData>
<equipment>
<name>Shelf-One</name>
<type>Shelf</type>
</equipment>
</objectData>
<objectData>
<equipment>
<name>Shelf-Two</name>
<type>Shelf</type>
</equipment>
</objectData>
<objectData>
<equipment>
<name>Slot-One</name>
<type>Slot</type>
</equipment>
</objectData>
How can I create an XSL that will transform my XML into another XML that looks like this:
<equipments>
<object>
<name>Chassis-One</name>
<object>
<name>Shelf-One</name>
<object>
<name>Slot-One</name>
</object>
</object>
</object>
It's like in a chassis, there are 2 shelves, and in Shelf One, there is Slot -One..
I tried halfway, but I couldn't think how to make the element nested:
<xsl:template match="/response">
<equipments>
<object>
<xsl:apply-templates select="objectData"/>
</object>
</equipments>
<xsl:template match="objectData/equipment[type='Chassis']">
<name><xsl:value-of select="equipment/name"/></name>
<!-- Now I want to find the shelf according to the chassis name -->
<xsl:call-template name="find-shelf-according-to-chasis-name">
<xsl:with-param name="chassisName" select="equipment/name"/>
</xsl:call-template>
</xsl:template>
I hope someone could shed some light
Thank you in advance
There's a fairly simple (although a little verbose) solution:
<xsl:template match="objectDataList">
<equipments>
<xsl:apply-templates select="objectData[equipment/type='Chassis']"/>
</equipments>
</xsl:template>
<xsl:template match="objectData[equipment/type='Chassis']">
<xsl:variable name="index" select="substring-after(equipment/name,'-')" />
<object>
<xsl:copy-of select="equipment/name" />
<xsl:apply-templates select="following-sibling::objectData[equipment/type='Shelf' and substring-after(equipment/name,'-') = $index]" />
</object>
</xsl:template>
<xsl:template match="objectData[equipment/type='Shelf']">
<xsl:variable name="index" select="substring-after(equipment/name,'-')" />
<object>
<xsl:copy-of select="equipment/name" />
<xsl:apply-templates select="following-sibling::objectData[equipment/type='Slot' and substring-after(equipment/name,'-') = $index]" />
</object>
</xsl:template>
<xsl:template match="objectData[equipment/type='Slot']">
<xsl:variable name="index" select="substring-after(equipment/name,'-')" />
<object>
<xsl:copy-of select="equipment/name" />
</object>
</xsl:template>
It's a bit repetitive though, the last three templates are almost identical. But then, depending on your specific requirements, it might be helpful that they're handled by different templates.
If you can guarantee that a shelf will always follow the related chassis etc, then you can change the <xsl:apply-templates
in the second template to:
<xsl:apply-templates select="following-sibling::*[1]">
If there might not be one, then you can do:
<xsl:apply-templates select="following-sibling::*[1][equipment/type='Shelf']">
The following script will do what you want, it is a bit lengthy due to the fact that the Chassis - Shelf - Slot structure has to be represented in the script. If your xml would contain id and parent-id attributes the script could be smaller and the naming convention could be removed or loosened.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
<equipments>
<xsl:apply-templates select="//equipment[type='Chassis']" />
</equipments>
</xsl:template>
<xsl:template match="equipment[type='Chassis']">
<xsl:variable name="suffix" select="substring-after(name, '-')" />
<object>
<xsl:copy-of select="name" />
<xsl:apply-templates select="//equipment[type='Shelf'][substring-after(name, '-')=$suffix]" />
</object>
</xsl:template>
<xsl:template match="equipment[type='Shelf']">
<xsl:variable name="suffix" select="substring-after(name, '-')" />
<object>
<xsl:copy-of select="name"/>
<xsl:apply-templates select="//equipment[type='Slot'][substring-after(name, '-')=$suffix]" />
</object>
</xsl:template>
<xsl:template match="equipment[type='Slot']">
<object>
<xsl:copy-of select="name"/>
</object>
</xsl:template>
</xsl:stylesheet>
The part you were asking for uses the substring-after
function to determine the name suffix and uses that in the subsequent selection.
精彩评论