Использование XSLT для итерации и преобразования XML в простой текст

Я новичок и все еще учусь XSLT. У меня есть простой XML-код ниже:

<?xml version = "1.0" encoding = "UTF-8"?>
<order id = "1021">
    <items>
        <item code = "11">
            <quantity>2</quantity
            <price>50</price>
        </item>
        <item code = "21">
            <quantity>1</quantity>
            <price>250</price>
        </item>
        <item code = "13">
            <quantity>4</quantity>
            <price>100</price>
        </item>
    </items>
    <status>3</status>
</order>

И я хочу написать сценарий XSLT, который преобразует его в простой текстовый массив, содержащий все коды элементов. Например, приведенный выше XML-код следует преобразовать как: [11,21,13]

Я написал следующий код XSLT:

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

    <xsl:output method = "text"/>
    <xsl:strip-space elements = "*"/>

    <!-- Template to match the root 'order' element -->
    <xsl:template match = "/order">
        <!-- Start bracket for the array -->
        <xsl:text>[</xsl:text>
        <!-- Iterate over each item -->
        <xsl:for-each select = "items/item">
            <!-- Output the code attribute -->
            <xsl:value-of select = "@code"/>
            <!-- If not the last item, add a comma and space -->
            <xsl:if test = "position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>
        </xsl:for-each>
        <!-- End bracket for the array -->
        <xsl:text>]</xsl:text>
    </xsl:template>

</xsl:stylesheet>

Я столкнулся с проблемой перебора всех элементов. Я получаю только код первого элемента вывода: [11]

Где я ожидаю коды всех предметов, например: [11,21,13]

Пожалуйста, дайте мне знать, если кто-нибудь заметит ошибку в моем коде XSLT. Я пробовал попросить об этом чатгпт, но это не очень помогло.

🤔 А знаете ли вы, что...
XML документ всегда должен иметь корневой элемент, который содержит все остальные элементы.


60
1

Ответ:

Решено

Ваш XSLT 1.0 отлично работает.

Для сравнения см. ниже, насколько проще это реализовать в XSLT 2.0 и более поздних версиях.

В XSLT 2.0 <xsl:value-of> был улучшен и теперь имеет атрибут разделителя.

XSLT, 2-е издание, Дуг Тидвелл

  • XSLT 1.0 стал рекомендацией W3C в ноябре 1999 года.
  • XSLT 2.0 стал рекомендацией W3C в январе 2007 года.
  • XSLT 3.0 стал рекомендацией W3C в июне 2017 года.

Для справки: XSLT

Входной XML

<?xml version = "1.0" encoding = "UTF-8"?>
<order id = "1021">
    <items>
        <item code = "11">
            <quantity>2</quantity>
            <price>50</price>
        </item>
        <item code = "21">
            <quantity>1</quantity>
            <price>250</price>
        </item>
        <item code = "13">
            <quantity>4</quantity>
            <price>100</price>
        </item>
    </items>
    <status>3</status>
</order>

XSLT 1.0

<?xml version = "1.0"?>
<xsl:stylesheet version = "1.0"
                xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
    <xsl:output method = "text"/>
    <xsl:strip-space elements = "*"/>

    <!-- Template to match the root 'order' element -->
    <xsl:template match = "/order">
        <!-- Start bracket for the array -->
        <xsl:text>[</xsl:text>
        <!-- Iterate over each item -->
        <xsl:for-each select = "items/item">
            <!-- Output the code attribute -->
            <xsl:value-of select = "@code"/>
            <!-- If not the last item, add a comma and space -->
            <xsl:if test = "position() != last()">
                <xsl:text>, </xsl:text>
            </xsl:if>
        </xsl:for-each>
        <!-- End bracket for the array -->
        <xsl:text>]</xsl:text>
    </xsl:template>
</xsl:stylesheet>

XSLT 2.0

<?xml version = "1.0"?>
<xsl:stylesheet version = "2.0"
                xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
    <xsl:output method = "text"/>

    <xsl:template match = "/">
        <xsl:text>[</xsl:text>
        <xsl:value-of select = "order/items/item/@code"
                      separator = ", "/>
        <xsl:text>]</xsl:text>
    </xsl:template>
</xsl:stylesheet>

Выход

[11, 21, 13]