2009-06-26 9 views
3

Comment puis-je convertir les éléments suivants à l'aide xsltTransformation XSLT avec le comte

<blogger> 
    <post> 
    <text>...</text> 
    <categories>Engineering, Internet, Sausages</catgories> 
    </post> 
    <post> 
    <text>...</text> 
    <categories>Internet, Sausages</catgories> 
    </post> 
    <post> 
    <text>...</text> 
    <categories>Sausages</catgories> 
    </post> 
</blogger> 

dans

Sausages (3) 
    Internet (2) 
    Engineering (1) 
+0

nous montrer votre tentative ..... –

+0

j'ai essayé et échoué mal. – Skiltz

+0

Pourquoi n'avez-vous même pas publié de XML valide? Je veux dire ... c'est une question de couper-coller ... – Tomalak

Répondre

2

D'abord, changer votre xml

créer data.xml

<blogger> 
<post> 
    <text>...</text> 
    <categories> 
     <category>Engineering</category> 
     <category>Internet</category> 
     <category>Sausages</category> 
    </categories>   
</post> 
<post> 
    <text>...</text> 
     <categories> 
     <category>Internet</category> 
     <category>Sausages</category> 
     </categories>  
    </post> 
<post> 
    <text>...</text> 
    <categories> 
     <category>Sausages</category> 
    </categories> 
</post> 
</blogger> 

Ensuite, écrivez votre xslt, créez transform.xslt

<?xml version="1.0" encoding="iso-8859-1"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="text"/> 

<xsl:template match="/"> 

    <xsl:for-each select="//category"> 
    <xsl:variable name="value" select="."/> 
    <xsl:if test="count(preceding::category[.=$value]) = 0"> 
    <xsl:value-of select="."/> 
    <xsl:text> (</xsl:text> 
    <xsl:value-of select="count(//category[.=$value])"/>  
    <xsl:text>)</xsl:text><br/> 
    </xsl:if> 
</xsl:for-each> 

</xsl:template> 
</xsl:stylesheet> 

Ensuite, vous pouvez ouvrir data.xml dans Internet Explorer et obtenir le résultat suivant:

Engineering (1)Internet (2)Sausages (3)
+0

Malheureusement je ne peux pas changer la structure du XML tel qu'il vient d'ailleurs. – Skiltz

+0

Il n'est pas logique (pour moi au moins) d'avoir votre structure XML existante. Pouvez-vous demander à votre fournisseur de sources xml de changer leur XML? Sinon, vous pouvez pré-traiter/affiner votre XML pour obtenir ce dont vous avez besoin pour exécuter le xslt requis. – Makach

+0

thats cool ... juste une dernière pensée voulait les trier plus haut au plus bas? 3 2 1 etc – Skiltz

2

Qu'est-ce que vous avez besoin est ceci:

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 

    <xsl:template match="/"> 
    <items> 
     <xsl:apply-templates select="/blogger/post/categories" /> 
    </items> 
    </xsl:template> 

    <xsl:template match="categories"> 
    <xsl:call-template name="split"> 
     <xsl:with-param name="pString" select="." /> 
    </xsl:call-template> 
    </xsl:template> 

    <!-- this splits a comma-delimited string into a series of <item>s --> 
    <xsl:template name="split"> 
    <xsl:param name="pString" select="''" /> 

    <xsl:variable name="vList" select=" 
     concat($pString, ',') 
    " /> 
    <xsl:variable name="vHead" select=" 
     normalize-space(substring-before($vList ,',')) 
    " /> 
    <xsl:variable name="vTail" select=" 
     normalize-space(substring-after($vList ,',')) 
    " /> 

    <xsl:if test="not($vHead = '')"> 
     <item> 
     <xsl:value-of select="$vHead" /> 
     </item> 
     <xsl:call-template name="split"> 
     <xsl:with-param name="pString" select="$vTail" /> 
     </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

qui produit ce résultat intermédiaire:

<items> 
    <item>Engineering</item> 
    <item>Internet</item> 
    <item>Sausages</item> 
    <item>Internet</item> 
    <item>Sausages</item> 
    <item>Sausages</item> 
</items> 

Et ceci:

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 

    <xsl:output method="text" /> 
    <xsl:key name="kItem" match="item" use="." /> 

    <xsl:template match="/items"> 
    <xsl:apply-templates select="item"> 
     <xsl:sort 
     select="count(key('kItem', .))" 
     data-type="number" 
     order="descending" 
     /> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:if test=" 
     generate-id() = generate-id(key('kItem', .)[1]) 
    "> 
     <xsl:value-of select=" 
     concat(
      ., ' (', count(key('kItem', .)), ')&#10;' 
     ) 
     " /> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet> 

qui sort:

Sausages (3) 
Internet (2) 
Engineering (1) 
1

En fait, il peut être fait et n'est pas difficile non plus. Cela fera ce que vous voulez qu'il fasse:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="fo msxsl"> 
    <xsl:output encoding="UTF-8" indent="yes" method="xml"/> 
    <xsl:variable name="Separator">,</xsl:variable> 
    <xsl:template match="/"> 
    <xsl:variable name="NodeList"> 
     <xsl:apply-templates select="//categories"/> 
    </xsl:variable> 
    <xsl:variable name="Nodes" select="msxsl:node-set($NodeList)"/> 
    <html> 
     <head> 
     <title>Simple list</title> 
     </head> 
     <body> 
     <xsl:for-each select="$Nodes/Value"> 
      <xsl:variable name="value" select="."/> 
      <xsl:if test="count(preceding::Value[.=$value]) = 0"> 
      <xsl:value-of select="."/> (<xsl:value-of select="count($Nodes/Value[.=$value])"/>)<br/> 
      </xsl:if> 
     </xsl:for-each> 
     </body> 
    </html> 
    </xsl:template> 
    <xsl:template match="categories" name="Whole"> 
    <xsl:call-template name="Substring"> 
     <xsl:with-param name="Value" select="normalize-space(.)"/> 
    </xsl:call-template> 
    </xsl:template> 
    <xsl:template name="Substring"> 
    <xsl:param name="Value"/> 
    <xsl:choose> 
     <xsl:when test="contains($Value, $Separator)"> 
     <xsl:variable name="Before" select="normalize-space(substring-before($Value, $Separator))"/> 
     <xsl:variable name="After" select="normalize-space(substring-after($Value, $Separator))"/> 
     <Value> 
      <xsl:value-of select="$Before"/> 
     </Value> 
     <xsl:call-template name="Substring"> 
      <xsl:with-param name="Value" select="$After"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <Value> 
      <xsl:value-of select="$Value"/> 
     </Value> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

En fait, c'est un morceau de gâteau. :-)

+0

Doit ajouter que ce code fonctionne avec MXSML. Si vous utilisez un autre processeur XSLT, vous avez besoin d'une autre solution pour transformer une variable en un ensemble de nœuds. (. Bien que certains processeurs ne ont pas besoin de tels convertions) –

+0

Mais ce n'est pas le tri sur le groupe comptent soit - une opération en deux étapes est nécessaire pour le faire. – Tomalak

+0

Oh, je viens de remarquer: le nom du modèle (« Whole ») est inutile. – Tomalak

Questions connexes