2009-02-21 11 views
7

J'ai un fichier XML d'entrée que j'ai besoin de copier 1: 1 à la sortie, sauf pour un sous-élément qui contient des sous-éléments qui doivent être triés.Comment trier un sous-élément de XML avec XSLT

<?xml version="1.0"?> 
<top> 
    <elementA /> 
    <elementB /> 
    <contents> 
     <contentitem> 
      <id>3</id> 
      <moretags1 /> 
      <moretags2 /> 
     </contentitem> 
     <contentitem> 
      <id>2</id> 
      <moretags1 /> 
      <moretags2 /> 
     </contentitem> 
     <contentitem> 
      <id>1</id> 
      <moretags1 /> 
      <moretags2 /> 
     </contentitem> 
    </contents> 
</top> 

Je voudrais une transformation XSL qui met les éléments « contentItem » afin, triés par leurs éléments « id ». Tous les autres tags, y compris ceux imbriqués, doivent être copiés textuellement. J'ai déjà essayé avec xsl: copy, mais soit j'ai un double contenu, soit il manque quelque chose.

Répondre

7

solution de Mark Gravell est presque correct - avec un léger problème qui crée deux éléments imbriqués <contents>. Note à tous ceux qui fournissent des réponses: Testez vos solutions!

Voici une solution correcte. 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:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
    </xsl:template> 
<!--            --> 
    <xsl:template match="contents"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="contentitem"> 
     <xsl:sort select="id" data-type="number"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

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

<top> 
    <elementA /> 
    <elementB /> 
    <contents> 
     <contentitem> 
      <id>3</id> 
      <moretags1 /> 
      <moretags2 /> 
     </contentitem> 
     <contentitem> 
      <id>2</id> 
      <moretags1 /> 
      <moretags2 /> 
     </contentitem> 
     <contentitem> 
      <id>1</id> 
      <moretags1 /> 
      <moretags2 /> 
     </contentitem> 
    </contents> 
</top> 

produit le résultat souhaité, correct:

<top> 
    <elementA/> 
    <elementB/> 
    <contents> 
     <contentitem> 
     <id>1</id> 
     <moretags1/> 
     <moretags2/> 
     </contentitem> 
     <contentitem> 
     <id>2</id> 
     <moretags1/> 
     <moretags2/> 
     </contentitem> 
     <contentitem> 
     <id>3</id> 
     <moretags1/> 
     <moretags2/> 
     </contentitem> 
    </contents> 
</top> 

Prenez note de la suivant:

  1. L'utilisation du identity rule pour copier tous les nœuds sans changement.

  2. Comment le modèle d'identité est surchargée avec un modèle spécifique correspondant à l'élément contents

  3. L'utilisation de l'instruction <xsl:sort> pour présenter les résultats de l'application d'un modèle dans un ordre spécifique, peut-être différent de l'ordre des documents des nœuds, sélectionnés pour le traitement.

0

Utilisez xsl: sort soit avec xsl: for-each ou xsl: apply-templates

Quelque chose comme

<xsl:template match='/top/contents'> 
    <xsl:apply-templates select='contentitem'> 
    <xsl:sort select='id' data-type='number'/> 
    </xsl:apply-templates> 
</xsl:template> 

xsl multiples: éléments de tri peut être utilisé pour les clés de tri multiples.

+0

Notez que vous avez pas écrit l'élément , ni aucun attribut sur elle ... –

+0

Ce n'est pas une solution complète, plutôt concentré sur la façon de trier. – Richard

2

Que diriez-vous:

<?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()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 
    <xsl:template match="/top/contents"> 
    <contents> 
     <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:apply-templates select="contentitem"> 
      <xsl:sort data-type="number" select="id"/> 
     </xsl:apply-templates> 
     </xsl:copy> 
    </contents> 
    </xsl:template> 
</xsl:stylesheet>