Проблема с использованием current () в xsl: for-each для извлечения узлов, которые находятся вне области видимости каждого - PullRequest
3 голосов
/ 27 июня 2011

Привет, я новичок в XSLT2.0, но, поскольку в недавнем проекте требуется конфигурация XML, я бы попробовал.Структура XML будет выглядеть так:

<bookstore>
<books>
    <book author="a" title="a1"/>
    <book author="b" title="b1"/>
    <book author="c" title="c1"/>
    <book author="d" title="d1"/>
</books>
<topAuthorList>
    <thisMonth>c,a,d,b</thisMonth>
</topAuthorList>

И XSLT выглядит так:

    <xsl:template match="/bookstore">
    <result>
        <xsl:variable name="varList">
            <xsl:value-of select="topAuthorList/thisMonth"></xsl:value-of>
        </xsl:variable> 

        <test>
            <xsl:value-of select="books/book[@author='a']/@title"></xsl:value-of>
        </test>

        <books>
            <xsl:for-each select="tokenize($varList, ',')">
                <xsl:value-of select="books/book[@author=current()]/@title"></xsl:value-of>
            </xsl:for-each>
        </books>
    </result>
</xsl:template>

Но в XMLSpy (версия 2011 г. rev3) это дает мнесообщение об ошибке:

XSLT 2.0 Debugging Error: Error in XPath 2.0 expression (Type error XPTY0004: Expected a node - current item is 'c' of type xs:string)

У меня был поиск в Google и на этом сайте много раз, и я не смог найти ответ.Я даже пытался использовать call-template, то есть передать current () в качестве параметра и позволить второму шаблону обрабатывать выбор узла, но все равно та же ошибка.

Ответы [ 3 ]

2 голосов
/ 27 июня 2011

Это работает:

  <xsl:template match="/bookstore">
    <result>
      <xsl:variable name="varList">
        <xsl:value-of select="topAuthorList/thisMonth"></xsl:value-of>
      </xsl:variable> 

      <test>
        <xsl:value-of select="books/book[@author='a']/@title"></xsl:value-of>
      </test>

      <books>
        <xsl:variable name="books" select="/bookstore/books"/>
        <xsl:for-each select="tokenize($varList, ',')">
          <xsl:value-of select="$books/book[@author=current()]/@title"></xsl:value-of>
        </xsl:for-each>
      </books>
    </result>
  </xsl:template>

Все, что я сделал, это поместил /bookstore/books в переменную, а затем выполнил поиск по переменной. У меня есть интуитивное понимание того, зачем это нужно, но у меня нет точной формальной причины без каких-либо исследований. Может быть, один из других экспертов по XML может вмешаться.

РЕДАКТИРОВАТЬ: я нашел соответствующую информацию в прекрасном опусе Майкла Кея «XSLT 2.0 и XPath 2.0», страница 625:

Корневой путь представляет собой путь начиная с корневого узла дерева который содержит узел контекста

Поскольку узел контекста в вашем случае является пустой строкой, он не содержит искомых узлов. Использование переменной обеспечивает правильный контекст для выражения XPath.

1 голос
/ 28 июня 2011

Когда вы пишете <xsl:value-of select="books/book[@author=current()]/@title">, «books» - это сокращение от «child :: books», то есть элементов books, которые являются потомками элемента контекста. Но что такое контекстный пункт? Содержащий xsl: for-each устанавливает элемент контекста для каждого элемента, выбранного в его выражении выбора. Но это вызов tokenize, поэтому элемент контекста является строкой, а строки не имеют дочерних элементов.

Концепция элемента контекста полезна, когда вы углубляетесь в иерархию. Это не полезно, когда вы делаете соединение. Для объединений вам нужны переменные. Иногда вы можете получить с помощью "." в качестве одной из переменных и «current ()» как другой, но когда это заканчивается, вам нужны реальные именованные переменные.

Кстати, не используйте xsl: value-of как дочерний элемент xsl: variable, если вы действительно не хотите создавать новое дерево документов. Вы почти наверняка можете переписать объявление varlist как <xsl:variable name="varList" select="topAuthorList/thisMonth">, которое не только требует меньше кода для написания, но и гораздо более эффективно, поскольку позволяет избежать необходимости создавать новое дерево.

0 голосов
/ 27 июня 2011

Я думаю, что вы хотите:

        <books>
            <xsl:variable name="tokens" select="tokenize($varList, ',')"/>
            <xsl:value-of select="
                for $a in $tokens 
                return books/book[@author=$a]/@title"/>
        </books>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...