Mrz 24 2008

Transforming SOAP-Messages with XSLT

Published by at 4:19 PM under Java,NetBeans,web services



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

Note:
Download-links to all files are available at the end of this blog.


Introduction

In my previous blog 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 normal 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>


SOAPUI with 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”):

NetBeans create java project

NetBeans create java project 2


Create a new Java Class (“XSLTransform):

NetBeans create new java file

NetBeans create new java file with package

Your opened NetBeans Java-Project:

NetBeans new java project opened


Replace the Java-Class with this code:

XSLTransform.java

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\";

        // 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.

NetBeans missing saxon jars

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

NetBeans Project properties

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

NetBeans Project properties add missing libraries


After that your NetBeans have to look like this:

Opened Netbeans 6 Project


This application is using some example XML-files which are located in the directory $XSLTransformation/xmldata/. You can download them separately here. So now create the directory “xmldata” in your project-directory and copy the xml-files to it.

NetBeans xmldata directory


NetBeans location of xml files


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

NetBeans main function code


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 output


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

SOAPUI with transformed request


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).

Generic SOAP Web Services - activity diagram

Intercept every non-conform request, transform it to a conform-request and send it to the Web Service Operation.


Downloads

NetBeans 6 Project: download
Example XML Files: download.


Writing 1Y0-259 becomes easier after 70-536 and 70-642, provided that one has not done 642-642 series like the 642-825 before.

Technorati Tags: , , , , , ,

No responses yet

Leave a Reply


− 5 = vier