Как использовать XSL: ключ для получения следующего-sibling в XSLT 2.0

#xml #xslt #richtext

#xml #xslt #richtext

Вопрос:

У меня есть XML со встроенным форматированием расширенного текста, который выглядит примерно так:

  <?xml version="1.0" encoding="UTF-8"?>
 <document>
     <richtext>
         <pardef/>
         <par><run>This is the </run><run>preamble.</run></par>
         <pardef list='bullet'/>
         <par><run>This is the </run><run>first bullet.</run></par>
         <par><run>This is the second </run><run>bullet.</run></par>
      </richtext>
 </document>
 

Я пытаюсь сгенерировать следующий HTML:

  <p>This is the preamble.</p>
 <ul>
    <li>This is the first bullet</li>
    <li>This is the second bullet</li>
 <ul>
 

Я попробовал следующий XSL, но он не работает. У меня такое чувство, что мне нужно использовать СЛЕДУЮЩИЙ-SIBLING, но я не уверен, как это сделать.

     <xsl:choose>

        <xsl:when test="document/richtext/pardef[@list] ='bullet'">
            <ul>
                <xsl:for-each select="document/richtext/par/run">
                    <li>
                        <xsl:for-each select="run">
                            <xsl:value-of select="."/> 
                        </xsl:for-each>
                    </li>
                </xsl:for-each>   

            </ul>
        </xsl:when>           

        <xsl:otherwise>
            <p>
                <xsl:for-each select="document/richtext/par">
                    <p>
                        <xsl:for-each select="run">
                            <xsl:value-of select="."/> 
                        </xsl:for-each>
                    </p>
                </xsl:for-each>
            </p>
        </xsl:otherwise>    

    </xsl:choose>            
 

Ответ №1:

Один подход с XSLT 2.0 и вашим «дизайном»:

 <?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:key name="key-for-par" match="document/richtext/par" use="generate-id(preceding-sibling::pardef[1])"/>
    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <xsl:apply-templates select="document/richtext/pardef" />
    </xsl:template>

    <xsl:template match="pardef[@list = 'bullet']">
        <ul>
            <xsl:for-each select="key('key-for-par', generate-id(.))">
                <li>
                    <xsl:value-of select="run" separator=""/>
                </li>
            </xsl:for-each>
        </ul>
    </xsl:template>

    <xsl:template match="pardef[not(@list)]">
        <p>
            <xsl:for-each select="key('key-for-par', generate-id(.))">
                <p>
                    <xsl:value-of select="run" separator=""/>
                </p>
            </xsl:for-each>
        </p>
    </xsl:template>

</xsl:stylesheet>
 

ПРАВКА 1: улучшенная версия.

Комментарии:

1. Это сработало! Хотя на самом деле я использую XSLT 2.0, о котором я должен был упомянуть ранее. Имеет ли это значение?

2. Да, это так. Посмотрите на редактирование 1 , есть еще больше способов решения.

3. Еще раз спасибо! Можете ли вы пояснить, почему группировка необходима? В прошлом я создавал таблицы стилей XSLT с группировкой, но мне пришлось бы немного переделать, чтобы включить группировку в эту.

4. Оси «следующий-sibling» или «предыдущий-sibling» недостаточно, потому что, например, элемент <par>.. this is the second по-прежнему является следующим-sibling первого pardef . Мы должны остановиться, когда возникает новое pardef . Ключ в моей группе решений по этой технологии. Также была бы истинная функция xslt 2.0 xsl:for-each-group . Много способов пойти 🙂