Как я могу обернуть группу смежных элементов в зависимости от предыдущего брата с помощью XSLT?

Я хочу обернуть все элементы приложения, но только если предыдущий родственный элемент первого элемента приложения является частью.

Итак, если ввод похож на

<part>
..
..
</part>
<appendix href="..">
</appendix>
<appendix href="..">
</appendix>

Тогда вывод похож на

<part>
..
..
</part>
<appendices>
  <appendix href="..">
  </appendix>
  <appendix href="..">
  </appendix>
</appendices>

Я новичок в XSLT. Так что все, что я пробовал, до сих пор терпит неудачу. Любая помощь будет высоко ценится.


person Gaurav Goenka    schedule 14.07.2015    source источник
comment
Пожалуйста, объясните, можно ли использовать процессор XSLT 2.0, такой как Saxon 9, поскольку в XSLT 2.0 группировать проще. Вам также необходимо предоставить более подробную информацию о возможных входных данных. Могут ли существовать входные документы другого типа, один тип со структурой, которую вы показали, другие с другой структурой, которую вы вообще не хотите преобразовывать? Или в одном входном документе больше элементов?   -  person Martin Honnen    schedule 14.07.2015
comment
Да, я использую XSLT 2.0 с процессором Saxon. Выхода может быть два. Одна представляет собой структуру, показанную выше, а другая - структуру, в которой нет ‹part›, но вместо этого есть ‹chapter›, для которого нет необходимости в обработке.   -  person Gaurav Goenka    schedule 14.07.2015
comment
Кроме того, элементов гораздо больше, чем перечисленные выше. Следовательно, использование <xsl:template match="@*|node()"> приводит к конфликту с другим шаблоном, который начинается с <xsl:template match="*">, который используется для уменьшения всех элементов в файле.   -  person Gaurav Goenka    schedule 14.07.2015


Ответы (1)


С XSLT 2.0 ваше словесное описание переводится в

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

   <xsl:output indent="yes"/>

    <xsl:template match="*[appendix]">
        <xsl:copy>
            <xsl:for-each-group select="*" group-adjacent="boolean(self::appendix)">
                <xsl:choose>
                    <xsl:when test="current-grouping-key() and preceding-sibling::*[1][self::part]">
                        <appendices>
                            <xsl:apply-templates select="current-group()"/>
                        </appendices>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:transform>
person Martin Honnen    schedule 14.07.2015
comment
Извините, я не упомянул об этом в своем вопросе, но есть другие шаблоны, такие как <xsl:template match="*">, которые конфликтуют с <xsl:template match="@*|node()">. Какое-либо обходное решение для этого? - person Gaurav Goenka; 14.07.2015
comment
Если вы получили предупреждение о неоднозначном совпадении правил, вам необходимо применить приоритет для шаблона, которому вы хотите присвоить приоритет, например. <xsl:template match="*" priority="5">...</xsl:template>. - person Martin Honnen; 14.07.2015
comment
Извините за это, но это, похоже, не работает для меня. Код вроде бы работает, но я полагаю, что один из немногих других шаблонов, изменяющих элемент приложения, не работает. @Martin Honnen - person Gaurav Goenka; 14.07.2015
comment
Что ж, если вам нужна помощь в интеграции предложенного кода в другой код, отредактируйте свой вопрос и представьте код. - person Martin Honnen; 14.07.2015
comment
Принял это как ответ, потому что этот код работает. Просто нужно было немного подправить его в соответствии с моими требованиями для интеграции. Большое спасибо @Martin Honnen - person Gaurav Goenka; 16.07.2015