0

I have a input and desired output xml file , but not able to write generic xsl transformer for that. Can anybody here help me out ? address/billing may have more elements at runtime, which should be directly copied to main person block.

<searchPersonResponse>
 <persons>
  <person>
   <name>name2</name>
   <address>
   <billing>
     <city>xx</city>
     <state>yyyy</state>
     <zip>zzzzz</zip>
   </billing>
   </address>
  </person>
  <person>
    <name>name1</name>
    <address>
      <billing>
       <city>xx</city>
       <state>yyyy</state>
       <zip>zzzzz</zip>
      </billing>
    </address>
   </person>
  </persons>
 </searchPersonResponse>

desired output xml

<searchPersonResponse>
 <persons>
  <person>
     <name>name2</name>
     <city>xx</city>
     <state>yyyy</state>
     <zip>zzzzz</zip>
  </person>
  <person>
       <name>name1</name>
       <city>xx</city>
       <state>yyyy</state>
       <zip>zzzzz</zip>
   </person>
  </persons>
 </searchPersonResponse>

1 Answer 1

2

EDITED: OP is only looking to "unwrap" address and billing elements when address is present with a billing child. XSLT now does that. Also, OP mentions needs a XSLT 1.0 solution; no XSLT 2.0 features were being used, so I simply changed the version to "1.0".

This XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
                <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="address[child::billing]|billing[parent::address]">
        <xsl:apply-templates/>
    </xsl:template>
</xsl:stylesheet>

When applied to this XML:

<searchPersonResponse>
    <persons>
        <person>
            <name>name2</name>
            <address>
                <billing>
                <city>xx</city>
                <state>yyyy</state>
                <zip>zzzzz</zip>
                </billing>
            </address>
        </person>
        <person>
            <name>name1</name>
            <address>
                <billing>
                <city>xx</city>
                <state>yyyy</state>
                <zip>zzzzz</zip>
                </billing>
            </address>
        </person>
    </persons>
</searchPersonResponse>

Produces the desired result:

<searchPersonResponse>
    <persons>
        <person>
            <name>name2</name>
            <city>xx</city>
            <state>yyyy</state>
            <zip>zzzzz</zip>
        </person>
        <person>
            <name>name1</name>
            <city>xx</city>
            <state>yyyy</state>
            <zip>zzzzz</zip>
        </person>
    </persons>
</searchPersonResponse>

The identity template will copy all nodes and attributes. The address and billing matching template (which matches either element) will copy their children but not themselves.

Sign up to request clarification or add additional context in comments.

5 Comments

You should consolidate your two templates by changing the match to match="address|billing" (+1)
Thank you! That is a good call. The perils of rushing to be the first to answer. :) Thanks!
Steveo, I want a exact match of address/billing and when this is found inside elements should be copied directly. Solution, you gave is looking for 'or' condition. To make it 'and' , I changed match to match='address/billing', but it is not working
other thing, I would like to add is , I am using version="1.0" .
@amarzeet, see my updated answer. The "address/billing" doesn't work because you are only selecting billing elements that are children of address elements, so the address element gets copied by the identity template. My updated answer matches on address elements with billing children and billing elements with address parents. Also, I wasn't using anything specific to XSLT 2.0, so changing the version number in the xsl:stylesheet element was all that was needed to make it usable by 1.0 processors.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.