[xsl] Re: Re: Filtering with multiple templates

Subject: [xsl] Re: Re: Filtering with multiple templates
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Fri, 7 Nov 2003 22:52:30 +0100
"Dongling Ding" <dling61@xxxxxxxxx> wrote in message
news:20031107191810.20723.qmail@xxxxxxxxxxxxxxxxxxxxxxxxxx
> Hi Dimitre,
>
> Thanks for the idea of merging two results together.
> But the problem is those two results are generated by
> program and has no certain order in there.
>
> In my case, t1 may not be the first. If t1 is after
> t2, the result of merge is
>
> <Member name="x">
> <Member name="w"/>
> <Member name="z"/>
> </Member>
>
> It is not the same as the original order(z should be
> before w).
>
> I think we want to merge those template results and
> also by looking at the original source to make sure
> the result of merge is consistent with the original
> one.

Hi Ding,

One way to achieve such merging, which will merge the elements according to
their document order, is the following:

The templates that produce the fragments to be merged must add one
additional attribute ("_pos"), the value of which is obtained using
xsl:number and reflects the document order of the copied elements.

Then when merging, we first sort the elements on the value of this
attributes and then copy them in the sorted order.

An example transformation is below. The two variables "vO1" and "vO2"
contain the results of applying templates.

The contents of "vO1" is:

<Member name="x">
   <Member name="w" _pos="6"/>
</Member>

The contents of "vO2" is:

<Member name="x">
   <Member name="z" _pos="3"/>
</Member>

Although the latter is merged to the former, their children are sorted on
the value of the "_pos" attribute before they are copied to the output.

Here's the complete transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:ext="http://exslt.org/common";
 exclude-result-prefixes="ext">

 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/">
    <xsl:variable name="vrtfO1">
      <xsl:apply-templates select="Member" mode="m2"/>
    </xsl:variable>
    <xsl:variable name="vrtfO2">
      <xsl:apply-templates select="Member" mode="m1"/>
    </xsl:variable>

    <xsl:variable name="vO1" select="ext:node-set($vrtfO1)/*"/>
    <xsl:variable name="vO2" select="ext:node-set($vrtfO2)/*"/>

    <xsl:for-each select="$vO1">
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:for-each select="* | $vO2/*">
          <xsl:sort select="@_pos" data-type="number"/>
          <xsl:copy>
            <xsl:copy-of select="@*[not(name()='_pos')]"/>
            <xsl:copy-of select="node()"/>
          </xsl:copy>
        </xsl:for-each>
      </xsl:copy>

    </xsl:for-each>
  </xsl:template>

  <xsl:template match="Member" mode="m1">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates select="Member[2]" mode="copy"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Member" mode="m2">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates select="Member[3]" mode="copy"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Member" mode="copy">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:attribute name="_pos">
        <xsl:number count="Member" level="any"/>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

When applied on this source.xml:

<Member name="x">
  <Member name="y"/>
  <Member name="z">
      <Member name="z1"/>
      <Member name="z2"/>
  </Member>
  <Member name="w"/>
</Member>

the wanted result is produced:

<Member name="x">
   <Member name="z"/>
   <Member name="w"/>
</Member>


=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL




 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread