2010-08-17 3 views
2

XML:Алфавит шаблон индекс: "XSL: ключ" проблема матч

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

мне нужно сделать алфавит индекс, как это:

alt text

Я получаю шаблон отсюда: link text

Моя проблема: для каждого mode должен быть свой собственный список «Алфавит» (для одного режима он отлично работает).

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> 

Этот код не работает правильно. Это должно быть исправлено, как это:

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

Но это очень криво решение.

Как решить эту проблему более элегантно?


Dimitre Novatchev, не бейте меня за "неточностей", я отрекаюсь от руки)).

+1

+1 для прошения милосердия от Dimitre :) – Oded

+0

Хороший вопрос (+1). См. Мой ответ для решения, которое демонстрирует использование метода Muenchian для группировки с составными ключами. –

ответ

1

Это преобразование:

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

при нанесении на этом 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> 

производит хотел индексы для каждого <mode> (не formatization в HTML не делается) :

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

Примечание: Метод Muenchian для группировки используется с составным ключом, который содержит как положение режима, так и имя термина.

1

При правильном входе:

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

Эта таблица стилей:

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

Выход:

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

Примечание: Теперь ваш ключ включает mode элемент предка, так что вы нужно ссылаться на это в свой ключ.

EDIT: Miss alfabetic order. Сожалею.

Смежные вопросы