2010-08-17 21 views
2

XML:modèle d'index alphabétique: "xsl: key" problème de correspondance

<?xml version="1.0" encoding="windows-1251"?> 
    <mode> 
     <term> 
      <name>abhdk</name> 
     </term> 
     <term> 
      <name>njhjsu</name> 
     </term> 

     <term> 
      <name>sdasd</name> 
     </term> 
     <term> 
      <name>vbvbcd</name> 
     </term> 
      ... 
    </mode> 
    <mode> 
     <term> 
      <name>asdfd</name> 
     </term> 
     <term> 
      <name>vcbbn</name> 
     </term> 
     <term> 
      <name>bnmbnmb</name> 
     </term> 
     <term> 
      <name>tyutyu</name> 
     </term> 
     <term> 
      <name>ghjghj</name> 
     </term> 
     <term> 
      <name>hjk</name> 
     </term> 
      ... 
    </mode> 
    <mode> 
     <term> 
      <name>asdfd</name> 
     </term> 
     <term> 
      <name>vcbbn</name> 
     </term> 
    </mode> 
    ... 

que je dois faire l'index alphabétique comme ceci:

alt text

Je reçois modèle à partir d'ici: link text

Mon problème: pour chaque mode il doit y avoir sa propre liste "Alphabet index" (pour le mode simple, cela fonctionne parfaitement).

XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" indent="no" encoding="windows-1251"/> 

    <xsl:for-each select="mode"> 
     <xsl:call-template name="alphabetIndexTmpl"> 
      <xsl:with-param name="key-name" select="'items-key'" /> 
      ... 
     </xsl:call-template> 
    </xsl:for-each> 

    <xsl:key name="items-key" match="term" use="substring(., 1, 1)" /> 

    <xsl:template name="alphabetIndexTmpl">   
     <xsl:param name="key-name"/> 
     ... 
    </xsl:template> 
</xsl:stylesheet> 

Ce code ne fonctionne pas correctement. Il doit être corrigé comme ceci:

<?xml version="1.0" encoding="windows-1251"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" indent="no" encoding="windows-1251"/> 

    <xsl:for-each select="mode"> 
     <xsl:call-template name="alphabetIndexTmpl"> 
      <xsl:with-param name="key-name" select="concat('items-key', position())" /> 
      ... 
     </xsl:call-template> 
    </xsl:for-each> 

    <xsl:key name="items-key1" match="mode[1]/term" use="substring(., 1, 1)" /> 
    <xsl:key name="items-key2" match="mode[2]/term" use="substring(., 1, 1)" /> 
    <xsl:key name="items-key3" match="mode[2]/term" use="substring(., 1, 1)" /> 
    ... 

    <xsl:template name="alphabetIndexTmpl">   
     <xsl:param name="key-name"/> 
     ... 
    </xsl:template> 

</xsl:stylesheet> 

Mais il est décision très tordu.

Comment résoudre ce problème de façon plus élégante?


Dimitre Novatchev, ne me battez pas vers le bas pour "inexactitudes", je rends mes bras)).

+1

+ 1 pour demander la pitié de Dimitre :) – Oded

+0

Bonne question (+1). Voir ma réponse pour une solution qui démontre l'utilisation de la méthode Muenchian pour le regroupement avec des clés composites. –

Répondre

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="kByMode-StartCharAndModPos" match="term" 
    use="concat(count(../preceding-sibling::mode), 
       '+', 
       substring(name,1,1) 
      )"/> 

