Removing DiffGram element in web service messages

Some time ago I was asked to review existing web services for a customer. The main thing I noticed was that they were using Microsoft’s diffgram elements and attributes in their input and output messages. I was not familiar with this format but found out that it has been created by Microsoft to make synchronizing datasets in .Net easier. In this case the web services were implemented with Spring-WS, so there was no real reason to use this format on the server side. Besides, it only makes the web service less useful on the client side since it leads to complications if you want to use a XML-Object mapper like JAXB (see this for example). One of the issues with Diffgram is that, besides the XML containing the Diffgram element, also the XSD is included. This XSD describes the content of the Diffram Dataset, however, the XSD and the resulting Dataset do not match because extra attributes are added (this is described in more detail here).
I decided to create a new web service that would accept incoming messages without this diffgram and ms-data elements and attributes (and would have a similar response). To make this work, I made use of an XSL transformation in combination with the interceptors in Spring-WS (the assumption is that only the content of the DataInstance part of the DiffGram are interesting).
For example this is the original request the web service is expecting:

<?xml version="1.0" encoding="UTF-8"?>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
	<CustomerDataSet>
		<Customers diffgr:id="Customers1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
			<CustomerID>ALFKI</CustomerID>
			<CompanyName>New Company</CompanyName>
		</Customers>
		<Customers diffgr:id="Customers2" msdata:rowOrder="1"  diffgr:hasChanges="inserted">
			<CustomerID>ANATR</CustomerID>
			<CompanyName>Ana Trujillo Emparedados y Helados</CompanyName>
		</Customers>
		<Customers diffgr:id="Customers3" msdata:rowOrder="2"  diffgr:hasChanges="inserted">
			<CustomerID>ANTON</CustomerID>
			<CompanyName>Antonio Moreno Taquera</CompanyName>
		</Customers>
		<Customers diffgr:id="Customers4" msdata:rowOrder="3"  diffgr:hasChanges="inserted">
			<CustomerID>AROUT</CustomerID>
			<CompanyName>Around the Horn</CompanyName>
		</Customers>
	</CustomerDataSet>
</diffgr:diffgram>

I created a new web service endpoint to which I added the XSLT interceptors. The new endpoint would expect this as a request:

<?xml version="1.0" encoding="UTF-8"?>
<CustomerDataSet>
	<Customers>
		<CustomerID>ALFKI</CustomerID>
		<CompanyName>New Company</CompanyName>
	</Customers>
	<Customers>
		<CustomerID>ANATR</CustomerID>
		<CompanyName>Ana Trujillo Emparedados y Helados</CompanyName>
	</Customers>
	<Customers>
		<CustomerID>ANTON</CustomerID>
		<CompanyName>Antonio Moreno Taquera</CompanyName>
	</Customers>
	<Customers>
		<CustomerID>AROUT</CustomerID>
		<CompanyName>Around the Horn</CompanyName>
	</Customers>
</CustomerDataSet>

As you can see this last example is quite simple and easy to use in combination with JAXB for example.
To create the original request out of the new one I made use of the following XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn fo">
	<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
	<xsl:template match="/">
		<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
			<xsl:copy>
				<!-- copy the attributes (if any) of the root element -->
				<xsl:copy-of select="@*"/>
				<xsl:apply-templates/>
			</xsl:copy>
		</diffgr:diffgram>
	</xsl:template>
	<!-- match any other element and copy it with the attributes -->
	<xsl:template match="*">
		<xsl:copy>
			<xsl:copy-of select="@*"/>
			<xsl:apply-templates/>
		</xsl:copy>
	</xsl:template>
	<xsl:template match="/CustomerDataSet/Customers">
		<Customers>
			<xsl:attribute name="id" namespace="urn:schemas-microsoft-com:xml-diffgram-v1">Customers<xsl:value-of select="position()"/></xsl:attribute>
			<xsl:attribute name="rowOrder" namespace="urn:schemas-microsoft-com:xml-msdata"><xsl:value-of select="position()-1"/></xsl:attribute>
			<xsl:attribute name="hasChanges" namespace="urn:schemas-microsoft-com:xml-diffgram-v1">inserted</xsl:attribute>
			<xsl:apply-templates/>
		</Customers>
	</xsl:template>
</xsl:stylesheet>

And for the response the opposite transformation is performed. The original response is used as input and the XSLT will filter out all diffgram and ms-data elements and attributes.
Here is an example XSL that takes the original CustomerDataSet as input and tranforms it the the more ‘simple’ format:

<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml example-original.xml?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn fo ">
	<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
	<xsl:template match="/">
		<xsl:copy>
			<!-- copy the attributes (if any) of the root element -->
			<xsl:copy-of select="@*"/>
			<xsl:apply-templates/>
		</xsl:copy>
	</xsl:template>
	<!-- match any other element and copy it with the attributes. Use local-name to get rid of the diffgr and ms-data namespaces -->
	<xsl:template match="*">
		<xsl:element name="{local-name()}">
			<xsl:copy-of select="@*"/>
			<xsl:apply-templates/>
		</xsl:element>
	</xsl:template>
	<!-- do not copy the attributes for  element'Customers' "/> -->
	<xsl:template match="/diffgr:diffgram/CustomerDataSet/Customers">
		<xsl:element name="{local-name()}">
			<xsl:apply-templates/>
		</xsl:element>
	</xsl:template>
	<!-- Remove the tag for the diffgram -->
	<xsl:template match="/diffgr:diffgram">
		<xsl:apply-templates/>
	</xsl:template>
</xsl:stylesheet>

With this post I have shown how you can use a simple XSLT to get rid of the Diffgram elements and attributes, of course with some assumptions that should be taken into account.

Advertisements

About Pascal Alma

Pascal is a senior IT consultant and has been working in IT since 1997. He is monitoring the latest development in new technologies (Mobile, Cloud, Big Data) closely and particularly interested in Java open source tool stacks, cloud related technologies like AWS and mobile development like building iOS apps with Swift. Specialties: Java/JEE/Spring Amazon AWS API/REST Big Data Continuous Delivery Swift/iOS
This entry was posted in General, JAXB, Web Service, XML/ XSD/ XSLT and tagged . Bookmark the permalink.