I have problem with write xsl to transform my xml to raport version. It looks like that:
Jo
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kArticleById" match="article"
use="authorId"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<raport>
<xsl:apply-templates select="authors/author"/>
</raport>
</xsl:template>
<xsl:template match="author">
<authorArticles>
<xsl:call-template name="identity"/>
<articles>
<xsl:apply-templates select="key('kArticleById',@id)"/>
</articles>
</authorArticles>
</xsl:template>
<xsl:template match="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="author/@id|articles|authorId"/>
</xsl:stylesheet>
when applied on the provided XML document:
<library>
<authors>
<author id="1001">John</author>
<author id="1002">Tom</author>
</authors>
<articles>
<article>
<authorId>1001</authorId>
<title>Article1</title>
</article>
<article>
<authorId>1002</authorId>
<title>Article2</title>
</article>
<article>
<authorId>1001</authorId>
<title>Article3</title>
</article>
</articles>
</library>
produces the wanted, correct result:
<raport>
<authorArticles>
<author>John</author>
<articles>
<article>Article1</article>
<article>Article3</article>
</articles>
</authorArticles>
<authorArticles>
<author>Tom</author>
<articles>
<article>Article2</article>
</articles>
</authorArticles>
</raport>
Notes:
Use/overriding of the identity rule.
All articles with the same authorId are selected using keys. This is significantly more efficient in case of many authors with many articles.
This XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node() | @*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="library">
<raport>
<xsl:apply-templates select="authors/author"/>
</raport>
</xsl:template>
<xsl:template match="author">
<authorArticles>
<xsl:call-template name="identity"/>
<articles>
<xsl:apply-templates select="../../articles/article[authorId = current()/@id]"/>
</articles>
</authorArticles>
</xsl:template>
<xsl:template match="article">
<xsl:call-template name="identity"/> <!-- In case of more characteristics -->
</xsl:template>
<xsl:template match="title">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="author/@id | authorId"/>
</xsl:stylesheet>
With this XML input:
<library>
<authors>
<author id="1001">John</author>
<author id="1002">Tom</author>
</authors>
<articles>
<article>
<authorId>1001</authorId>
<title>Article1</title>
</article>
<article>
<authorId>1002</authorId>
<title>Article2</title>
</article>
<article>
<authorId>1001</authorId>
<title>Article3</title>
</article>
</articles>
</library>
Provides this needed result:
<raport>
<authorArticles>
<author>John</author>
<articles>
<article>Article1</article>
<article>Article3</article>
</articles>
</authorArticles>
<authorArticles>
<author>Tom</author>
<articles>
<article>Article2</article>
</articles>
</authorArticles>
</raport>
The further optimization might be using keys, but it looks premature with your structure.