Developer

Modify generated XSLT 1.0 with the xsl:namespace element

Edmond Woychowsky shares a trick for modifying generated XSLT 1.0 without worrying about someone regenerating the map. He also throws in a couple of Star Trek references for good measure.

I really like Altova's MapForce for generating XSLT, but it shares something with every tool that generates XSLT: the warnings in the generated code (Listing A). These warnings essentially say that if you modify the generated code, you can kiss your code goodbye when you regenerate, because your code will be overlaid. While this might sound like Project Genesis to some, there is a way to modify the generated code and survive. Listing A

MapForce warning

<!—

This file was generated by Altova MapForce 2009sp1

YOU SHOULD NOT MODIFY THIS FILE, BECAUSE IT WILL BE

OVERWRITTEN WHEN YOU RE-RUN CODE GENERATION.

Refer to the Altova MapForce Documentation for further details.

http://www.altova.com/mapforce

—>

The key to survival is the xsl:namespace-alias element, which allows one to say that a particular namespace prefix will be replaced in the output with a different value namespace prefix. This allows the developer to include XSLT elements that won't be executed but will be present in the output. This is a rather useful way to add logic to existing XSLT when you find that you'll need to do it more than once.

Before I start with the modification, a brief examination of the XSLT generated by MapForce is necessary. This XSLT is comprised entirely of a variable number of named templates and a single match template that matches the document. All of the processing is handled through a series of xsl:for-each elements, which makes modifications easier because all of the code is in one place (with the exception of the named templates).

Example

Let's say the assignment is to do a proof of concept and create a new root element called xyzzy. We can accomplish this task by using the code in Listing B. Listing B

Proof of concept

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tr="http://techrepublic.com">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>

<xsl:namespace-alias stylesheet-prefix="tr" result-prefix="xsl"/>

<xsl:template match="/">

<tr:stylesheet>

<xsl:attribute name="version">1.0</xsl:attribute>

<tr:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>

<xsl:comment>MapForce generated named templates</xsl:comment>

<xsl:copy-of select="./xsl:stylesheet/xsl:template[./@name]"/>

<xsl:comment>MapForce generated match templates</xsl:comment>

<xsl:apply-templates select="./xsl:stylesheet/xsl:template[./@match]" mode="match"/>

</tr:stylesheet>

</xsl:template>

<xsl:template match="xsl:template" mode="match">

<xsl:copy>

<xsl:copy-of select="./attribute::node()"/>

<tr:element name="xyzzy">

<xsl:copy-of select="./child::node()"/>

</tr:element>

</xsl:copy>

</xsl:template>

</xsl:stylesheet>

The XSLT in Listing B looks pretty much like any XSLT except for these elements:

  • Although the namespace xmlns:tr="http://techrepublic.com" in the xsl:stylesheet element looks official, it is a placeholder for the tr namespace — almost any URL would do.
  • The xsl:namespace-alias, which specifies that the tr namespace is to be written to the result document as xsl.
  • The tr:stylesheet and the others become valid XSLT elements, and the tr namespace becomes xsl in the result (Listing C).
Listing C

Result

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>

<!—MapForce generated named templates—>

.

.

.

<!—MapForce generated match templates—>

<xsl:template match="/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vmf="http://www.altova.com/MapForce/UDF/vmf">

<xsl:element name="xyzzy">

.

.

.

</xsl:element>

</xsl:template>

</xsl:stylesheet>

Summary

While this is merely a proof of concept, you can build upon this idea. By using the EXSLT node-set function or its Microsoft equivalent, it would be possible to add post-processing to the mapped XML. With this technique, you can modify generated code in any way desired without worrying about someone regenerating the map.

To quote Scotty: "Is this worth something to you, laddie?"

Editor's Picks

Free Newsletters, In your Inbox