Deepak Chaudhary
Deepak Chaudhary

Reputation: 145

XSLT code for converting attributes to child elements and putting the value of current element into its another new child element

I am unaware of XSLT,Please help: I have the following XML:

<OLifE>
  <Holding id="1234">
    <HoldingKey>1397650618090</HoldingKey>
    <HoldingTypeCode tc="2">Policy</HoldingTypeCode>
    <HoldingStatus tc="2">Inactive</HoldingStatus>
    <CarrierAdminSystem>PAS</CarrierAdminSystem>
  </Holding>
</OLifE>

I want the output like this:

<OLifE>
  <Holding>
    <id>1234</id>
    <HoldingKey>1397650618090</HoldingKey>
    <HoldingTypeCode>
      <tc>2</tc>
      <value>Policy</value>
    </HoldingTypeCode>
    <HoldingStatus>
      <tc>2</tc>
      <value>Inactive</value>
    </HoldingStatus>
    <CarrierAdminSystem>PAS</CarrierAdminSystem>
   </Holding>
 </OLifE>

please note that, all attributes are needed to be converted to child elements but, for elements that have a tc attribute specified:

<HoldingTypeCode tc="2">Policy</HoldingTypeCode>

need to be handled carefully.

I DO NOT want the output like:

<HoldingTypeCode>
                <tc>2</tc>Policy</HoldingTypeCode>

I have the following XSLT code which needs the slight modification:

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

 <xsl:output method="xml"/>

 <xsl:template match="*">
       <xsl:element name="{name()}">
            <xsl:for-each select="@*">
                 <xsl:element name="{name()}">
                       <xsl:value-of select="."/>
                 </xsl:element>
            </xsl:for-each>
            <xsl:apply-templates select="*|text()"/>
       </xsl:element>
 </xsl:template>

Please help.

Upvotes: 0

Views: 834

Answers (2)

potame
potame

Reputation: 7905

I think you can define a template like this to be called where you want to output the attributes :

<xsl:template name="transform.attrs">
  <xsl:for-each select="@*">
    <xsl:element name="{name()}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:for-each>
</xsl:template>

For the most general case you use almost the same template as before, just call the new template for attributes:

<xsl:template match="*">
   <xsl:element name="{name()}">
      <xsl:call-template name="transform.attrs">
      <xsl:apply-templates select="*|text()"/>
   </xsl:element>
</xsl:template>

And for the specific elements, bearing the @tc attribute:

<xsl:template match="*[@tc]">
  <xsl:element name="{name()}">
    <xsl:call-template name="transform.attrs" />
    <value>
       <xsl:apply-templates select="*|text()"/>
    </value>
  </xsl:element>
</xsl:template>

Upvotes: 0

michael.hor257k
michael.hor257k

Reputation: 116959

Assuming you want a generic solution, how about:

XSLT 1.0

<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:strip-space elements="*"/>

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

<!-- attributes to elements -->
<xsl:template match="@*">
    <xsl:element name="{name()}">
        <xsl:value-of select="."/>
    </xsl:element>
</xsl:template>

<!-- avoid mixed content -->
<xsl:template match="text()[../@*]">
    <value>
        <xsl:value-of select="."/>
    </value>
</xsl:template>

</xsl:stylesheet>

Edit

However, the root element in my original XML has got xmlns="some web address" attribute.

In such case, change the first template to:

<!-- modified identity transform -->
<xsl:template match="*">
     <xsl:element name="{name()}">
        <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
</xsl:template>

This is assuming you want all the output nodes to be in no namespace.

Upvotes: 1

Related Questions