Java / Saxon: программный запуск функции XSL - PullRequest
1 голос
/ 17 октября 2011

У меня есть XSL, определяющий несколько функций.

Я хочу написать код Java, который принимает имя функции XSL (и список аргументов) и запускает эту функцию (и, конечно, связывает аргументы с формальными параметрами функции).

Пока единственное решение, которое у меня есть, - это на лету сгенерировать XSL-код с основным шаблоном, который запускает выбранную функцию. Это довольно неловко. Я ищу решение, позволяющее мне запускать функцию напрямую через Saxon API.

Ответы [ 4 ]

1 голос
/ 17 октября 2011

Способ, которым XPath Visualizer делает это (независимо от используемого процессора XSLT), заключается в загрузке основной таблицы стилей XSL в виде документа XML и динамическом изменении только одного атрибута select с необходимым выражением XPath.

Примерно так :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:import href="yourTrueMainStylesheetModule"/>
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vResult" select="."/>

 <xsl:template match="/">
     <xsl:sequence select="$vResult"/>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
  1. Загрузите вышеуказанный модуль таблицы стилей как XmlDocument.

  2. Выпуск: SelectNodes("/*/xsl:variable[@name='vResult']/@select")

  3. Используя API DOM, измените значение выбранного атрибута на желаемое, скажем: my:foo(1,2,3).

  4. Инициировать преобразование, используя уже загруженную (и динамически измененную таблицу стилей.

В течение многих лет я использовал XPath Visualizer 2 (для XSLT 2.0 - не опубликован) в качестве интерпретатора, похожего на командную строку, для функций FXSL. Я могу свободно написать:

f:fold(f:mult(), 1, 1 to 4)

и получите правильный результат:

24

Вот скриншот использования XPath Visualizer 2 в качестве интерпретатора FXSL :

enter image description here

0 голосов
/ 17 октября 2011

Есть API, который делает это для XQuery (XQueryEvaluator.callFunction () в пакете s9api), но ничто не сравнимо с XSLT.Вероятно, было бы возможно достичь этого, вызвав правильную последовательность низкоуровневых внутренних методов, но вам, вероятно, придется изучить исходный код, чтобы заставить его работать.

0 голосов
/ 17 октября 2011

XSLT уже имеет функцию для запуска различных инструкций в зависимости от содержимого вашего входного документа: шаблоны .Я считаю, что слишком сложно работать с внутренним API Saxon, если вы уже используете XSLT, просто скомпилируйте этот большой XSLT один раз и используйте его снова.

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

Я приведу пример.Давайте предположим, что у нас есть два входных XML:

<myxml>
  <doctype>recipe</doctype>
  <descr>Bread 'n jam sandwich</descr>
  <var>jam</var>
  <var>bread</var>
</myxml>

<myxml>
  <doctype>shoppinglist</doctype>
  <descr>Monday</descr>
  <var>honey</var>
  <var>butter</var>
  <var>loaf of bread</var>
  <var>jam</var>
</myxml>

Теперь предположим, что мы хотим сгенерировать HTML для этих XML с правильным форматированием.Первый XML должен генерировать HTML с «Recipe:» и списком ингредиентов.Второй должен содержать список покупок.

Вот XSLT для генерации обоих:

<xsl:stylesheet version="2.0"    
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:saxon="http://saxon.sf.net/" 
    exclude-result-prefixes="xs saxon">

<xsl:output method="html" indent="yes"/>

<!-- Generate basic html -->
<xsl:template match="/">
        <html>
            <body><xsl:apply-templates /></body>
        </html>
</xsl:template>

<!-- Only call template doctype element, not for vars -->
<xsl:template match="myxml">
    <xsl:apply-templates select="doctype"/>
</xsl:template>

<xsl:template match="doctype[.='shoppinglist']">
    <h1>Shopping list for <xsl:value-of select="../descr"/></h1>
    <span><b>Stuff to bring:</b></span>
    <ul>
        <xsl:for-each select="../var">
            <li><xsl:value-of select="."/></li>
        </xsl:for-each>
    </ul>
</xsl:template>

<xsl:template match="doctype[.='recipe']">
    <h1>Recipe: <xsl:value-of select="../descr"/></h1>
    <span><b>Ingredients:</b></span>
    <ul>
        <xsl:for-each select="../var">
            <li><xsl:value-of select="."/></li>
        </xsl:for-each>
    </ul>
</xsl:template>

</xsl:stylesheet>

Теперь рассмотрим аргумент match последних шаблонов.В этом случае я выбрал на основе содержимого элемента, но вы можете просто использовать любое выражение фильтра XPath, которое вам нравится (т.е. выбирать на основе аргумента XML).

0 голосов
/ 17 октября 2011

Вы, вероятно, не можете напрямую, но не могли бы вы просто иметь основной шаблон, вызывающий разные шаблоны на основе одного из ваших параметров, например, большой оператор switch.

...