Генерация нескольких динамических строк html-таблицы с использованием XSLT

#xml #xslt

#xml #xslt

Вопрос:

Я хочу создавать строки в таблице динамически в зависимости от содержимого в XML. В приведенном ниже коде я пытаюсь создать строку ( <tr> ) с 5 столбцами. После заполнения 5 столбцов я хочу создать новую строку.

Строка может содержать только 5 столбцов в соответствии с приведенным ниже кодом. Если я применяю XSL к XML, я получаю сообщение об ошибке, отображающее

Ошибка компиляции XSLT. Начальный тег ‘tr’ в строке 574 не совпадает с конечным тегом ‘xsl:when’. Строка 578, позиция 7.

 570:<table>
571:    <xsl:for-each select="/alert/account_links/account_links_info">
572:                <xsl:choose>
573:                <xsl:when test="position() mod 5 = 1">
574:                    <tr>
575:                        <td>
576:                            <xsl:value-of select="account_id"/>
577:                        </td>                           
578:                </xsl:when>
579:                <xsl:when test="position() mod 5 = 0">
580:                    <td>
581:                        <xsl:value-of select="account_id"/>
582:                    </td>
583:                    </tr>
584:                </xsl:when>
585:                <xsl:otherwise>
586:                    <td>
587:                        <xsl:value-of select="account_id"/>
588:                    </td>
589:                </xsl:otherwise>
590:                </xsl:choose>
591:                </xsl:for-each>         
592:            </table>
  

Ввод Xml:

 <?xml version="1.0" encoding="utf-8" standalone="no"?>
<alert>
  <account_links>
    <account_links_info>
      <account_id>1</account_id>
    </account_links_info>
    <account_links_info>
      <account_id>2</account_id>
    </account_links_info>
    <account_links_info>
      <account_id>3</account_id>
    </account_links_info>
    <account_links_info>
      <account_id>4</account_id>
    </account_links_info>
    <account_links_info>
      <account_id>5</account_id>
    </account_links_info>
  </account_links>
</alert>
  

Может ли кто-нибудь помочь мне, как продолжить это?

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

1. Ваш «XML» неправильно сформирован: в нем отсутствует закрывающий элемент tr после закрывающего td в строке 577, и в нем отсутствует открывающий элемент tr перед открывающим td в строке 580. Даже в этом случае генерируемая структура не является допустимой таблицей XHTML. Было бы полезно, если бы вы опубликовали образец того, чего вы хотели достичь (предпочтительно с образцом того, что вы вводите).

2. Никто не сможет вам помочь без образца вашего ввода и желаемого результата.

3. <? версия xml = «1.0» кодировка = «utf-8″ автономный =»нет»?> <оповещение> <account_links> <account_links_info> <account_id>1</account_id> </account_links_info> <account_links_info> <account_id>2</account_id> </account_links_info> <account_links_info> <account_id>3</account_id> </ account_links_info> <account_links_info> <account_id> 4</account_id> </account_links_info> <account_links_info> <account_id>5</account_id> </account_links_info> </alert>

4. Я хочу знать, как написать код XSL для отображения идентификаторов учетной записи в приведенном выше xml в HTML-таблице, где каждая строка содержит 5 столбцов….

5. Пожалуйста, отредактируйте свой пост, чтобы включить входной XML, не добавляйте его в качестве комментария. Кстати, XML в комментарии неправильно сформирован.

Ответ №1:

Попробуйте это решение:

 <table>
       <xsl:for-each select="/alert/account_links/account_links_info[position()mod5=1]">
        <xsl:variable name = "current-pos" select="(position()-1) * 5 1"/>
        <tr>
        <xsl:for-each select="../account_links_info[position()amp;>=$current-pos and position() amp;< $current-pos 5]" >
            <td>
                <xsl:value-of select="account_id"/>
            </td>
        </xsl:for-each>
        </tr>           
       </xsl:for-each>         
</table>
  

(идея состоит в том, чтобы иметь внешний цикл для <tr> вывода, проходящий через каждый пятый account_links_info element цикл, и внутренний цикл, заполняющий строки account_id значениями).

Ответ №2:

Инструкции XSLT создают узлы в результирующем дереве, а не лексические начальные и конечные теги. Вывод узла — это одна операция, вы не можете разделить ее на две операции, каждая из которых содержит половину узла. Итак, вы должны думать так: «для каждых пяти узлов на входе я хочу создать узел на выходе», что естественным образом приводит к такой конструкции, как

 <xsl:for-each select="*[position() mod 5 = 1]">
  

Не поддавайтесь соблазну использовать disable-output-escaping для этого. Это отрава. Это нарушает четкую архитектурную границу между механизмом преобразования и сериализованным, что означает, что ваша таблица стилей не может быть развернута и повторно использована в произвольном конвейере (по этой причине она не будет работать в Firefox, если вас интересуют практические последствия).

Ответ №3:

Поскольку вы устанавливаете теги <tr> и </tr> в разных местах, вы должны вывести их в виде текста, чтобы сохранить допустимый XML для файла XSL. Кроме того, вы должны выводить </tr> тег, когда это последний элемент в таблице, иначе последняя строка может быть не закрыта:

 <table>
  <xsl:for-each select="/alert/account_links/account_links_info">
    <xsl:if test="position()mod5=1">
      <xsl:text disable-output-escaping="yes">amp;<tramp;></xsl:text>          
    </xsl:if>
    <td>
      <xsl:value-of select="account_id"/>
    </td>
    <xsl:if test="position()mod5=0 or position()=last()">
      <xsl:text disable-output-escaping="yes">amp;</tramp;></xsl:text>
    </xsl:if>        
  </xsl:for-each>
</table>
  

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

1. И это не одна из них. Это ужасно.

2. @Michael Kay: думаю, вы правы; надеюсь, мое решение лучше соответствует вашим ожиданиям.

3. @Michael Kay: Из вашего комментария в вашем решении, какая часть не будет работать в Firefox? Не является ли вывод преобразования текстовым файлом, который интерпретируется как XML, следующим шагом по линии? Кроме того, при любой возможности вы можете включить новые теги XSL для этой цели в будущем: <xsl:startTag name=»tr»/>, <xsl:endTag name =»tr» /> 🙂 P.S. Понравилась ваша книга по XSLT 2.0. Извините, меня привлекла темная сторона 😉

4. @Michael Kay: Не обращайте внимания на первый вопрос, я вижу, что Firefox пропускает промежуточный текстовый шаг и переходит непосредственно к DOM и, следовательно, не может обработать его должным образом.