TransformingSOAPMessagesWithXSLT

Transforming SOAP-Messages with XSLT

netbeans logo xslt soap

Written by Siegfried Bolz
The original blog is available at Another Random Developer Blog
If you have comments, suggestions.. feel free to drop a line in my blog.



In this tutorial you can read how you can modify SOAP-Messages using XSL Transformation (XSLT). It is the continuation of the previous two tutorials How to modify JAX-WS SOAP-Messages and Creating generic SOAP Web Services. I am using the NetBeans 6 - Project from the tutorial Creating SOAP Web Services with NetBeans 6 to demonstrate the transformed SOAP-Request.

Please note:
Download-links to all files are available at the end of this tutorial.

[[{TableOfContentsTitle=TableOfContents} | {TableOfContents title='Table of Contents'}]]

Introduction

In my previous tutorial Creating generic SOAP Web Services i have shown a theoretic way to modify SOAP-Messages for your needs. The key for success was using XSLT for the transformations. In this blog i am using XSLT 2.0 for transformations.

Take a look at the Creating SOAP Web Services with NetBeans 6-project. The incoming request must look like this to work:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="soapwebservices.jdevelop.eu">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:calculateValues>
         <value1/>
         <value2/>
      </soap:calculateValues>
   </soapenv:Body>
</soapenv:Envelope>



soapui with incoming request


If a customer want to send a special request like this, it does not work:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="genericsoapwebservices.jdevelop.eu" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ customschema.xsd">
	<soapenv:Header>
		<data1 xmlns:soap="http://blog.jdevelop.eu/headerdata"/>
		<data2 xmlns:soap="http://blog.jdevelop.eu/headerdata"/>
		<SchemaVersion xmlns:soap="http://blog.jdevelop.eu/headerdata"/>
	</soapenv:Header>
	<soapenv:Body>
	</soapenv:Body>
</soapenv:Envelope>




custom request


With XSLT it is possible to transform the malformed request to a useful request.


Create the application

Open NetBeans 6 and create a new Java-Project (name it “XSLTransformation”):

create new java project


create new java project 2


Create a new Java Class (”XSLTransform):

new java class


new java class 2


Your opened NetBeans Java-Project should now look like this:

opened netbeans project

Replace the Java-Class with this code:

package eu.jdevelop.xsltransformation;

import java.io.StringWriter;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import net.sf.saxon.Configuration;
import net.sf.saxon.PreparedStylesheet;
import net.sf.saxon.trans.CompilerInfo;

/**
 * This class represents a XSL Transformation for the
 * SOAP Web Service Request.
 *
 * @author Siegfried Bolz (http://blog.jdevelop.eu)
 *
 */
public class XSLTransform {

    /**
     * The Configuration object
     */
    private Configuration config;
    
    /**
     * The StreamSource wrapping the XSLT stylesheet
     */
    private StreamSource styleSheet;

    /**
     * Constructs a new transformer with the given XSLT stylesheet.
     *
     * @param streamSource - The style sheet as a <code>StreamSource</code>
     */
    public XSLTransform(StreamSource streamSource) {
        this(streamSource, new Configuration());
    }

    /**
     * Constructs a new transformer with the given XSLT stylesheet
     * and the given <code>Configuration</code>.
     *
     * @param streamSource - The style sheet as a <code>StreamSource</code>
     * @param configuration - The configuration object
     */
    public XSLTransform(StreamSource streamSource, Configuration configuration) {
        this.styleSheet = streamSource;
        this.config = configuration;
    }

    /**
     * Transforms the given XML file wrapped in a <code>StreamSource</code>
     * and returns an XML file in form of a <code>String</code>. This <code>String</code>
     * can be than wrapped into a <code>java.io.StringWriter</code> to get a
     * <code>java.io.Writer</code> or into a <code>java.io.StringReader</code> to get a
     * <code>java.io.Reader</code>.
     *
     * @param streamSourceInput
     * @return An XML document in form of a <code>String</code>
     * @throws Exception
     */
    public String transform(StreamSource streamSourceInput) throws Exception {

        StringWriter out = new StringWriter();

        Transformer transformer = newTransformer(styleSheet);

        transformer.transform(streamSourceInput, new StreamResult(out));

        return out.toString();
    }

    /**
     * Returns a new <code>Transformer</code> object for the given XSLT
     * file.
     *
     * @param source
     * @return A <code>Transformer</code>
     * @throws TransformerConfigurationException
     */
    protected Transformer newTransformer(Source source) throws TransformerConfigurationException {
        Templates templates = newTemplates(source);
        return templates.newTransformer();
    }

