Как в XSLT 1.0 создать функцию поиска для XML-данных, встроенных в XSLT, с использованием ключа и документа ('')?

Моя конкретная потребность состоит в том, чтобы искать высоту строки с учетом определенного размера шрифта, но я пытаюсь изучить общую технику создания поиска/конкретного сопоставления.

Я думаю, что можно встроить XML в сам документ XSLT (чтобы он мог работать автономно) и создать на нем ключ, используя функцию document('') для ссылки на текущий XSLT, примерно так:

<xsl:variable name="data.font-metrics.line-height">
    <line-height font-size="11">12</line-height>
    <line-height font-size="12">14</line-height>
    <line-height font-size="13">15</line-height>
    <line-height font-size="14">16</line-height>
    <line-height font-size="15">17</line-height>
    <line-height font-size="16">18</line-height>
    <line-height font-size="17">20</line-height>
    <line-height font-size="18">21</line-height>
</xsl:variable>
<xsl:key name="lookup.font-metrics.line-height" match="document('')//xsl:variable[@name='data.font-metrics.line-height'])/line-height" use="@font-size"/>

После этого я смогу найти высоту строки с помощью ключевой функции:

<xsl:value-of select="key('lookup.font-metrics.line-height',$font-size)"/>

... однако я получаю следующее сообщение об ошибке:

XPath error : Invalid expression
//document('')//xsl:variable[@name='data.font-metrics.line-height'])/line-height/text()
           ^

Я думаю, что здесь сходятся несколько проблем:

  • использование функции документа
  • использование ключевой функции
  • каков наилучший метод встраивания XML? в переменной?

Также может быть совершенно другое решение проблемы.

Буду очень признателен за вашу помощь!


person MrWatson    schedule 12.05.2015    source источник
comment
Совершенно непонятно, что вы пытаетесь сделать, но я могу сказать вам, что document('')/xsl:variable не является правильным способом доступа к переменной. Не могли бы вы добавить входной XML, ожидаемый результат и полный XSLT и рассказать нам, чего вы пытаетесь достичь.   -  person Lingamurthy CS    schedule 12.05.2015


Ответы (2)


В XSLT 1.0 функция key() работает только в контексте текущего документа (в XSLT 2.0 у нее есть третий аргумент, позволяющий выбирать контекст). Чтобы использовать ключ для узлов в другом документе, вы должны сначала переключить контекст на этот документ, например:

XSLT 1.0

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="data.font-metrics.line-height">
    <line-height font-size="11">12</line-height>
    <line-height font-size="12">14</line-height>
    <line-height font-size="13">15</line-height>
    <line-height font-size="14">16</line-height>
    <line-height font-size="15">17</line-height>
    <line-height font-size="16">18</line-height>
    <line-height font-size="17">20</line-height>
    <line-height font-size="18">21</line-height>
</xsl:variable>

<xsl:key name="lookup.font-metrics.line-height" match="line-height" use="@font-size"/>

<xsl:template match="/">
    <xsl:param name="font-size" select="14"/>
    <output>
        <!-- other nodes -->
        <!-- switch context to the stylesheet itself in order to use the key -->
        <xsl:for-each select="document('')">
            <lookup>
                <xsl:value-of select="key('lookup.font-metrics.line-height', $font-size)"/>
            </lookup>
        </xsl:for-each>
        <!-- more nodes -->
    </output>
</xsl:template>

</xsl:stylesheet>

Результат

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <lookup>16</lookup>
</output>

Обратите внимание, что элемент xsl:key не играет роли в этом переключателе и может быть определен гораздо проще.

person michael.hor257k    schedule 12.05.2015
comment
МОЙ БОГ! Вау - какое понимание! - person MrWatson; 12.05.2015

Это означает, что <xsl:key> не (сопоставляется и) не компилируется, когда механизм XSLT впервые достигает элемента определения ключа, а когда механизм XSLT встречает первую функцию XPath key(). Только в это время может быть создан ключ, потому что только тогда известен контекст.

...что-то вроде ленивой казни...

КРОМЕ ТОГО, один ключ может применяться к нескольким документам, например, если преобразуемый документ XML содержит следующий XML:

<?xml version="1.0" encoding="UTF-8"?>
<fmxmlsnippet type="LayoutObjectList">
    <Layout enclosingRectTop ="46.0000000" enclosingRectLeft ="46.0000000" enclosingRectBottom ="171.0000000" enclosingRectRight ="366.0000000">
        <line-height font-size="14">18 in XML file</line-height>
        …

Затем следующий XSLT (добавленный к исходному XSLT выше):

    <xsl:comment>
        <xsl:for-each select="document('')">
            <!-- apply the key to the XSLT document -->
            <xsl:value-of select="key('lookup.font-metrics.line-height','14')"/>
        </xsl:for-each>
    </xsl:comment>
    <xsl:comment>
            <!-- apply the key to the XML document -->
            <xsl:value-of select="key('lookup.font-metrics.line-height','14')"/>
    </xsl:comment>

создаст следующий вывод:

<!--16-->
<!--18 in XML file-->

Таким образом, ключевая функция — это не ссылка на ранее созданный статический индекс, а — в сочетании с уловкой for-each-document('') — именно то, что я искал: функция поиска, которую можно использовать на узлах XML, где бы они ни были!

Ницца.

person MrWatson    schedule 12.05.2015
comment
<xsl:key> не компилируется...* Мы этого не знаем. Точно сказать могли только люди, написавшие XSLT-движок — и только применительно к собственному продукту. - person michael.hor257k; 12.05.2015