2011-05-31 4 views
3

J'ai une XML qui apparaît comme ceBoucler dans XSLT

<Data> 

<MainItem> 
<ItemGroup>Foo</ItemGroup> 
<ItemDetails>Details</ItemDetails> 
</MainItem> 

<MainItem> 
<ItemGroup>Bar</ItemGroup> 
<ItemDetails>Details</ItemDetails> 
</MainItem> 

<MainItem> 
<ItemGroup>Baz</ItemGroup> 
<ItemDetails>Details</ItemDetails> 
</MainItem> 

<OtherData> 
<ItemGroup>Foo</ItemGroup> 
<OtherDataDetails>Blah</OtherDataDetails> 
</OtherData> 

<OtherData> 
<ItemGroup>Bar</ItemGroup> 
<OtherDataDetails>BlahBlah</OtherDataDetails> 
</OtherData> 

<OtherData> 
<ItemGroup>Baz</ItemGroup> 
<OtherDataDetails>BlahBlahBlahBlahBlah</OtherDataDetails> 
</OtherData> 

</Data> 

Ce que je suis en train de transformer quelque chose de similaire à ceci:

Foo 
- Details 
- Blah 

Bar 
- Details 
- BlahBlah 

Baz 
- Details 
- BlahBlahBlahBlahBlah 

en utilisant XSLT 1.0.

J'accomplis actuellement le groupement en faisant quelque chose de similaire au Muenchian method; mais je ne suis pas sûr de savoir comment intégrer les données des tags dans mon groupe. Des conseils?

+0

Pouvez-vous montrer un peu de votre transformation? –

+0

Bonne question, +1. Voir ma réponse pour une solution complète qui est la solution la plus courte et la plus efficace jusqu'à présent, n'utilise pas de conditions ou '' et contient une explication détaillée des points principaux et des liens vers le matériel de référence approprié ou enseigner ces concepts fondamentaux de XSLT. –

Répondre

2

Essayez quelque chose comme ceci:

<?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" /> 

    <xsl:key name="groups" match="//ItemGroup" use="text()" /> 

    <xsl:template match="/"> 
     <Data> 
      <xsl:apply-templates 
       select="//ItemGroup[count(. | key('groups', text())[1]) = 1]" /> 
     </Data> 
    </xsl:template> 

    <xsl:template match="ItemGroup"> 
     <xsl:variable name="text" select="text()" /> 
     <Group><xsl:value-of select="$text" /></Group> 
     <xsl:for-each select="/Data/*[ItemGroup = $text]/*[contains(name(), 'Details')]"> 
      <Detail>- <xsl:value-of select="." /></Detail> 
     </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

Je mis en place un working example pour vous.

+0

