0
votes

Working on a xslt 1.0 stylesheet for mapping of an address service. I have lookup up some of the examples for the Muenchian method for grouping in xslt 1.0, but i still am confused on the xsl:key and nested xsl:for-each loops.

I am only concerned with the InputAddress node-set. There may be multiple (but not always) InputAddress nodesets as part of the parent ValidateRequest node so i need to loop thru all iterations of InputAddress and then perform the mapping to the pertinent elements.

source xml

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:v1="blah" xmlns:v3="blah2">
<soap:Header/>
<soap:Body>
    <v1:validate>
        <ValidateRequest>
            <!--One or more repetitions:-->
            <InputAddress>
                <v3:City>Redmond</v3:City>
                <v3:Territory>
                    <v3:Name>Washington</v3:Name>
                    <FIPSStateAlphaCode>WA</FIPSStateAlphaCode>
                </v3:Territory>
                <v3:PostalCode>98007</v3:PostalCode>
                <v3:Country>
                    <!--Zero or more repetitions:-->
                    <v3:Name>US</v3:Name>
                </v3:Country>
                <v3:FullAddress>123 main street</v3:FullAddress>
                <v3:FullAddress>Ste 200</v3:FullAddress>
            </InputAddress>
            <InputAddress>
                <v3:City>Seattle</v3:City>
                <v3:Territory>
                    <v3:Name>Washington</v3:Name>
                    <FIPSStateAlphaCode>WA</FIPSStateAlphaCode>
                </v3:Territory>
                <v3:PostalCode>98103</v3:PostalCode>
                <v3:Country>
                    <!--Zero or more repetitions:-->
                    <v3:Name>US</v3:Name>
                </v3:Country>
                <v3:FullAddress>987 1st street</v3:FullAddress>
            </InputAddress>
        </ValidateRequest>
    </v1:validate>
</soap:Body>

expected result

    <soap:Body>
    <wsdl:WS_MDM_Address_ValidationRequest>
        <wsdl:WS_MDM_Address_ValidationRequestElement>
            <wsdl:Address_Line1>123 main street</wsdl:Address_Line1>
            <wsdl:Address_Line2>Ste 200</wsdl:Address_Line2>
            <wsdl:City>Redmond</wsdl:City>
            <wsdl:State>WA</wsdl:State>
            <wsdl:Postal_Code>98007</wsdl:Postal_Code>
            <wsdl:Country>US</wsdl:Country>
        </wsdl:WS_MDM_Address_ValidationRequestElement>
        <wsdl:WS_MDM_Address_ValidationRequestElement>
            <wsdl:Address_Line1>987 1st Street</wsdl:Address_Line1>
            <wsdl:City>Seattle</wsdl:City>
            <wsdl:State>WA</wsdl:State>
            <wsdl:Postal_Code>98103</wsdl:Postal_Code>
            <wsdl:Country>US</wsdl:Country>
        </wsdl:WS_MDM_Address_ValidationRequestElement>
    </wsdl:WS_MDM_Address_ValidationRequest>
</soap:Body> 

and my named template snipet after an xsl:choose(not shown):

<xsl:key name="AddressDoctor" match="v3:FullAddress" use="//v3:FullAddress" />
<xsl:variable name="address" select="/*[local-name()='Envelope']/*[local-name()='Body']/*[local-name()='validate']/ValidateRequest/InputAddress"/>

