Mrz 24 2008
Transforming SOAP-Messages with XSLT
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>
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>
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 a new Java Class (“XSLTransform):
Your opened NetBeans Java-Project:
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.
Download Saxon XSLT 9 and add the JAR-files to the project. To do that, rightclick on the Projectname and choose “Properties”.
Click on the left side on libraries, and add all saxon jar-files:
After that your NetBeans have to look like this:
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.
You see the hardcoded values in the “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:
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.
If you send this new request to the Web Service, you will receive a 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).
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.
No responses yet