Unnamed user
Unnamed user

Reputation: 181

XML conversion using XSLT

I want to convert my XML document but not sure whether the desired output can be obtained using XSLT. Below is my XML code:

    <GetInvoiceList>
    <Request>
    <Case>
    <id>Case_1</id>
    <CaseID>Hi</CaseID>
    </Case>
    <BillStatusCode>
    <BillStatusCode>type description</BillStatusCode>
    <typecode>1</typecode>
    </BillStatusCode>
    <EBillProcessStatusCode>
    <EBillProcessStatusCode>type description</EBillProcessStatusCode>
    <typecode>2</typecode>
    </EBillProcessStatusCode>
    </Request>
    </GetInvoiceList>

I want to convert it into this:

   <GetInvoiceList>
   <Request>
   <Case id="Case_1">
   <CaseID>Hi</CaseID>
   </Case>
   <BillStatusCode typecode="1">type description</BillStatusCode> 
   <EBillProcessStatusCode typecode="2">type description</EBillProcessStatusCode>
   </Request>
   </GetInvoiceList>

Is it possible to get the desired output? Would appreciate any help regarding this. Thanks!

Upvotes: 0

Views: 96

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

If I understand correctly, the "generic solution" to undo the mess you have created would do two things:

  1. Convert id and typecode elements to attributes of their parent element;

  2. Eliminate any element whose name is the same as the name of its parent element, and copy its child nodes (text nodes in your example) to the parent element.

This translates to:

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="*"/>

<xsl:template match="*">
    <xsl:copy>
        <xsl:for-each select="id | typecode">
            <xsl:attribute name="{name()}">
                <xsl:value-of select="."/>
            </xsl:attribute>
        </xsl:for-each>
        <xsl:apply-templates select="node()[not(self::id or self::typecode)]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*[name(.) = name(..)]">
    <xsl:apply-templates/>
</xsl:template>

</xsl:stylesheet>

Upvotes: 1

Bala
Bala

Reputation: 68

Try it!!!, now I've changed the coding based on the element position. If you change the element positions in the input this won't help you.

Regards Bala

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
   <xsl:strip-space elements="*"/>

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

  <xsl:template match="*" mode="all">
    <xsl:choose>
      <xsl:when test="(count(ancestor::*) = 3 and count(preceding::*) = 0)
                      or (count(ancestor::*) = 3 and count(preceding::*) > 1 and count(preceding-sibling::*) = 1)">
      </xsl:when>
      <xsl:when test="count(ancestor::*) = 3 and count(preceding-sibling::*) = 0">
        <xsl:apply-templates mode="all"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy>
          <xsl:choose>
            <xsl:when test="count(ancestor::*) = 2 and count(preceding-sibling::*) = 0">
              <xsl:attribute name="{*[1]/name()}" select="*[1]"/>
            </xsl:when>
            <xsl:when test="count(ancestor::*) = 2 and count(preceding-sibling::*) != 0">
              <xsl:attribute name="{*[2]/name()}" select="*[2]"/>
            </xsl:when>
          </xsl:choose>
          <xsl:apply-templates mode="all"/>
        </xsl:copy>        
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Upvotes: 0

Related Questions