XML Transformations
The final XML-based technology mentioned here handles how you transform XML from one vocabulary into another. That is, you can change one XML document format into another very easily using the eXtensible Stylesheet Language with Transforms (XSLT). Actually, we've already looked at a major component of XSLTXPath. What we'll do here, briefly, is combine XPath with the XML style sheet vocabulary to change XML from one form into another.
Why would we want to do this in a Web Service book? After all, .NET does all the soapy stuff, right? Well, that's true, in a way. But you might have noticed that three versions of SOAP are available (1.0, 1.1, and 1.2). The SOAP specification states that you should return a version mismatch error if you receive a SOAP packet indicating that the packet is formed using a version of SOAP that you don't handle. But you might want to work with Web Services or clients that expect another version. If you accept a SOAP packet that .NET cannot handle (an old SOAP version, for example), you can easily intercept the packet using a .NET SoapExtension and then can transform it into something .NET can handle. We're simply showing you how to take SOAP in one form and convert it to another, in case you ever need to do so.
NOTE
This is by far not the most common use of XSL and XSLT. In the vast majority of the cases we've seen, people are using XSLT to turn XML documents into an HTML representation for display purposes. You'll probably never have to actually transform XML from one version of SOAP to another, especially given Microsoft's aggressive acceptance of the SOAP standard. But this transformation, no matter how unlikely, is still a valid use of the XSLT technology. This use simply relates XML and XSLT to SOAP and Web Services. However, you might find that if you use Web Services often and long enough, you'll want to access a Web Service that will require you to modify your SOAP packets for one reason or another, and XSLT is an excellent alternative for doing so.
NOTE
As I write this, the latest SOAP working draft specification has just been released. Therefore, my prediction that you might use XSL to transform SOAP 1.1 packets into SOAP 1.2 packets isn't necessarily so far-fetched. Luckily, the differences in the protocol versions aren't significant enough, for the most part, to truly merit XSL transformation. However, two clichés come to mind"You never know" and "Never say never"... .
Before diving in, another caveat should be mentioned: XPath and XSL/XSLT are huge topics that merit books of their own, and many are available. What we intend to present here is just enough to get you working with the technology. For an in-depth view, definitely pick up a good reference.
XSLT Drilldown
XSLT combines XPath expressions with templates. A template combines a nodeset returned from a specific XPath location step and produces output based upon the contents of the template. More often than not, the template uses the results obtained from the nodeset as input.
Let's say that you were given this XML document:
<?xml version="1.0"?> <Parts> <Part vehicle="Corvette" manufacturer="GM"> <Number>3972178</Number> <Desc>Special Hi-Perf Camshaft</Desc> <MinYear>1970</MinYear> <MaxYear>1972</MaxYear> <Comment>LT-1, Solid Lifters</Comment> </Part> (More part elements...) </Parts>
This document is clearly parts-centric. What if you want an XML document that is vehicle-centric? Would you need to create that from scratch? Well, assuming that all (or some) of the data that you require is already contained in the parts XML document, you wouldn'tyou could use XSLT to transform it from the parts-centric view to the vehicle-centric view rather easily.
Let's do just that. The vehicle XML document needs to look like this:
<?xml version="1.0"?> <Vehicles> <Vehicle> <Make/> <Model/> <Parts> <Part> <Number/> <Description/> <ModelYears/> </Part> <Parts> <Additional parts elements here) </Vehicle> </Vehicles>
The XSL style sheet to accomplish this is shown in Listing 3.1.
Listing 3.1 Example XSL Style Sheet
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <Vehicles> <xsl:apply-templates select="Parts"/> </Vehicles> </xsl:template> <xsl:template match="Parts"> <Vehicle> <Make><xsl:value-of select="Part/@manufacturer"/></Make> <Model><xsl:value-of select="Part/@vehicle"/></Model> <Parts> <xsl:for-each select="Part"> <Part> <Number> <xsl:value-of select="Number"/> </Number> <Description> <xsl:value-of select="Desc"/> <xsl:text>: </xsl:text> <xsl:value-of select="Comment"/> </Description> <ModelYears> <xsl:value-of select="MinYear"/> <xsl:text> to </xsl:text> <xsl:value-of select="MaxYear"/> </ModelYears> </Part> </xsl:for-each> </Parts> </Vehicle> </xsl:template> </xsl:stylesheet>
If you run the XML file and style sheet through Internet Explorer, you might not get the output that you expect. Internet Explorer will execute the transformation, but it will not display the result as XML. If you're interested in viewing the actual transformed output, it's best to run the XML document and style sheet through a program designed to execute the style sheet and save the resulting output to a file for later recall. You'll get an application that does just this when you get to .NET in the upcoming section ".NET and XSL."
XSL is an XML vocabulary, which is to say that your XSL style sheets will be XML documents in their own right. Many elements are associated with XSL; Table 3.4 gives you the more commonly used XSL instructions.
Table 3.4 Commonly Used XSL Vocabulary Elements
Operator |
Purpose |
---|---|
<apply-templates/> |
Tells the XSL processor to apply all appropriate templates to the nodeset |
<call-template/> |
Invokes a template by name |
<choose/> |
Uses multiple conditional testing (use with when and otherwise) |
<for-each/> |
Applies a template repeatedly to all nodes in the nodeset |
<if/> |
Is a conditional construct (has no else clauseuse <choose/> instead) |
<number/> |
Inserts a formatted integer into the output document |
<otherwise/> |
Is a default conditional expression used in conjunction with <choose/> |
<output/> |
Specifies serialization of the result tree |
<sort/> |
Sorts output nodes (used to rearrange output document) |
<stylesheet/> |
Is the XSL style sheet document (root) element |
<template/> |
Is the template tag (identifies and encapsulates template) |
<text/> |
Inserts literal text into the output document |
<value-of/> |
Copies the node of the input document to the output document |
<when/> |
Is an optional conditional expression used in conjunction with <choose/> |
<when/> |
Is an optional conditional expression used in conjunction with <choose/> |
Here you see the XSL document element, <xsl:stylesheet/>, as well as the XSL workhorse, <xsl:template/>. The style sheet element encapsulates the style sheet itself, while the template element identifies what could be referred to as XSL subroutines. In fact, they're not subroutines, but you could view them that way and not be terribly incorrect. Although we didn't show the XSL elements related to variables, XSL does have the capability of passing variables and parameters between templates. Because they're so powerful, let's look at XSL templates in a bit more detail.
XSL Templates
Listing 3.1 provided two templates, one for the document element and one for the <Parts/> element. We could have created more templates, one for each <Part/> node and children, but instead we elected to dig more deeply into the original XML document using <xsl:for-each/>. This simply made the template a bit easier to read.
The template itself is the cookie cutter that XSL will use to create the newly formatted document. For each template that you include within your style sheet, you'll receive formatted output. The key is to set up the templates so that they operate on the nodeset returned from the match attribute. If you know that many XML nodes will match the template, but you want to constrain the use of some of those nodes, you can also apply the mode attribute to the template:
<xsl:template match="/"> ... <xsl:apply-templates select="Parts" mode="Engine" /> <xsl:apply-templates select="Parts" mode="Body" /> ... </xsl:template> <xsl:template match="Parts" mode="Engine"> (Something to do with engine parts...) </xsl:template> <xsl:template match="Parts" mode="Body"> (Something to do with body parts...) </xsl:template>
Essentially, mode enables you to process original document nodes many times, with each processing iteration producing a different result.
Notice that we also used the XSL instruction <xsl:apply-templates/>. This tells XSL to go through its template collection and, for any of the input XML nodes that match the templates, produce the output. The key is to create XPath expressions that draw from the XML document the precise nodeset that you want to work with.
The template is the key to transforming the original XML document. After you establish the XPath expression that will pull the set of nodes of interest, you insert the new XML document structure within the template. For each XML node XSL finds that matches the template, it spits out a copy of the resulting template into the new XML document.
At this point, you've reviewed enough XML to move into .NET. Although it's entirely possible to write .NET-based Web Services all day long and never need to access their XML nature, it's also very likely that you'll find a minor change to some part of your SOAP packet to be useful. In that case, you'll find yourself using some or all of the technologies described here. If you're comfortable with what has been discussed so far, let's now talk about XML within .NET.