Я новичок и все еще учусь 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. Я пробовал попросить об этом чатгпт, но это не очень помогло.
Я тестирую это на онлайн-компиляторе школ w3, а также пробовал программу на Python, которая его преобразует. Оба они дают одинаковый результат
Пожалуйста, отредактируйте вопрос и покажите полный код Python, позволяющий нам воспроизвести предполагаемый результат [11]
. Я с кодом типа gist.github.com/martin-honnen/baa79449b27317d33e697a15ee2d67f9 конечно получаю результат [11, 21, 13]
.
Вы должны использовать другой код в своих тестах.
Я вижу, что вы используете XSLT 1.0 (около 1999 г.). Можно ли начать использовать XSLT 2.0 или 3.0? Это значительно облегчит вашу задачу.
@YitzhakKhabinsky Ваш комментарий можно истолковать как предположение о том, что проблема вызвана каким-то недостатком в XSLT 1.0. Что, конечно, неправда.
В ОП упоминается: «Я новичок и все еще учусь XSLT». Лучше начинать изучение XSLT с версии выше 1.0.
@YitzhakKhabinsky Возможно, но это не имеет никакого отношения к вопросу. Было бы лучше отложить ваш совет до тех пор, пока не будет решена текущая проблема.
Я допустил глупую ошибку в XML-коде: мне не хватает >
, как заметил @michael.hor257k <item code = "11"> <quantity>2</quantity <price>50</price> </item>
Но любой соответствующий процессор выдал бы ошибку вместо того результата, который вы утверждаете.
Ваш XSLT 1.0 отлично работает.
Для сравнения см. ниже, насколько проще это реализовать в XSLT 2.0 и более поздних версиях.
В XSLT 2.0 <xsl:value-of>
был улучшен и теперь имеет атрибут разделителя.
XSLT, 2-е издание, Дуг Тидвелл
Для справки: 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]
Поскольку вы с таким энтузиазмом стремитесь быть в курсе последних версий XSLT, вы могли бы перейти на XSLT 3.0 и получить желаемый результат, используя только <xsl:sequence select = "array{/order/items/item/number(@code)}"/>
. Но все это еще не имеет никакого отношения к вопросу.
@michael.hor257k, я полностью с тобой согласен. Подождем отзывов ОП.
Спасибо за ссылку на XSLT 2.0, а также на XSLT 3.0 @michael.hor257k. Я считаю, что с новыми версиями язык стал проще. Однако в рамках моего курса мы должны изучать и работать с XSLT 1.0. Поэтому я пытался изучить и практиковать это.
Вы правильно написали XML-код, добавив недостающий >
, который вызывал проблемы при выводе.
В вашем XSLT нет ошибок, и он дает ожидаемый результат (за исключением пробелов после запятых) — при условии, что вы добавите недостающий
>
во входной XML. Как вы это тестируете?