использование аккумулятора в xslt 3.0 не работает как мне нужно

У меня есть XML, в котором у меня есть список книг с такими свойствами, как название, цена, автор, дополнительная цена, исполнитель, страна и т. Д. XML выглядит следующим образом.

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
  <cd>
    <title>Empire Burlesque</title>
    <artist>Bob Dylan</artist>
    <country>USA</country>
    <company>Columbia</company>
    <price>10.90</price>
    <additionalprice>12.90</additionalprice>
    <year>1985</year>
  </cd>
  <cd>
    <title>Hide your heart</title>
    <artist>Bonnie Tyler</artist>
    <country>UK</country>
    <company>CBS Records</company>
    <price>9.90</price>
    <additionalprice>10.90</additionalprice>
    <year>1988</year>
  </cd>

и так далее

Я хочу написать XSLT 3.0, применяемый к XML, чтобы получить HTML. Я хочу использовать аккумулятор, чтобы получить общее количество книг в каталоге. Хотя есть методы получше, я просто хотел использовать аккумулятор для практических целей и вывести итоговую сумму в конце таблицы, содержащей книги, где в столбцах указаны название, автор и общая цена. Для заполнения названия и автора я использовал for-each. Итоговая цена = цена + дополнительная цена. Я хочу использовать итерацию для подачи итоговой цены. Может ли кто-нибудь помочь мне с этим. Моя неполная таблица стилей выглядит следующим образом:

<?xml version="3.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html> 
<body>
  <h2>My CD Collection</h2>
  <table border="2">
    <tr bgcolor="#9acd32">
       <th style="text-align:left">Title</th>
       <th style="text-align:left">Artist</th>
       <th style="text-align:left">Total Price</th>
    </tr>
 <xsl:accumulator name="total" as="xs:integer" initial-value="0" streamable="no">
    <xsl:accumulator-rule match="title" select="$value+1"/>
 </xsl:accumulator>
    <xsl:for-each select="catalog/cd">
     <tr>
       <td><xsl:value-of select="title"/></td>
       <td><xsl:value-of select="artist"/></td>
     </tr>
   </xsl:for-each>
         <tr bgcolor="#FFA500">
           <td> Total number of Books </td>
           <td> <xsl:value-of select="accumulator-before('total')"/</td>
         </tr>
     </table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

Я не хочу использовать стриминг.


person swifty    schedule 05.11.2017    source источник


Ответы (1)


Если вы посмотрите на спецификацию https://www.w3.org/TR/xslt-30/#accumulator-declaration, то вы видите, что xsl:accumulator является объявлением, то есть вы должны использовать его как элемент / дочерний элемент верхнего уровня для xsl:stylesheet, а не внутри шаблона.

А значение аккумулятора связано с узлом и такими функциями, как https://www.w3.org/TR/xslt-30/#func-accumulator-before "Возвращает значение предварительного спуска выбранного аккумулятора в узле контекста", поэтому в вашем случае, когда у вас есть один шаблон с контекстным узлом / не имеет особого смысла обращаться к аккумулятору перед значением, вам скорее понадобится значение accumulator-after.

Наконец, вы должны объявить, что аккумулятор должен быть применен к режиму по умолчанию.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:mode use-accumulators="#all"/>

    <xsl:accumulator name="total" as="xs:integer" initial-value="0" streamable="no">
        <xsl:accumulator-rule match="title" select="$value + 1"/>
    </xsl:accumulator>

    <xsl:template match="/">
        <html>
            <body>
                <h2>My CD Collection</h2>
                <table border="2">
                    <tr bgcolor="#9acd32">
                        <th style="text-align:left">Title</th>
                        <th style="text-align:left">Artist</th>
                        <th style="text-align:left">Total Price</th>
                    </tr>

                    <xsl:for-each select="catalog/cd">
                        <tr>
                            <td>
                                <xsl:value-of select="title"/>
                            </td>
                            <td>
                                <xsl:value-of select="artist"/>
                            </td>
                        </tr>
                    </xsl:for-each>
                    <tr bgcolor="#FFA500">
                        <td> Total number of Books </td>
                        <td>
                            <xsl:value-of select="accumulator-after('total')"/>
                        </td>
                    </tr>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>
person Martin Honnen    schedule 05.11.2017
comment
Вышеупомянутый не работает для меня @Martin. Не знаю почему. При удалении строки ‹td› ‹xsl: value-of select = accumulator-after ('total') /› ‹/td›, я получаю вывод, в котором значение, которое должно быть заполнено аккумулятором, пусто. Я использую w3schools.com/xml/tryxslt.asp, поэтому я не получаю ошибок компиляции . - person swifty; 05.11.2017
comment
Чтобы использовать XSLT 3, вам необходимо использовать процессор XSLT 3, инструмент, с которым вы связались, не является таковым. Известные мне реализации XSLT 3, соответствующие последней спецификации XSLT 3 этого года, - это Saxon 9.8 и Altova 2017 R3 или 2018, поэтому я предлагаю вам попробовать одну из них, если вы хотите использовать XSLT 3. Saxon 9.8 HE с ваш ввод исправлен, чтобы быть правильно сформированным и полным, а мой фрагмент внутри полного xsl:stylesheet выводит 2 для accumulator-after('total'), как и Altova XMLSpy 2018. - person Martin Honnen; 05.11.2017
comment
Я отредактировал фрагмент кода и превратил его в полную таблицу стилей на тот случай, если ваши проблемы возникли из-за того, что предыдущий фрагмент имел только соответствующий код для тела таблицы стилей. - person Martin Honnen; 05.11.2017
comment
После того, как я начал использовать xml spy от Altova, он отлично работает - person swifty; 06.11.2017