+1. J'aime ça parce que c'est plus général alors que la méthode de regroupement est appliquée (même si j'utiliserais 'Group' pour regrouper les éléments' Detail' :) :) –

+0

Complètement révisé ma réponse. L'approche est la même que la vôtre, mais les boucles ne sont pas utilisées. –

2

La solution de regroupement suivante n'utilise pas de boucle et prend en charge tout autre élément de même type après le ItemGroup. De plus, seule une petite clé basée sur MainItem est utilisée pour identifier les groupes.


XSLT 1.0 sous saxon 6.5.5

texte production:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:key name="main" match="MainItem/ItemGroup" use="text()"/> 

    <xsl:template match="/Data"> 
     <xsl:apply-templates select="MainItem"/> 
    </xsl:template> 

    <xsl:template match="MainItem"> 
     <xsl:value-of select="ItemGroup"/><xsl:text>&#xA;</xsl:text> 
     <xsl:apply-templates select="ItemGroup[generate-id(.)=generate-id(key('main', current()/ItemGroup)[1])]"/> 
    </xsl:template> 

    <xsl:template match="ItemGroup"> 
     <xsl:apply-templates select="/Data/*[ItemGroup = current()]/*/following-sibling::*"/> 
     <xsl:text>&#xA;</xsl:text> 
    </xsl:template> 

    <xsl:template match="*"> 
     <xsl:text>- </xsl:text><xsl:value-of select="."/><xsl:text>&#xA;</xsl:text> 
    </xsl:template> 

</xsl:stylesheet> 

Appliqué sur votre entrée, produit:

Foo 
- Details 
- Blah 

Bar 
- Details 
- BlahBlah 

Baz 
- Details 
- BlahBlahBlahBlahBlah 

La production de sortie XML:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:key name="main" match="MainItem/ItemGroup" use="text()"/> 

    <xsl:template match="/Data"> 
     <xsl:copy> 
      <xsl:apply-templates select="MainItem"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="MainItem"> 
     <xsl:variable name="id" select="ItemGroup"/> 
     <Group id="{$id}"> 
      <xsl:apply-templates select="ItemGroup[generate-id(.)=generate-id(key('main', current()/ItemGroup)[1])]"/> 
     </Group> 
    </xsl:template> 

    <xsl:template match="ItemGroup"> 
     <xsl:copy-of select="/Data/*[ItemGroup = current()]/*/following-sibling::*"/> 
    </xsl:template> 

</xsl:stylesheet> 

produit:

<Data> 
    <Group id="Foo"> 
     <ItemDetails>Details</ItemDetails> 
     <OtherDataDetails>Blah</OtherDataDetails> 
    </Group> 
    <Group id="Bar"> 
     <ItemDetails>Details</ItemDetails> 
     <OtherDataDetails>BlahBlah</OtherDataDetails> 
    </Group> 
    <Group id="Baz"> 
     <ItemDetails>Details</ItemDetails> 
     <OtherDataDetails>BlahBlahBlahBlahBlah</OtherDataDetails> 
    </Group> 
</Data> 
+0

Veuillez garder les lignes de code courtes afin qu'aucun défilement horizontal ne soit nécessaire. Maintenant, il est difficile de lire et de comprendre. S'il vous plaît modifier et formater pour plus de lisibilité. –

1

Voici une transformation très courte et la plus efficace qui utilise uniquement des modèles et clés:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text"/> 
<xsl:key name="kGroupByVal" match="ItemGroup" 
    use="."/> 
<xsl:key name="kNonGroupByGroup" 
    match="*[not(self::ItemGroup)]" use="../ItemGroup"/> 

<xsl:template match= 
    "ItemGroup[generate-id() 
      = 
      generate-id(key('kGroupByVal',.)[1]) 
      ] 
    "> 
<xsl:value-of select="concat('&#xA;',.)"/> 

<xsl:apply-templates mode="listGroup" 
    select="key('kNonGroupByGroup',.)"/> 
</xsl:template> 

<xsl:template match="*" mode="listGroup"> 
    <xsl:value-of select="concat('&#xA; - ', .)"/> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

Lorsque appliqué sur le document XML fourni:

<Data> 
    <MainItem> 
     <ItemGroup>Foo</ItemGroup> 
     <ItemDetails>Details</ItemDetails> 
    </MainItem> 
    <MainItem> 
     <ItemGroup>Bar</ItemGroup> 
     <ItemDetails>Details</ItemDetails> 
    </MainItem> 
    <MainItem> 
     <ItemGroup>Baz</ItemGroup> 
     <ItemDetails>Details</ItemDetails> 
    </MainItem> 
    <OtherData> 
     <ItemGroup>Foo</ItemGroup> 
     <OtherDataDetails>Blah</OtherDataDetails> 
    </OtherData> 
    <OtherData> 
     <ItemGroup>Bar</ItemGroup> 
     <OtherDataDetails>BlahBlah</OtherDataDetails> 
    </OtherData> 
    <OtherData> 
     <ItemGroup>Baz</ItemGroup> 
     <OtherDataDetails>BlahBlahBlahBlahBlah</OtherDataDetails> 
    </OtherData> 
</Data> 

le voulait, résultat correct est produit:

Foo 
- Details 
- Blah 
Bar 
- Details 
- BlahBlah 
Baz 
- Details 
- BlahBlahBlahBlahBlah 

** Explication **:

  1. Muenchian grouping pour obtenir les valeurs distinctes de ItemGroup.

  2. Key utilisé pour indexer tous les éléments non ItemGroup par leurs frères et soeurs ItemGroup.

  3. modèle vide correspondant à un noeud quelconque de texte pour empêcher la sortie built-in XSLT template à un noeud quelconque de texte.