1

I am a newbie with XSL Transformations. I tried all possible options in this site from other questions & answers but i think my situation little unique (atleast for me).

I have to parse below xml and construct a key-value pair kinda structure as an output.

My actual xml is as below.

<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema/"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance/" xmlns:HNS="http://tempuri.org/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://tempuri.org/">
<SOAP-ENV:Header>
    <ROClientIDHeader SOAP-ENV:mustUnderstand="0" xmlns="http://tempuri.org/">
        <ID>{E931E54B-DA4C-4A93-9BF3-BF82EE028B26}</ID>
    </ROClientIDHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:ro="http://tempuri.org/">
    <v1:Response>
        <v1:Result>
            <v1:Fields>
                <v1:TSimpleDataField>
                    <v1:FieldName>COMMENT</v1:FieldName>
                </v1:TSimpleDataField>
                <v1:TSimpleDataField>
                    <v1:FieldName>SITE_TYPE</v1:FieldName>
                </v1:TSimpleDataField>
                <v1:TSimpleDataField>
                    <v1:FieldName>TOTAL_ADDRESSES</v1:FieldName>
                </v1:TSimpleDataField>
            </v1:Fields>
            <v1:Data>
                <v1:TVarArray>
                    <v1:anyType>DQT NLB Dev</v1:anyType>
                    <v1:anyType>62</v1:anyType>
                    <v1:anyType>100</v1:anyType>
                </v1:TVarArray>
            </v1:Data>
        </v1:Result>
    </v1:Response>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

I want to parse and extract the values under <v1:Fields> and <v1:Data> and construct a single record.

For example, if we take a single key-pair value from these two elements as below

<v1:TSimpleDataField>
    <v1:FieldName>COMMENT</v1:FieldName>
</v1:TSimpleDataField>

And

<v1:TVarArray>
    <v1:anyType>DQT NLB Dev</v1:anyType>

I want to see the output as below

<v1:Response>
  <v1:COMMENT>DQT NLB Dev</v1:COMMENT>
  <v1:SITE_TYPE>62</SITE_TYPE>
  <v1:TOTAL_ADDRESSES>100</v1:TOTAL_ADDRESSES>
</v1:Response>

what is the best way to write the XSLT to extract this data from this given xml. Any help or pointers would be really appreciated.

8
  • 1. Could you post the complete output document that you expect to get as a result? -- 2. Are you sure all FieldNames can be used as valid XML element names? Commented Feb 5, 2015 at 8:34
  • I see 2 problems - firstly you have 3 key fields but 4 data fields. So there is no explicit one to one mapping, and secondly xml does not provide any fundamental guarantee over the ordering of nodes, so relying on the position of data within the xml instance to be always correct could become a problem. Commented Feb 5, 2015 at 8:42
  • @TomRedfern "xml does not provide any fundamental guarantee over the ordering of nodes" Beg pardon? Commented Feb 5, 2015 at 8:46
  • @michael.hor257k yes agree that is unclear. My meaning was that any strategy to work with nodes of a document, selected solely by relative order (1,2,3,etc), is problematic because there is nothing inherent in the production of the document (which is a soap payload) to guarantee that over multiple passes the order of said nodes will remain constant. Commented Feb 5, 2015 at 8:51
  • @TomRedfern I know nothing about how this document is being produced; however, once it has been produced, the order of the nodes is definitive and authoritative. Otherwise every HTML table would be unreliable... Commented Feb 5, 2015 at 8:56

1 Answer 1

1

Here's an example you could adapt to your needs:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:v1="http://tempuri.org/"
exclude-result-prefixes="SOAP-ENV">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/">
    <v1:root>
        <xsl:for-each select="SOAP-ENV:Envelope/SOAP-ENV:Body/v1:Response/v1:Result/v1:Fields/v1:TSimpleDataField">
            <xsl:variable name="i" select="position()" />
            <xsl:element name="v1:{v1:FieldName}">
                <xsl:value-of select="../../v1:Data/v1:TVarArray/v1:anyType[$i]" />
            </xsl:element>
        </xsl:for-each>
    </v1:root>
</xsl:template>     

</xsl:stylesheet>

Applied to your (corrected) example input, the result is:

<?xml version="1.0" encoding="UTF-8"?>
<v1:root xmlns:v1="http://tempuri.org/">
  <v1:COMMENT>DQT NLB Dev</v1:COMMENT>
  <v1:SITE_TYPE>62</v1:SITE_TYPE>
  <v1:TOTAL_ADDRESSES>100</v1:TOTAL_ADDRESSES>
</v1:root>

I repeat here the warning I made in the comments: this will fail if any one of the <v1:FieldName> elements contains a value that cannot be used as a valid XML element name.

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

1 Comment

This is perfect. Thank you very much for quick response.

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.