Re: [xsl] How to merge XML node including all the corresponding children with unique element and latest value?

Subject: Re: [xsl] How to merge XML node including all the corresponding children with unique element and latest value?
From: Lucent Lau <lucent.lau@xxxxxxxxx>
Date: Wed, 18 Jul 2012 02:22:02 +0700
Here is my code.
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                xmlns:xs="http://www.w3.org/2001/XMLSchema";
                xmlns:fn="http://www.w3.org/2005/xpath-functions";
                xmlns:tn="http://";
                exclude-result-prefixes="xsl xs fn tn">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*" />

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

 <xsl:template match="genre/*">
        <xsl:copy>
            <xsl:apply-templates select="@*" />

            <xsl:apply-templates select="
     book[@id=current()/@id][@action='extend']
         [not( preceding-sibling::book[@id=current()/@id][@action='borrow'])]"
/>

            <xsl:for-each-group
                select="book[@id=current()/@id][@action='borrow']
             |
            book[@id=current()/@id][@action='extend']
                [preceding-sibling::book[@id=current()/@id][@action='borrow']]"
                group-starting-with="book[@action='borrow']">
                <xsl:for-each select="current-group()[1]">
                    <xsl:copy>
                        <xsl:apply-templates select="@*" />
                        <xsl:call-template name="merge-books-deeply">
                            <xsl:with-param name="books"
select="current-group()" />
                            <xsl:with-param name="name-path" select="()" />
                        </xsl:call-template>
                    </xsl:copy>
                </xsl:for-each>
            </xsl:for-each-group>

            <xsl:apply-templates select="
     node()[ not(
self::book[@id=current()/@id][@action=('borrow','extend')])]" />

        </xsl:copy>
    </xsl:template>

    <xsl:function name="tn:children-on-path" as="element()*">
        <xsl:param name="base" as="element()*" />
        <xsl:param name="path" as="xs:string*" />
        <xsl:choose>
            <xsl:when test="fn:empty($base)">
                <xsl:sequence select="()" />
            </xsl:when>
            <xsl:when test="fn:empty($path)">
                <xsl:copy-of select="$base/*" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:sequence select="tn:children-on-path(
     $base/*[name()=$path[1]],
     $path[position() ne 1])" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>

    <xsl:template name="merge-books-deeply">
        <xsl:param name="books" as="element()*" />
        <xsl:param name="name-path" as="xs:string*" />
        <xsl:for-each-group
            select="tn:children-on-path($books,$name-path)"
            group-by="name()">
            <xsl:for-each select="current-group()[last()]" >
                <xsl:copy>
                    <xsl:apply-templates select="@*" />
                    <xsl:call-template name="merge-books-deeply">
                        <xsl:with-param name="books" select="$books" />
                        <xsl:with-param name="name-path"
select="$name-path,name()" />
                    </xsl:call-template>
                    <xsl:apply-templates select="text()" />
                </xsl:copy>
            </xsl:for-each>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

The problem is that if i change all the book id to '1a' the code wont
work, could you point me to the right direction?
Thanks

On Tue, Jul 17, 2012 at 2:42 PM, Michel Hendriksen
<michel.hendriksen@xxxxx> wrote:
> Can;'t you try first?
>
> On Mon, Jul 16, 2012 at 6:54 PM, Lucent Lau <lucent.lau@xxxxxxxxx> wrote:
>> I have this XSL:
>> <root>
>>     <library id="L1">
>>         <floor1 id="1">
>>             <shelf id="1">
>>                 <book id="1" action="borrow">
>>                     <attributes>
>>                         <user>John</user>
>>                     </attributes>
>>                     <other1>y</other1>
>>                 </book>
>>                 <book id="1" action="extend">
>>                     <attributes>
>>                         <user>Woo</user>
>>                         <length>3</length>
>>                     </attributes>
>>                     <other2>y</other2>
>>                 </book>
>>                 <book id="2" action="extend">
>>                     <attributes>
>>                         <length>2</length>
>>                         <condition>ok</condition>
>>                     </attributes>
>>                     <other3>y</other3>
>>                 </book>
>>             </shelf>
>>             <shelf id="2">
>>         </floor1>
>>         <floor1 id="2">..</floor1>
>>     </library>
>> </root>
>>
>> Output:
>> <root>
>>     <library id="L1">
>>         <floor1 id="1">
>>             <shelf id="1">
>>                 <book id="1" action="borrow">
>>                     <attributes>
>>                         <user>Woo</user>
>>                         <length>3</length>
>>                     </attributes>
>>                     <other1>y</other1>
>>                     <other2>y</other2>
>>                 </book>
>>
>>                 <book id="2" action="extend">
>>                     <attributes>
>>                         <length>2</length>
>>                         <condition>ok</condition>
>>                     </attributes>
>>                     <other3>y</other3>
>>                 </book>
>>             </shelf>
>>             <shelf id="2">
>>         </floor1>
>>         <floor1 id="2">..</floor1>
>>     </library>
>> </root>
>>
>> I need to combine the node such that For every node that has the same
>> id with action=borrow followed by one or more node with action=extend
>>
>>     Merge it together to the node with action=borrow.
>>     Merge the attributes children together such that it will have all
>> the unique attributes from the siblings with the latest value.
>>     leave other children unchanged
>>
>> Please let me know how to fix this transformation using XSLT 2.0 ?
>>
>> Thanks very much.
>> LL

Current Thread