2010-12-14 8 views
2

J'ai un problème avec write xsl pour transformer mon xml en version raport. On dirait que:Transformation XSLT en XML, regroupement par clé

<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> 

Je veux Tranform à:

<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> 

Je idée d'utiliser pour chacun, sur des ids dans auteurs et neasted pour les articles, mais je ne sais pas comment pour le faire. Quelqu'un sait comment faire cette transformation?

+0

Bonne question, +1. Voir ma réponse pour une solution complète et efficace démontrant l'utilisation des clés. :) –

Répondre

1

Ce 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> 

Avec cette entrée XML:

<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> 

Fournit ce résultat nécessaire:

<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> 

L'une optimisation plus poussée peut-être à l'aide des touches, mais il semble prématuré avec ta structure.

+0

grand thx eu ceci :) – niceNick44

1

Cette 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> 

lorsqu'il est appliqué sur le document XML fourni:

<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> 

produit le résultat souhaité, correct:

<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> 

Remarques:

  1. Utilisation/Primauté identité.

  2. Tous les articles ayant la même ID d'auteur sont sélectionnés à l'aide des touches. Ceci est nettement plus efficace dans le cas de nombreux auteurs avec de nombreux articles.

Questions connexes