Thanks Mike, this to me seems like a novel way of doing it. I guess it would
be good to use this approach when there are very few elements from the src
xml that are not needed in the output xml i.e. I do not have too many
templates to ignore elements (just like you have here for BILL_TO_ADDRESS3).
Here is a template-based approach. I added comments so you would better
understand what is going on. Couple of things: 1. Any time you use
disable-output-escaping, you'd better have a really good reason. The
utility of producing an empty DOCTYPE is a mystery to me, but it's what you
wanted, so... See, normally you let the serializer create the DOCTYPE for
you; you just put doctype-public and/or doctype-system attributes in the
xsl:output element to signal what you want, as long as you don't need to
write an internal DTD subset. 2. Maybe you have a good reason for using
template modes. They're not needed for your example, though.
As I believe I mentioned, the DOCTYPE, though empty is needed by the target
system.
About the template modes, they came in the sheet I inherited. I just
retained them as I had a very limited mandate and I am only beginning to
learn xsl, so I did not want to touch any thing that I was not sure of.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
<!--
since doctype-public="" doctype-system="" in xsl:output
doesn't uniformly produce an empty DOCTYPE across all
XSLT processors, we'll use d-o-e
-->
<xsl:value-of disable-output-escaping="yes"
select="'<DOCTYPE Order>
'"/>
<!-- go process the root node's children -->
<xsl:apply-templates/>
</xsl:template>
Just an addition - I had to add an "!" before the DOCTYPE.
<!-- when processing a Quote element, generate an Order element
that contains the result of processing the Quote element's children -->
<xsl:template match="Quote">
<Order>
<xsl:apply-templates/>
</Order>
</xsl:template>
<!-- when processing an Info element, generate another Info element
that contains the result of processing the original's children -->
<xsl:template match="Info">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<!-- when processing an 'attribute' element that has a 'name' child
whose normalized string-value is 'BILL_TO_ADDRESS3', do nothing -->
<xsl:template
match="attribute[normalize-space(name)='BILL_TO_ADDRESS3']"/>
<!-- when processing any other 'attribute' element, generate an
element whose name is the normalized string-value of the 'attribute'
element's 'name' element child, and its contents shall be the result
of processing the 'atomicValue' children of the 'attribute' element -->
<xsl:template match="attribute">
<xsl:element name="{normalize-space(name)}">
<xsl:apply-templates select="atomicValue"/>
</xsl:element>
</xsl:template>
<!-- when processing a text node, generate a new text node
using the normalized value of the original node -->
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
When does this overridden text template get called. We do not seem to have
any templates that explicitly match text(). Does it get auto called when any
text is encountered?
<!-- don't forget that there is a built-in template that we're
relying on to handle the atomicValue elements (and any others
that we didn't provide explicit templates for): it just results
in the processing of the element's children; nothing is
generated. It looks like this:
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
-->
</xsl:stylesheet>
Just for info, I am also posting here the other approach that Lars
suggested:
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:transform xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version =
"1.0">
<xsl:template match = "Quote">
<xsl:text disable-output-escaping="yes"><!DOCTYPE Order></xsl:text>
<xsl:element name = "Order">
<xsl:element name ="Info">
<xsl:apply-templates mode = "Attribs" select =
"/Quote/Info"/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template mode = "Attribs" match = "Info">
<xsl:call-template name="atomicValue">
<xsl:with-param name="AVname" select="'BILL_TO_ADDRESS2'" />
</xsl:call-template>
<xsl:call-template name="atomicValue">
<xsl:with-param name="AVname" select="'PO_NUMBER'" />
</xsl:call-template>
</xsl:template>
<xsl:template name="atomicValue">
<xsl:param name="AVname" select="''" />
<xsl:element name="{$AVname}">
<xsl:value-of
select="attribute/atomicValue[normalize-space(../name)=$AVname]"/>
</xsl:element>
</xsl:template>
</xsl:transform>
Thanks Mike, Lars, Michael, David and all others who helped out.
Vish.
_________________________________________________________________
Add photos to your messages with MSN 8. Get 2 months FREE*.
http://join.msn.com/?page=features/featuredemail
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list