I am wondering does the statement [@id=current()/@id]
can only work if the id is integer for example:
<elem id="1">
<elem id="1">
But if I have:
<elem id="AAA">
<elem id="AAA">
It does not work.
My XSL where it fails:
<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>
input sample where it works:
<root>
<library id="L1">
<genre id="a">
<shelf1 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="1" action="extend">
<attributes>
<length>2</length>
<condition>ok</condition>
</attributes>
<other3>y</other3>
</book>
<book id="2" action="extend">
<attributes>
<length>99</length>
<condition>not-ok</condition>
</attributes>
<other>y</other>
</book>
</shelf1>
<shelf1 id="b">...
</shelf1>
</genre>
<genre id="b">...
</genre>
</library>
</root>
If I change the id of the book to 1a
:
<root>
<library id="L1">
<genre id="a">
<shelf1 id="1">
<book id="1a" action="borrow">
<attributes>
<user>John</user>
</attributes>
<other1>y</other1>
</book>
<book id="1a" action="extend">
<attributes>
<user>Woo</user>
<length>3</length>
</attributes>
<other2>y</other2>
</book>
<book id="1a" action="extend">
<attributes>
<length>2</length>
<condition>ok</condition>
</attributes>
<other3>y</other3>
</book>
<book id="2" action="extend">
<attributes>
<length>99</length>
<condition>not-ok</condition>
</attributes>
<other>y</other>
</book>
</shelf1>
<shelf1 id="b">...
</shelf1>
</genre>
<genre id="b">...
</genre>
</library>
</root>
My Error Output: (it doesn't merge at all)
<root>
<library id="L1">
<genre id="a">
<shelf1 id="1">
<book id="a1" action="borrow">
<attributes>
<user>John</user>
</attributes>
<other1>y</other1>
</book>
<book id="a1" action="extend">
<attributes>
<user>Woo</user>
<length>3</length>
</attributes>
<other2>y</other2>
</book>
<book id="a1" action="extend">
<attributes>
<length>2</length>
<condition>ok</condition>
</attributes>
<other3>y</other3>
</book>
<book id="2" action="extend">
<attributes>
<length>99</length>
<condition>not-ok</condition>
</attributes>
<other>y</other>
</book>
</shelf1>
<shelf1 id="b">...
</shelf1>
</genre>
<genre id="b">...
</genre>
</library>
</root>
Expected Output:
<root>
<library id="L1">
<genre id="a">
<shelf1 id="1">
<book id="1a" action="borrow">
<attributes>
<user>Woo</user>
<length>2</length>
<condition>ok</condition>
</attributes>
<other1>y</other1>
</book>
<book id="2" action="extend">
<attributes>
<length>99</length>
<condition>not-ok</condition>
</attributes>
<other>y</other>
</book>
</shelf1>
<shelf1 id="b">...
</shelf1>
</genre>
<genre id="b">...
</genre>
</library>
</root>
For every node 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
THe merging only happen with node that has the same id.
Thanks. Regards, John