Altova Mailing List Archives>Archive Index >microsoft.public.xsl Archive Home >Recent entries >Thread Prev - Re: multi step transformation [Thread Next] Re: multi step transformationTo: NULL Date: 10/2/2004 10:46:00 AM Hi,
Seeing as you will need to modify your generic split routine anyway (as it
currently will not work correctly - the "Add all the attributes this bit not
tested" will never work because you are trying to output attributes after
you have output element content) the best approach would probably be to add
some generic capabilities to that template to cater for any optional
additional processing you might want to do when splitting.
You could employ a 'callback' technique - whereby you pass an element as a
param to your named template (usually an element with a discrete namespace
binding) and then apply templates to that passed element from within your
generic routine. The template that matches that element will then be your
'callback' routine that will do any additional specific processing for this
call to the generic template.
An example (using the same well-formed XML I gave previously as the test)...
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="my-callbacks"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my-callbacks="urn:my-callbacks">
<!-- define the callbacks - there will be one element in the list for
every -->
<!-- special process that you want to carry out -->
<my-callbacks:list>
<my-callbacks:add-b-attribute/>
</my-callbacks:list>
<!-- pull the callbacks into a variable for use later -->
<xsl:variable name="callbacks" select="document('')/*/my-callbacks:list"/>
<xsl:template match="/">
<output>
<xsl:apply-templates select="item"/>
</output>
</xsl:template>
<xsl:template match="item">
<xsl:call-template name="split">
<xsl:with-param name="elem" select="a"/>
<xsl:with-param name="input" select="string(a)"/>
<xsl:with-param name="delimiter" select="' '"/>
<xsl:with-param name="callback"
select="$callbacks/my-callbacks:add-b-attribute"/>
</xsl:call-template>
</xsl:template>
<!-- callback routine for adding the @b attribute -->
<xsl:template match="my-callbacks:add-b-attribute">
<xsl:param name="elem"/>
<xsl:attribute name="b">
<xsl:value-of select="$elem/../b"/>
</xsl:attribute>
</xsl:template>
<!-- generic split routine -->
<xsl:template name="split">
<xsl:param name="elem"/>
<xsl:param name="input"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:param name="callback"/> <!-- if this param is not passed there will
be no added processing -->
<xsl:choose>
<!-- See if the input contains the search string -->
<xsl:when test="contains($input, $delimiter)">
<xsl:element name="{name($elem)}"
namespace="{namespace-uri($elem)}">
<!-- add all the attributes this bit -->
<xsl:copy-of select="$elem/@*"/>
<xsl:if test="$callback">
<!-- perform an additional processing in the callback -->
<xsl:apply-templates select="$callback">
<xsl:with-param name="elem" select="$elem"/>
</xsl:apply-templates>
</xsl:if>
<!-- output spliced part of value -->
<xsl:value-of
select="normalize-space(substring-before($input,$delimiter))"/>
</xsl:element>
<xsl:call-template name="split">
<xsl:with-param name="elem" select="$elem"/>
<xsl:with-param name="input"
select="substring-after($input,$delimiter)"/>
<xsl:with-param name="delimiter" select="$delimiter"/>
<xsl:with-param name="callback" select="$callback"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="normalize-space($input)">
<xsl:element name="{name($elem)}"
namespace="{namespace-uri($elem)}">
<!-- add all the attributes this bit -->
<xsl:copy-of select="$elem/@*"/>
<xsl:if test="$callback">
<!-- perform an additional processing in the callback -->
<xsl:apply-templates select="$callback">
<xsl:with-param name="elem" select="$elem"/>
</xsl:apply-templates>
</xsl:if>
<!-- output spliced part of value -->
<xsl:value-of select="normalize-space($input)"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
HTH
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator
"wooks" <wookiz@h...> wrote in message
news:8852d33c.0410012329.1e30fc84@p......
>
> Memo to self - when asking for help be more explicit.
>
> Below is my generic split routine (the input parameter is probably
> otiose as it is just the text value of the element passed). It passes
> the element to be split as well as the delimiter to split by. I want
> each element created to have a copy of all the attributes that the
> unsplit element had (as per the comments the xsl:for-each to handle
> this is as yet untested).
>
> The difficulty is that the input XML doesn't have any attribute nodes.
> In this particular instance it is in element b, but the split routine
> will no longer be generic if I pass it specific elements to be
> converted to attributes (and there could be more than one element that
> needs to be so converted).
>
> So the constraints are -
> 1. Using the generic splitter which can be amended but not in a way as
> to lose genericity.
> 2. Avoid a 2 step transformation.
>
> The alternative is to accept that a generic routine cannot do this in
> one pass, but something in my brain tells me XSLT should be capable of
> better than that, I don't know how though.
>
>
>
>
>
> <xsl:stylesheet
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="1.0">
> <xsl:template name="split">
> <xsl:param name="elem"/>
> <xsl:param name="input"/>
> <xsl:param name="delimiter"/>
> <xsl:choose>
> <!-- See if the input contains the search string -->
> <xsl:when test="contains($input, $delimiter)">
> <xsl:element name="{name($elem)}"
> namespace="{namespace-uri($elem)}">
> <xsl:value-of select="normalize-space(substring-before($input,
> $delimiter))"/>
> <!-- Add all the attributes this bit not tested-->
> <xsl:for-each select="$elem/@*">
> <xsl:attribute name="name(current())">
> <xsl:value-of select="current()"/>
> </xsl:attribute>
> </xsl:for-each>
> </xsl:element>
> <xsl:call-template name="split">
> <xsl:with-param name="elem" select="$elem"/>
> <xsl:with-param name="input" select="substring-after($input,
> $delimiter)"/>
> <xsl:with-param name="delimiter" select="$delimiter"/>
> </xsl:call-template>
> </xsl:when>
> <xsl:otherwise>
> <xsl:element name="{name($elem)}"
> namespace="{namespace-uri($elem)}">
> <xsl:value-of select="$input"/>
> </xsl:element>
> </xsl:otherwise>
> </xsl:choose>
> </xsl:template>
> </xsl:stylesheet>
| ||||||
| Company | Legal | Press | Partners | Careers | Sitemap | Contact Us | Altova Blog | Mobile | Full Site | |||
|
