2011-12-16 3 views
3

У меня есть XSLT, как это:XSLT: XPath контекст и документ()

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

    <xsl:variable name="fooDocument" select="document('fooDocument.xml')"/> 

    <xsl:template match="/"> 
    <xsl:apply-templates select="$fooDocument//*"/> 
    </xsl:template> 

    <xsl:template match="nodeInFooDocument"> 
    <xsl:variable name="valueFromSource" select="//someSourceElement"/> 
    </xsl:template> 
</xsl:transform> 

Во втором шаблоне, который соответствует узлов в fooDocument.xml, который загружается с document(), я хочу, чтобы получить доступ к узлам в XML источник преобразование выполняется. Это не работает с //someSourceElement, потому что, по-видимому, XPath выполняет этот путь в контексте fooDocument.

Первое решение, которое приходит на ум, это:

... 
<!-- global variable --> 
<xsl:variable name="root" select="/"/> 

... 
<!-- in the template --> 
<xsl:variable name="valueFromSource" select="$root//someSourceElement"/> 

... 

Но я не могу использовать этот обходной путь, потому что на самом деле, моя переменная выбирается так:

<xsl:variable name="valueFromSource" select="xalan:evaluate($someXPathString)"/> 

$someXPathString не обработаны в файл XSLT, но загружается из fooDocument (и содержит абсолютный путь, как тот, который использовался выше). Тем не менее, мне нужно как-то изменить XPath-контекст обратно на источник XML. очень Hacky обходной путь я нашел это:

<xsl:for-each select="$root[1]"> 
    <xsl:variable name="valueFromSource" select="xalan:evaluate($someXPathString)"/> 
</xsl:for-each> 

The (бесполезно) for-each цикл изменяет контекст обратно к основному источнику XML, таким образом, XPath оценивает правильно. Но, очевидно, это не приемлемое решение.

Есть ли способ сделать это право, или может кто-нибудь предложить лучшее обходное решение?

ответ

3

Даже если вы считаете, что ваша попытка с использованием for-each select="$root" изменить контекстный документ неприемлема, это правильный подход. Так что используйте это, другого пути нет.

+1

Я согласен с тем, что для каждого - прекрасный способ изменить контекстный документ (если несколько неинтуитивно понятный), но, конечно же, Мартин, вы не имеете в виду, что другого пути нет. Например. 'apply-templates select =" $ root "' (с режимом или без него) также будет устанавливать контекстный документ, правильно? – LarsH

+0

Я не нашел другого возможного способа изменить контекстный документ. – flyx

2

Рассматривали ли вы все вычисления, которые строят $ someXPathString, используя серию глобальных переменных?

<xsl:variable name="fooDocument" select="document('fooDocument.xml')"/> 

<xsl:variable name="temp1" 
    .. some computation using fooDocument .. 
</xsl:variable> 

<xsl:variable name="temp2" 
    .. some computation using temp1 .. 
</xsl:variable> 

<xsl:variable name="someXPathString" 
    .. some computation using temp2 .. 
</xsl:variable> 

<xsl:variable name="root" select="xalan:evaluate($someXPathString)"/> 
+0

Это будет работать, если я захочу скопировать все содержимое fooDocument в глобальную переменную и использовать xalan: nodeset() на нем. Поскольку fooDocument содержит последовательность произвольной длины, я не могу разбить ее на фиксированное число глобальных переменных, содержащих примитивные значения. Для удобства чтения это определенно вариант. EDIT: Во-вторых, когда я использую 'apply-templates' в этой глобальной переменной, мой контекст все равно не будет находиться в источнике XML, а в переменной, которая содержит результат вызова xalan: nodeset(). – flyx

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