<xsl:template match="node()|@*" mode="identity"> 
    <xsl:copy> 
    <xsl:apply-templates mode="identity" 
    select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/*"> 
    <modes> 
    <xsl:apply-templates/> 
    </modes> 
</xsl:template> 

<xsl:template match="mode"> 
    <mode pos="{position()}"> 
     <xsl:apply-templates select= 
     "term[generate-id() 
      = 
      generate-id(key('kByMode-StartCharAndModPos', 
           concat(count(../preceding-sibling::mode), 
            '+', 
            substring(name,1,1) 
            ) 
          )[1] 
         ) 
      ]"> 
    <xsl:sort select="substring(name,1,1)"/> 
    </xsl:apply-templates> 
    </mode> 
</xsl:template> 

<xsl:template match="term"> 
    <starting letter="{substring(name,1,1)}"> 
    <xsl:apply-templates mode="identity" select= 
    "key('kByMode-StartCharAndModPos', 
      concat(count(../preceding-sibling::mode), 
        '+', 
        substring(name,1,1) 
        ) 
      ) 
    "/> 
    </starting> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué sur ce document XML:

<modes> 
    <mode> 
     <term> 
      <name>Adams</name> 
     </term> 
     <term> 
      <name>Allen</name> 
     </term> 
     <term> 
      <name>Brooks</name> 
     </term> 
     <term> 
      <name>Cameron</name> 
      <name>Campbell</name> 
     </term> 
    </mode> 
    <mode> 
     <term> 
      <name>Apple</name> 
     </term> 
     <term> 
      <name>Egan</name> 
      <name>Elkin</name> 
     </term> 
     <term> 
      <name>Fisher</name> 
      <name>Foster</name> 
     </term> 
     <term> 
      <name>Hall</name> 
     </term> 
     <term> 
      <name>ghjghj</name> 
     </term> 
     <term> 
      <name>Jackson</name> 
     </term> 
    </mode> 
    <mode> 
     <term> 
      <name>Lewis</name> 
     </term> 
     <term> 
      <name>Murray</name> 
      <name>Myers</name> 
     </term> 
    </mode> 
</modes> 

produit les indices recherchés pour chaque <mode> (pas formatization en html est fait) :

<modes> 
    <mode pos="1"> 
     <starting letter="A"> 
      <term> 
       <name>Adams</name> 
      </term> 
      <term> 
       <name>Allen</name> 
      </term> 
     </starting> 
     <starting letter="B"> 
      <term> 
       <name>Brooks</name> 
      </term> 
     </starting> 
     <starting letter="C"> 
      <term> 
       <name>Cameron</name> 
       <name>Campbell</name> 
      </term> 
     </starting> 
    </mode> 
    <mode pos="2"> 
     <starting letter="A"> 
      <term> 
       <name>Apple</name> 
      </term> 
     </starting> 
     <starting letter="E"> 
      <term> 
       <name>Egan</name> 
       <name>Elkin</name> 
      </term> 
     </starting> 
     <starting letter="F"> 
      <term> 
       <name>Fisher</name> 
       <name>Foster</name> 
      </term> 
     </starting> 
     <starting letter="g"> 
      <term> 
       <name>ghjghj</name> 
      </term> 
     </starting> 
     <starting letter="H"> 
      <term> 
       <name>Hall</name> 
      </term> 
     </starting> 
     <starting letter="J"> 
      <term> 
       <name>Jackson</name> 
      </term> 
     </starting> 
    </mode> 
    <mode pos="3"> 
     <starting letter="L"> 
      <term> 
       <name>Lewis</name> 
      </term> 
     </starting> 
     <starting letter="M"> 
      <term> 
       <name>Murray</name> 
       <name>Myers</name> 
      </term> 
     </starting> 
    </mode> 
</modes> 

A noter: La méthode Muenchienne de regroupement est utilisée avec une clé composée qui contient à la fois la position du mode et le nom du terme.

1

Avec l'entrée correcte:

<modes> 
    <mode> 
     <term> 
      <name>abhdk</name> 
     </term> 
     <term> 
      <name>njhjsu</name> 
     </term> 
     <term> 
      <name>sdasd</name> 
     </term> 
     <term> 
      <name>vbvbcd</name> 
     </term> 
    </mode> 
    <mode> 
     <term> 
      <name>asdfd</name> 
     </term> 
     <term> 
      <name>vcbbn</name> 
     </term> 
     <term> 
      <name>bnmbnmb</name> 
     </term> 
     <term> 
      <name>tyutyu</name> 
     </term> 
     <term> 
      <name>ghjghj</name> 
     </term> 
     <term> 
      <name>hjk</name> 
     </term> 
    </mode> 
    <mode> 
     <term> 
      <name>asdfd</name> 
     </term> 
     <term> 
      <name>vcbbn</name> 
     </term> 
    </mode> 
</modes> 

Cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="html" indent="no" encoding="windows-1251"/> 
    <xsl:key name="ByModeAndFirst" match="name" use="concat(generate-id(../..),'&amp;',substring(.,1,1))"/> 
    <xsl:template match="modes"> 
     <html> 
      <body> 
       <xsl:apply-templates/> 
      </body> 
     </html> 
    </xsl:template> 
    <xsl:template match="mode"> 
     <div> 
     <xsl:apply-templates> 
      <xsl:sort select="name"/> 
     </xsl:apply-templates> 
     </div> 
    </xsl:template> 
    <xsl:template match="term"/> 
    <xsl:template match="term[name[count(.|key('ByModeAndFirst',concat(generate-id(../..),'&amp;',substring(.,1,1)))[1])=1]]"> 
     <dl> 
      <dt> 
       <xsl:value-of select="substring(name,1,1)"/> 
      </dt> 
      <dd> 
       <xsl:apply-templates select="key('ByModeAndFirst',concat(generate-id(..),'&amp;',substring(name,1,1)))"/> 
      </dd> 
     </dl> 
    </xsl:template> 
    <xsl:template match="name"> 
     <p> 
      <xsl:value-of select="."/> 
     </p> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<html> 
    <body> 
     <div> 
      <dl> 
       <dt>a</dt> 
       <dd> 
        <p>abhdk</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>n</dt> 
       <dd> 
        <p>njhjsu</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>s</dt> 
       <dd> 
        <p>sdasd</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>v</dt> 
       <dd> 
        <p>vbvbcd</p> 
       </dd> 
      </dl> 
     </div> 
     <div> 
      <dl> 
       <dt>a</dt> 
       <dd> 
        <p>asdfd</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>v</dt> 
       <dd> 
        <p>vcbbn</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>b</dt> 
       <dd> 
        <p>bnmbnmb</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>t</dt> 
       <dd> 
        <p>tyutyu</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>g</dt> 
       <dd> 
        <p>ghjghj</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>h</dt> 
       <dd> 
        <p>hjk</p> 
       </dd> 
      </dl> 
     </div> 
     <div> 
      <dl> 
       <dt>a</dt> 
       <dd> 
        <p>asdfd</p> 
       </dd> 
      </dl> 
      <dl> 
       <dt>v</dt> 
       <dd> 
        <p>vcbbn</p> 
       </dd> 
      </dl> 
     </div> 
    </body> 
</html> 

Remarque: Maintenant, votre clé implique l'ancêtre de l'élément mode, de sorte que vous besoin de référencer cela dans votre clé.

EDIT: Manque l'ordre alfabétique. Pardon.