tags:

views:

67

answers:

2

Here is a contrived example of an xml document. In my real world case, the xml is fairly complex with multiple nested levels.

<alphabet>
<a>A</a>
<b>B</b>
<c>C</c> 
... and so on
</alphabet>

Using xslt, I want to transform the document so that only the vowels are printed.

In my real world case, we're using empty template match tags to block the display. But that's too verbose for my liking.

A: 

XSLT has precedence rules for templates with conflicting matches (link to XSLT spec). Therefore, you can have a * template which "swallows" the tags by default and add explicit templates which display or process the vovels.

Lucero
+1  A: 

I wouldn't allow the "default" or lowest precedence/priority matching template to silently swallow vowels or to do any other meaningful application processing.

It is a good practice that the template for all otherwise unmatched nodes (of a given kind), should produce a good debugging message and, optionally, terminate processing.

If this recommended practice isn't followed, then quite some errors will go silently unnoticed and it would be very difficult to find them and fix in any given fixed period of time.

Here is a solution, which involes only one empty template:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <my:vowels>
   <c>A</c>
   <c>E</c>
   <c>I</c>
   <c>O</c>
   <c>U</c>
 </my:vowels>

 <xsl:template match="node()|@*">
   <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
   </xsl:copy>
 </xsl:template>

 <xsl:template match="c[not(. = document('')/*/my:vowels/*)]"/>
</xsl:stylesheet>

When this transformation is performed on the following XML document:

<alphabet>
    <c>A</c>
    <c>B</c>
    <c>C</c>
    <c>D</c>
    <c>E</c>
    <c>F</c>
    <c>G</c>
    <c>H</c>
    <c>I</c>
    <c>J</c>
    <c>K</c>
    <c>L</c>
    <c>M</c>
    <c>N</c>
    <c>O</c>
    <c>P</c>
    <c>Q</c>
    <c>R</c>
    <c>S</c>
    <c>T</c>
    <c>U</c>
    <c>V</c>
    <c>W</c>
    <c>X</c>
    <c>Y</c>
    <c>Z</c>
</alphabet>

the wanted result is produced:

<alphabet>
    <c>A</c>
    <c>E</c>
    <c>I</c>
    <c>O</c>
    <c>U</c>
</alphabet>
Dimitre Novatchev
He wants only the vowels to be printed, not everything but the vowels.
Pavel Minaev
@Pavel-Minaev: Thanks for this reminder. I've corrected the solution.
Dimitre Novatchev
Ok, this should be a good starting point for us. Thanks Dimitre.
StevenWilkins