0

I am very new to XSLT and am struggling to get the below done. I am trying to reduce the number hierarchies in a XML document by adding the node names as additional nodes. I am unable to write the correct XSLT though. Also, is there any other way of achieving this(without XSLT, any tools?) ?

Appreciate any help in this. Thanks.

Input XML:

    <Rates>
    <Rate1>
        <Current>
            <onsite>100</onsite>
            <net>100</net>
            <gross>100</gross>
        </Current>
        <Past>
            <onsite>100</onsite>
            <net>100</net>
            <gross>100</gross>
        </Past>
    </Rate1>
    <Rate2>
        <Current>
            <onsite>2100</onsite>
            <net>2100</net>
            <gross>2100</gross>
        </Current>
        <Past>
            <onsite>2100</onsite>
            <net>2200</net>
            <gross>1200</gross>
        </Past>
    </Rate2>
</Rates>

Expected Output:

<Rates>
    <Rate>
        <RateType>Rate1</RateType>
        <RateHistory>Current</RateHistory>
        <onsite>100</onsite>
        <net>100</net>
        <gross>100</gross>
    </Rate>
    <Rate>
        <RateType>Rate1</RateType>
        <RateHistory>Past</RateHistory>
        <onsite>100</onsite>
        <net>100</net>
        <gross>100</gross>
    </Rate>
    <Rate>
        <RateType>Rate2</RateType>
        <RateHistory>Current</RateHistory>
        <onsite>2100</onsite>
        <net>2100</net>
        <gross>2100</gross>
    </Rate>
    <Rate>
        <RateType>Rate2</RateType>
        <RateHistory>Past</RateHistory>
        <onsite>2100</onsite>
        <net>2200</net>
        <gross>1200</gross>
    </Rate>
</Rates>
Sudhee
  • 704
  • 6
  • 12

2 Answers2

2

You are looking for this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:strip-space elements="*"/>

    <xsl:output indent="yes"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Current|Past">
        <Rate>
            <RateType><xsl:value-of select="name(..)"/></RateType>
            <RateHistory><xsl:value-of select="name()"/></RateHistory>
            <xsl:apply-templates/>
        </Rate>
    </xsl:template>

    <xsl:template match="Rate1|Rate2">
        <xsl:apply-templates/>
    </xsl:template>

</xsl:stylesheet>
Joel M. Lamsen
  • 7,143
  • 1
  • 12
  • 14
  • You are assuming `Rate1` and `Rate2` are the only possible rate types. – michael.hor257k May 27 '14 at 11:30
  • And that `Current` and `Past` are the only possible `RateHistory` values - although that seems more likely. – michael.hor257k May 27 '14 at 11:35
  • Thanks Joel. Works. Also, adding to michael's comments, if there are more rate types, I assume I need to update the template_match and add on further types, or something like "Rate*" – Sudhee May 27 '14 at 11:38
2

Assuming the rate types are not known in advance (and also not assuming that Current and Past are the only possible RateHistory values) try:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/">
    <Rates>
        <xsl:for-each select="Rates/*/*">
            <Rate>
                <RateType><xsl:value-of select="name(..)"/></RateType>
                <RateHistory><xsl:value-of select="name()"/></RateHistory>
                <xsl:copy-of select="*"/>
            </Rate>
        </xsl:for-each>
    </Rates>
</xsl:template>

</xsl:stylesheet>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51