    /**
     * Creates a new XSLT stylesheet template from the given
     * XSLT source file
     *
     * @param source
     * @return A <code>Templates</code>
     * @throws TransformerConfigurationException
     */
    protected Templates newTemplates(Source source) throws TransformerConfigurationException {
        CompilerInfo info = new CompilerInfo();
        info.setURIResolver(config.getURIResolver());
        info.setErrorListener(config.getErrorListener());
        info.setCompileWithTracing(config.isCompileWithTracing());

        return PreparedStylesheet.compile(source, config, info);
    }

    /**
     * A simple use case for testing.
     * 
     * XSLT: mapping.xslt
     * Input XML: custom_request.xml
     * Output XML: printed to System.out
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        // in this directory are all files located
        String directory = "xmldata<br>";

        // this is the XSLT-mapping-file
        String XSLTfile = "mapping.xslt";

        // create a transformer and initialize it with the XSLT
        XSLTransform transformer = new XSLTransform(new StreamSource(directory + XSLTfile));

        // execute the transformation and show the produced XML in System.out
        System.out.println(transformer.transform(new StreamSource(directory + "custom_request.xml")));
    }
    
} // .EOF



You see some errors in the NetBeans-IDE. Don’t worry, there are only some missing JAR’s.

missing jars


Download Saxon XSLT 9 and add the JAR-files to the project. To do that, rightclick on the Projectname and choose “Properties”.

project properties


Click on the left side on libraries, and add all saxon jar-files:

add jars


After that your NetBeans have to look like this:

netbeans status


This application is using some example XML-files which are located in the directory $XSLTransformation/xmldata/. You can download them separately at this location http://blog.jdevelop.eu/downloads/transforming_soap_messages/xmldata.zip. So now create the directory “xmldata” in your project-directory and copy the xml-files into it.

file location

xml data location


You see the hardcoded values of the XML-files in the “main”-function:

main function


How this application is working

This application is using the XSLT-file “mapping.xslt” to transform the malformed request (located in the file “custom_request.xml”) into a “normal” request, which the Web Service understood.

mapping.xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="soapwebservices.jdevelop.eu" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn xs xsi xsl" xmlns="http://schemas.xmlsoap.org/soap/envelope/">
	<xsl:namespace-alias stylesheet-prefix="n" result-prefix="#default"/>
	<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
	<xsl:template match="/n:Envelope">
		<n:Envelope>
			<xsl:attribute name="xsi:schemaLocation">
				<xsl:sequence select="'http://schemas.xmlsoap.org/soap/envelope/'"/>
			</xsl:attribute>
			<xsl:variable name="Vvar0_firstSource" select="."/>
			<xsl:for-each select="n:Header">
				<n:Header/>
			</xsl:for-each>
			<xsl:for-each select="n:Body">
				<n:Body>
					<soap:calculateValues>
						<xsl:for-each select="$Vvar0_firstSource/n:Header">
							<xsl:for-each select="data1">
								<value1 xmlns="">
									<xsl:sequence select="xs:decimal(.)"/>
								</value1>
							</xsl:for-each>
						</xsl:for-each>
						<xsl:for-each select="$Vvar0_firstSource/n:Header">
							<xsl:for-each select="data2">
								<value2 xmlns="">
									<xsl:sequence select="xs:decimal(.)"/>
								</value2>
							</xsl:for-each>
						</xsl:for-each>
					</soap:calculateValues>
				</n:Body>
			</xsl:for-each>
		</n:Envelope>
	</xsl:template>
</xsl:stylesheet>




custom_request.xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="genericsoapwebservices.jdevelop.eu" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ customschema.xsd">
	<soapenv:Header>
		<data1 xmlns:soap="http://blog.jdevelop.eu/headerdata">6</data1>
		<data2 xmlns:soap="http://blog.jdevelop.eu/headerdata">3.21</data2>
		<SchemaVersion xmlns:soap="http://blog.jdevelop.eu/headerdata">1.1</SchemaVersion>
	</soapenv:Header>
	<soapenv:Body>
	</soapenv:Body>
</soapenv:Envelope>




Example of a normal request

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="soapwebservices.jdevelop.eu">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:calculateValues>
         <value1>6</value1>
         <value2>3.21</value2>
      </soap:calculateValues>
   </soapenv:Body>
</soapenv:Envelope>




This is the mapping from the custom-request to the normal-request schema:

xslt mapping


Test the application

Build the application and launch it. The application is now transforming the malformed specific request with the XSLT stylesheet. In the Output-window you can see the generated XML. This XML is the valid request for our Web Service.

netbeans console result


If you send this new request to the Web Service, you will receive a positive response.

soap positive response


Web Service Implementation

If you want to use this XSL Transformation in your Web Service, you have to include it in the “Technical mapping” section (described in my blog Creating generic SOAP Web Services).

service call process


Intercept every non-conform request, transform it to a conform-request and send it to the Web Service Operation. That's it! :-)


Downloads




See also



Have a lot of fun!

---
Siegfried Bolz
Another Random Developer Blog

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo