Search code examples
xmlxsltsoappeoplesoft

Modifying SOAP Envelope


I am fairly new with XSLT and wondering how to change the XML SOAP message to add more tags in between

Source XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <DataValidationFailureFault xmlns="http://sample.com">
         <ValidationErrorList>
            <ValidationError>
               <ErrorCode>1234</ErrorCode>
               <ErrorString>Test Error</ErrorString>
            </ValidationError>
         </ValidationErrorList>
      </DataValidationFailureFault>
   </soapenv:Body>
</soapenv:Envelope>

After XSLT, I want the XML SOAP to look like:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>HardCoded Value</faultcode>
         <faultstring>HardCoded Value</faultstring>
         <detail>
            <DataValidationFailureFault xmlns="http://sample.com">
               <ValidationErrorList>
                  <ValidationError>
                    <ErrorCode>1234</ErrorCode>
                    <ErrorString>Test Error</ErrorString>
                  </ValidationError>
               </ValidationErrorList>
            </DataValidationFailureFault>
         </detail>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>


Solution

  • Start with an identity tranform. Then, write another template to intervene in the identity copying process in the right place, namely when the soapenv:Body element is processed.

    XSLT Stylesheet

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    
      <xsl:strip-space elements="*"/>
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="soapenv:Body">
        <xsl:copy>
          <soapenv:Fault>
              <faultcode>HardCoded Value</faultcode>
              <faultstring>HardCoded Value</faultstring>
              <detail>
                  <xsl:apply-templates select="@*|node()"/>
              </detail>
          </soapenv:Fault>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>
    

    XML Output

    By the way, sure you need all those unused namespace declarations?

    <?xml version="1.0" encoding="utf-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <soapenv:Body>
          <soapenv:Fault>
             <faultcode>HardCoded Value</faultcode>
             <faultstring>HardCoded Value</faultstring>
             <detail>
                <DataValidationFailureFault xmlns="http://sample.com">
                   <ValidationErrorList>
                      <ValidationError>
                         <ErrorCode>1234</ErrorCode>
                         <ErrorString>Test Error</ErrorString>
                      </ValidationError>
                   </ValidationErrorList>
                </DataValidationFailureFault>
             </detail>
          </soapenv:Fault>
       </soapenv:Body>
    </soapenv:Envelope>
    

    EDIT

    just curious how do I remove the namespace in DataValidationFailureFault tag?

    In this case, add another template to the stylesheet that matches the elements in that namespace (DataValidationFailureFault and its descendants, too - it's a default namespace). Then, construct a new element without a namespace for each of them:

    <xsl:template match="sample:DataValidationFailureFault|sample:DataValidationFailureFault//*">
      <xsl:element name="{name()}">
          <xsl:apply-templates select="@*|node()"/>
      </xsl:element>
    </xsl:template>
    

    and modify the stylesheet element of the XSLT code to include a namespace declaration for the sample: prefix and also exclude this prefix, since it becomes unused in the output.

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:sample="http://sample.com"
    exclude-result-prefixes="sample">