2010-08-23 1 views
3

Я работаю с таблицей стилей XSL, и я пытаюсь использовать метод, показанный here, для хранения отсортированного поддерева как переменной. Я использую saxon 8.7 в xml-maven-plugin для преобразования моего XML-файла. Вот код, который у меня есть:Сортировка поддерева и сохранение его в переменной xsl:

<xsl:variable name="miniDays"> 
    <xsl:for-each select="//day[position() > $firstPosToShow]"> 
     <xsl:sort select="@date" order="descending" /> 
     <xsl:copy-of select=".|@*" /> 
    </xsl:for-each> 
</xsl:variable> 

Когда я запускаю таблицу стилей, я получаю следующее сообщение об ошибке:

Error at xsl:copy-of on line 598 of file:/D:/home/Projects/src/main/xsl/site.xsl: 
    XTDE0420: Cannot create an attribute node (date) whose parent is a document node 

Если я просто установить поддерево переменного без сортировки, она работает, но это не отсортировано «»

<xsl:variable name="miniDays" select="//day[position() > $firstPosToShow]" /> 

Если я установил копирование в заявлении выберет к, он получает мимо этой точки, но дает мне ошибку позже, когда я на самом деле пытаюсь использовать переменные данные. Вот как он используется:

<xsl:for-each select="exsl:node-set($miniDays)"> 
    <xsl:variable name="in" select="local:calculate-total-in-days(.)" /> 
    <!-- do some stuff with the var --> 
</xsl:for-each> 

и ошибка:

Error on line 676 of file:/D:/home/Projects/src/main/xsl/site.xsl: 
    XPTY0004: Required item type of first argument of local:calculate-total-in-days() is element(); supplied value has item type document-node() 

Функция:

<xsl:function name="local:calculate-total-in-days"> 
    <xsl:param name="days" as="element()*" /> 
    <!-- Do some calculations --> 
</xsl:function> 

Могу ли я с помощью exsl: набор узлов неправильно? И что должно быть в выбранном экземпляре «.». или ". @ @"?

+0

Покажите нам достаточно входного XML, чтобы иметь возможность рассказать, что происходит. –

+0

Хороший вопрос (+1). См. Мой ответ для обсуждения вопросов в коде и решения каждого из этих вопросов. –

ответ

1

Есть целый ряд проблем, с кодом:

  1. <xsl:for-each select="//day[position() > $firstPosToShow]">. Это выберет каждый элемент day в документе, который находится в позиции $firstPosToShow+1 или больше в наборе day детей его родителей! Скорее всего, вы хотите (//day)[position() >= $firstPosToShow]

  2. <xsl:copy-of select=".|@*" />. Это копирует текущий элемент, но также копирует его атрибуты. Атрибут может быть скопирован только в том случае, если родительский элемент является элементом. Это не так, поскольку операции внутри нетипизированной переменной создают временное дерево (документ), а узел документа не может иметь атрибуты. Правильная инструкция: <xsl:copy-of select="." />

  3. Список itemIn следующий код:

выражение exsl:node-set($miniDays) снова имеет тип document-node() и <xsl:for-each> выбирает только один (этот) узел. Это объясняет возникшую ошибку, потому что local:calculate-total-in-days(.) ожидает элемент-аргумент, но передается узел документа.

Правильный код:

<xsl:for-each select="exsl:node-set($miniDays)/*"> 
    <xsl:variable name="in" select="local:calculate-total-in-days(.)" /> 
    <!-- do some stuff with the var --> 
</xsl:for-each> 

Кроме того, exslt:node:set() не требуется в XSLT 2.0, потому что нет никакого типа RTF в XSLT 2.0, и на самом деле не поддерживается в Саксонской 9.x.Таким образом, правильный код будет:

<xsl:for-each select="$miniDays/*"> 
    <xsl:variable name="in" select="local:calculate-total-in-days(.)" /> 
    <!-- do some stuff with the var --> 
</xsl:for-each> 

В качестве альтернативы, вы можете рассмотреть указать тип $miniDays явно как element()* и это упростит код - это не было бы необходимо использовать $miniDays/* - только $miniDays

+0

Хороший ответ - спасибо! Дала мне много чего читать. –

Смежные вопросы