<xsl:template name="addressdoctor">
    <soap:Envelope>
        <soap:Header>
            <xsl:copy-of select="/*[local-name()='Envelope']/*[local-name()='Header']/*"/>
        </soap:Header>
        <soap:Body>
            <wsdl:WS_MDM_Address_ValidationRequest>

            <xsl:for-each select="key('AddressDoctor', '.')">
                <wsdl:WS_MDM_Address_ValidationRequestElement>
                    <xsl:for-each select="[not($FullAddress = preceding::text()=$FullAddress)]">
                        <xsl:element name="wsdl:{concat('Address_Line',position())}">
                            <xsl:value-of select="."/>
                        </xsl:element>
                    </xsl:for-each>
                    <wsdl:City>
                    <xsl:for-each select="$address/*[local-name()='City']">
                        <xsl:value-of select="$address/*[local-name()='City']"/>
                    </xsl:for-each>
                    </wsdl:City>
                    <wsdl:State>
                        <xsl:value-of select="$address/*[local-name()='Territory']/*[local-name()='FIPSStateAlphaCode']"/>
                    </wsdl:State>
                    <wsdl:Postal_Code>
                        <xsl:value-of select="$address/*[local-name()='PostalCode']"/>
                    </wsdl:Postal_Code>
                    <wsdl:Country>
                        <xsl:value-of select="$address/*[local-name()='Country']/*[local-name()='Name']"/>
                    </wsdl:Country>
                </wsdl:WS_MDM_Address_ValidationRequestElement>
                </xsl:for-each>
            </wsdl:WS_MDM_Address_ValidationRequest>
        </soap:Body>
    </soap:Envelope>
</xsl:template>
1
Can you have duplicate v3:FullAddress elements? Based on the example input you gave I don't see why you need a grouping function.Matthew Green
yes i can have multiple v3:FullAddress elements, but i mainly want to keep the wsdl:WS_MDM_Address_ValidationRequestElement nodeset together as it can have multiple iterations, before sending the request to the SP. If i just run a for-each on each node, i get the value of each node, in each iteration of wsdl:WS_MDM_Address_ValidationRequestElement, in other words, the iterations are not unique.user3225475
Please show an actual, accurate sample of your XML document. For the current one there is indeed no need for grouping.Mathias Müller
Mathias, the current XML source tree i have in the post is the most accurate representation of what i am trying to work with. There are 2 InputAddress elements, which are parent 'groups' whose child nodes need to be processed independently and 'grouped' with one another. I look at any other of these grouping based questions with xmlt 1.0 and they involve groups of multiple unique parent nodes, so i don't know how my example could not involve the use of a grouping technique.user3225475

1 Answers

0
votes

Based on the input XML you have provided I don't see that there is a need for any type of grouping. Which is a good thing considering you are working with XSLT 1.0 since grouping can be a bit difficult to get right. You can instead start with a simple identity template and then override a few of the elements to display the output you are looking for.

Here is the XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v1="blah" xmlns:v3="blah2" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <xsl:output method="xml" indent="yes" />

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

  <xsl:template match="ValidateRequest">
    <wsdl:WS_MDM_Address_ValidationRequest>
      <xsl:apply-templates/>
    </wsdl:WS_MDM_Address_ValidationRequest>
  </xsl:template>

  <xsl:template match="InputAddress">
    <wsdl:WS_MDM_Address_ValidationRequestElement>
      <wsdl:Address_Line1>
        <xsl:value-of select="v3:FullAddress[1]"/>
      </wsdl:Address_Line1>
      <xsl:if test="v3:FullAddress[2]">
        <wsdl:Address_Line2>
          <xsl:value-of select="v3:FullAddress[2]"/>
        </wsdl:Address_Line2>
      </xsl:if>
      <wsdl:City>
        <xsl:value-of select="v3:City"/>
      </wsdl:City>
      <wsdl:State>
        <xsl:value-of select="v3:Territory/FIPSStateAlphaCode"/>
      </wsdl:State>
      <wsdl:Postal_Code>
        <xsl:value-of select="v3:PostalCode"/>
      </wsdl:Postal_Code>
      <wsdl:Country>
        <xsl:value-of select="v3:Country/v3:Name"/>
      </wsdl:Country>
    </wsdl:WS_MDM_Address_ValidationRequestElement>
  </xsl:template>

  <xsl:template match="v1:validate">
    <xsl:apply-templates/>
  </xsl:template>

</xsl:stylesheet>

This will produce the output that you are looking for based on the example you provided.