stack values in xsl or substract element from tree

Discussion in 'XML' started by Jean-Christophe Michel, Dec 24, 2003.

  1. Hi,

    In a complex merging of two (non ordered) xml files
    i need to keep track of the elements of the second tree that were already
    merged with first tree, to copy only unused elements at the end.

    I tried two solutions:

    * first is to 'substract' the used element from existing tree

    <param name="elem" />
    <param name="tree" />

    <call-template name="recurse">
    <with-param name="tree"
    select="$tree/*[generate-id() != generate-id($elem)]" />
    </call-template>

    (elem was found among $tree/*)

    Last copy would be
    <copy-of select="$tree" />

    * second was to stack values

    <key name="uid" match="*" use="used-id" />
    ....
    <param name="elem" />
    <param name="tree" />

    <param name="used-tree">
    <used used-id="{generate-id($elem)}" />
    <copy-of select="$used-tree" />
    </param>

    Last copy would be
    <apply-templates mode="last-copy"
    select="$tree[count(. | key('uid', generate-id())=0]" />
    <template mode="last-copy" match="node()|@*">
    <copy>
    <apply-templates mode="last-copy"
    select="./*[count(. | key('uid', generate-id())=0]" />
    </copy>
    </template>

    (maybe using exslt:node-set($tree) to have a node-set)
    *****

    Which way should work best ? what are the standard solutions for this ?
    Jean-Christophe Michel, Dec 24, 2003
    #1
    1. Advertising

  2. I cannot understand either the problem or the solutions.

    You are speaking about "trees", but you are using your $tree variable just
    as a node-set (tree with a depth of one).

    Also, it is not at all clear what the second method does.

    I suspect that your original problem may have a simpler solution, in which
    it is not necessary to "copy only unused elements at the end".

    Probably if you describe your problem here, many people will be able to
    help.



    Dimitre Novatchev.
    FXSL developer, XML Insider,

    http://fxsl.sourceforge.net/ -- the home of FXSL
    Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html


    "Jean-Christophe Michel" <> wrote in message
    news:p...
    > Hi,
    >
    > In a complex merging of two (non ordered) xml files
    > i need to keep track of the elements of the second tree that were already
    > merged with first tree, to copy only unused elements at the end.
    >
    > I tried two solutions:
    >
    > * first is to 'substract' the used element from existing tree
    >
    > <param name="elem" />
    > <param name="tree" />
    >
    > <call-template name="recurse">
    > <with-param name="tree"
    > select="$tree/*[generate-id() != generate-id($elem)]" />
    > </call-template>
    >
    > (elem was found among $tree/*)
    >
    > Last copy would be
    > <copy-of select="$tree" />
    >
    > * second was to stack values
    >
    > <key name="uid" match="*" use="used-id" />
    > ...
    > <param name="elem" />
    > <param name="tree" />
    >
    > <param name="used-tree">
    > <used used-id="{generate-id($elem)}" />
    > <copy-of select="$used-tree" />
    > </param>
    >
    > Last copy would be
    > <apply-templates mode="last-copy"
    > select="$tree[count(. | key('uid', generate-id())=0]" />
    > <template mode="last-copy" match="node()|@*">
    > <copy>
    > <apply-templates mode="last-copy"
    > select="./*[count(. | key('uid', generate-id())=0]" />
    > </copy>
    > </template>
    >
    > (maybe using exslt:node-set($tree) to have a node-set)
    > *****
    >
    > Which way should work best ? what are the standard solutions for this ?
    Dimitre Novatchev, Dec 24, 2003
    #2
    1. Advertising

  3. On Wed, 24 Dec 2003 12:05:39 +0100, Dimitre Novatchev wrote:

    > I cannot understand either the problem or the solutions.


    Sorry, i was probably not clear.

    > You are speaking about "trees", but you are using your $tree variable just
    > as a node-set (tree with a depth of one).


    It contains the document() loaded.

    > Probably if you describe your problem here, many people will be able to
    > help.


    Would be happy if such solution existed. I've been searching for a while.

    We have a main xml file containing a recursive structure:

    <definition id="first" ... >
    <param name="p1">value1</param>
    <param name="p2">value2</param>
    <section name="s1">
    <param name="p3">value3</param>
    <param name="p4">value4</param>
    </section>

    <children>
    <definition id="second" ...>
    </definition>

    <include id="overridden-id" definition="myfile">
    <param name="p5">value5</param>
    <section name="s2">
    <param name="p6">value6</param>
    </section>
    <children>
    <definition id="ignored" .../>
    </children>
    </include>

    </children>
    </definition>

    The included 'myfile' contains itself a definition:

    <definition id="included" other-attrib="foo">
    <param name="p5">overridden value5</param>
    <section name="s2">
    <param name="p7">value7</param>
    </section>
    <children>
    <definition id="included-too" .../>
    </children>
    </definition>

    The purpose is to include the file(s) and override the elems/attribs with
    the values contained in <include> elems, _only_ for some elemes/attribs
    that are authorized to be overriden :)
    Here is the wished result for the example here:

    <definition id="first" ... >
    <param name="p1">value1</param>
    <param name="p2">value2</param>
    <section name="s1">
    <param name="p3">value3</param>
    <param name="p4">value4</param>
    </section>

    <children>
    <definition id="second" ...>
    </definition>

    <definition id="overridden-id" other-attrib="foo">
    <param name="p5">overridden value5</param>
    <section name="s2">
    <param name="p6">value6</param>
    <param name="p7">value7</param>
    </section>
    <children>
    <definition id="included-too" .../>
    </children>
    </definition>

    </children>
    </definition>

    Note that include/children are ignored because children cannot be
    overridden.
    The included file can contain other include elements too.
    One more constraint: our xml format can be extended with other ns and the
    xsl sheet should be easily extendable (ie by adding only a template that
    could be included if possible).

    My solution (?) currently is (sorry for the length):
    (not working completely :(

    <xsl:template match="/">
    <xsl:apply-templates />
    </xsl:template>

    <!-- ::: start to merge on include only ::: -->
    <xsl:template match="include">
    <!-- try to retrieve the included ndf -->
    <xsl:param name="ndf" select="@definition" />

    <xsl:call-template name="merge-trees">
    <xsl:with-param name="included-ndf" select="document($ndf)/definition" />
    <xsl:with-param name="main-ndf" select="." />
    </xsl:call-template>
    </xsl:template>

    <!-- ::: merge two trees, some elements and attribs can be overridden ::: -->
    <xsl:template name="merge-trees">
    <xsl:param name="included-ndf" />
    <xsl:param name="main-ndf" />

    <xsl:choose>
    <!-- loop recursively on included elements -->
    <xsl:when test="count($included-ndf)&gt;0">
    <xsl:variable name="included-elt" select="$included-ndf[1]" />

    <!-- find overriding element from main -->
    <xsl:variable name="main-elt">
    <xsl:apply-templates select="$main-ndf" mode="find-elem-in-main">
    <xsl:with-param name="ie" select="$included-elt" />
    </xsl:apply-templates>
    </xsl:variable>

    <xsl:choose>
    <!-- handle overriding (if any) -->
    <xsl:when test="boolean($main-elt)">
    <xsl:apply-templates select="exslt:node-set($main-elt)"
    mode="mix-with-main">
    <xsl:with-param name="ie" select="$included-elt" />
    </xsl:apply-templates>

    <!-- recurse on following -->
    <!-- commented because leads to infinite loop :(
    xsl:call-template name="merge-trees">
    <xsl:with-param name="included-ndf"
    select="$included-ndf[position() &gt; 1]" />
    <xsl:with-param name="main-ndf"
    select="$main-ndf[generate-id() !=
    generate-id(exslt:node-set($main-elt))]" />
    </xsl:call-template-->
    </xsl:when>

    <!-- else simply copy current included element -->
    <xsl:eek:therwise>
    <xsl:apply-templates select="." />
    </xsl:eek:therwise>
    </xsl:choose>
    </xsl:when>

    <!-- copy remaining main elements -->
    <xsl:eek:therwise>
    <xsl:apply-templates select="$main-ndf" />
    </xsl:eek:therwise>
    </xsl:choose>
    </xsl:template>

    <!-- ::::::::::: extendable part ::::::::::::
    (we can include similar templates later) -->

    <!-- ::: find the element in main that could override $ie (included element) ::: -->
    <xsl:template match="include" mode="find-elem-in-main">
    <xsl:param name="ie" />

    <xsl:if test="name($ie)='definition'">
    <xsl:copy-of select="." />
    </xsl:if>
    </xsl:template>

    <xsl:template match="param" mode="find-elem-in-main">
    <xsl:param name="ie" />

    <xsl:if test="name($ie)='param' and $ie/@name = @name">
    <xsl:copy-of select="." />
    </xsl:if>
    </xsl:template>

    <!-- ::: merge included element with overriding in main ::: -->
    <xsl:template match="include" mode="mix-with-main">
    <xsl:param name="ie" />

    <xsl:element name="definition">
    <xsl:attribute name="id">
    <xsl:choose>
    <xsl:when test="boolean(@id)">
    <xsl:value-of select="@id" />
    </xsl:when>
    <xsl:when test="boolean($ie/@id)">
    <xsl:value-of select="$ie/@id" />
    </xsl:when>
    <xsl:eek:therwise>
    <xsl:text>undefined</xsl:text>
    </xsl:eek:therwise>
    </xsl:choose>
    </xsl:attribute>

    <xsl:apply-templates select="$ie/@*[name()!='definition' and name()!='id']" />
    <xsl:apply-templates select="@*[name()!='definition' and name()!='id']" />

    <!-- recurse on children -->
    <xsl:call-template name="merge-trees">
    <xsl:with-param name="included-ndf" select="$ie/*" />
    <xsl:with-param name="main-ndf" select="./*" />
    </xsl:call-template>
    </xsl:element>
    </xsl:template>

    <xsl:template match="param" mode="mix-with-main">
    <xsl:param name="ie" />

    <xsl:copy>
    <xsl:apply-templates select="$ie" />
    </xsl:copy>
    </xsl:template>
    <!-- /::::::::::: extendable part :::::::::::: -->

    <!-- ::: copy all others and don't forget attributes ::: -->
    <xsl:template match="node()|@*">
    <xsl:copy>
    <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
    </xsl:template>
    Jean-Christophe Michel, Dec 24, 2003
    #3
  4. Hey,

    ANswering myself to tell i found a solution:

    > <!-- find position of overriding element from main -->
    > <xsl:variable name="main-elt-pos">
    > <xsl:apply-templates select="$main-ndf"
    > mode="find-elem-in-main">
    > <xsl:with-param name="ie" select="$included-elt" />
    > </xsl:apply-templates>
    > </xsl:variable>


    now returns the position() in $main-ndf instead of the element;
    so the recursion call is simply

    > <xsl:with-param name="main-ndf"
    > select="$main-ndf[position() != $main-elt-pos]" />


    All seems possible in xsl, just the time to find it that's long!
    Jean-Christophe Michel, Dec 24, 2003
    #4
  5. "Jean-Christophe Michel" <> wrote in message
    news:p...
    > Hey,
    >
    > ANswering myself to tell i found a solution:
    >
    > > <!-- find position of overriding element from main -->
    > > <xsl:variable name="main-elt-pos">
    > > <xsl:apply-templates select="$main-ndf"
    > > mode="find-elem-in-main">
    > > <xsl:with-param name="ie" select="$included-elt" />
    > > </xsl:apply-templates>
    > > </xsl:variable>

    >
    > now returns the position() in $main-ndf instead of the element;
    > so the recursion call is simply
    >
    > > <xsl:with-param name="main-ndf"
    > > select="$main-ndf[position() != $main-elt-pos]" />

    >
    > All seems possible in xsl, just the time to find it that's long!


    So you see how important it is to try to explain the problem well -- often
    one also finds the solution while doing so ... :eek:)



    Dimitre Novatchev.
    FXSL developer, XML Insider,

    http://fxsl.sourceforge.net/ -- the home of FXSL
    Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html
    Dimitre Novatchev, Jan 5, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Hon Seng Phuah

    Substract numeric from a string.

    Hon Seng Phuah, Feb 25, 2004, in forum: Perl
    Replies:
    3
    Views:
    526
    Joe Smith
    Feb 26, 2004
  2. CBN Media

    DateTime Substract

    CBN Media, Mar 2, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    13,256
    CBN Media
    Mar 2, 2004
  3. Damien
    Replies:
    5
    Views:
    1,081
    Larry Coon
    Dec 10, 2003
  4. Francois Grieu

    Is it conformant to substract two pointer-to-void ?

    Francois Grieu, Mar 12, 2008, in forum: C Programming
    Replies:
    10
    Views:
    587
    Gordon Burditt
    Mar 14, 2008
  5. Dmitry Maksyoma
    Replies:
    0
    Views:
    89
    Dmitry Maksyoma
    May 17, 2006
Loading...

Share This Page