#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 и, следовательно, не может обработать его должным образом.