фрагмент дерева результатов для набора узлов: общий подход для всех движков xsl - PullRequest
4 голосов
/ 23 марта 2012

Ответ на другой поток (см. stackoverflow: генерировать цветовые схемы css ) Я столкнулся с проблемой ниже, где различные механизмы xsl, похоже, нуждаются в разных подходах при преобразовании фрагментов дерева результатов в наборы узлов.

Упрощая проблему (но см. Ссылку выше для полной истории этого), я хочу иметь встроенное дерево, содержащее список значений цвета.Поскольку это должно использоваться в выражениях Xpath, мне пришлось создать из него набор узлов специально для движка MSXML xx xsl (встроенному XML Spy было меньше проблем с интерпретацией переменных выражения Xpath, созданных как rtf).
Еще одинthread stackoverflow: automating-exsltnode-set помог мне в этом.Результирующий набор узлов используется при создании новой переменной rtf из входного XML.
Опять же, MSXML жалуется, когда новая переменная используется в выражениях Xpath, поэтому я использовал функцию набора узлов для создания набора узлов изэто.
Пока все хорошо, и MSXML xx больше не дает ошибок.
Но когда я запускаю то же самое во встроенном XML Spy или в Saxon 9he, я получаю еще одну ошибку: кажется, что набор узловфункция неизвестна:

Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set() in variable colorList

Обратите внимание, что этот двухэтапный подход не нужен в данном конкретном примере, но, как я уже сказал, я упростил вещи;Я просто хочу знать, как написать преобразование XSLT 1.0, которое будет работать во всех движках xsl.

XSLT, который я использовал:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:std="http://whatever"
    xmlns:exslt="urn:schemas-microsoft-com:xslt"
    exclude-result-prefixes="std exslt">

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

    <std:colors>
        <color>#0000FF</color>
        <color>#FF0000</color>
    </std:colors>

    <xsl:variable name="colors" select="document('')/*/std:colors"/>

    <xsl:variable name="std:colorList">
        <xsl:for-each select="//testid">
            <xsl:variable name="pos" select="position() mod 2"/>
            <xsl:element name="color">
                <xsl:attribute name="testid"><xsl:value-of select="."/></xsl:attribute>
                <xsl:value-of select="$colors/color[$pos + 1]"/>
            </xsl:element>
        </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="colorList" select="exslt:node-set($std:colorList)"/>

    <xsl:template match="/">
        <output>
            <xsl:copy-of select="$colorList/color"/>
        </output>
   </xsl:template>

</xsl:stylesheet>

Входной файл:

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
  <defects>
    <testid>111</testid>
  </defects>
  <defects>
    <testid>999</testid>
  </defects>
</NewDataSet>

Результат в MSXML 3.0 / 4.0 / 6.0:

<?xml version="1.0" encoding="UTF-16"?>
<output>
<color testid="111">#FF0000</color>
<color testid="999">#0000FF</color>
</output>

Результат в Saxon9he:

Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set()
in variable colorList

результат во встроенном в XML Spy движке XML Spy:

Error in XPath expression
Unknown function - Name and number of arguments do not match any function signature in the static context - 'urn:schemas-microsoft-com:xslt:node-set'

Ответы [ 5 ]

6 голосов
/ 23 марта 2012

Для процессоров, отличных от MSXML, используйте функцию exslt: node-set ().(http://www.exslt.org/). (Немного странно связывать префикс exslt с версией функции Microsoft - это меня некоторое время смущало!)

Вы можете проверить, какие функции доступны, используя function-available ():

<xsl:choose>
  <xsl:when test="function-available('exslt:node-set')"...
  <xsl:when test="function-available('msxsl:node-set')"...

Для Saxon-HE и других процессоров XSLT 2.0 вам не нужны эти функции, поэтому используйте

<xsl:when test="xsl:version='2.0'">
4 голосов
/ 23 марта 2012

Чтобы избежать необходимости

 <xsl:choose>
 <xsl:when test="function-available('exslt:node-set')"...

каждый раз, когда вам это нужно, вы можете определять набор узлов exslt для движков xslt2 (используя xsl: function) и для msxml (используя msxsl: script), а затем просто использовать функцию exslt: node-set в остальная часть вашего документа.

http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html

показывает, как определить его для msxml, а для движков xslt2 вы можете xsl: включить таблицу стилей

<xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:exslt="http://exslt.org/common"
        >

<xsl:function name="exslt:node-set">
  <xsl:param name="rtf"/>
  <xsl:sequence select="$rtf"/>
</xsl:function>

<xsl:stylesheet>

Правила прямой совместимости XSLT1 означают, что включить это безопасно, механизм XSLT1 просто проигнорирует это.

1 голос
/ 23 марта 2012

Microsoft .NET XsltCompiledTransform XSLT-процессор поддерживает exslt: node-set ().

Для MSXML можно использовать мою собственную реализацию подмножества функций EXSLT - для MSXML. Подробное описание и ссылку на скачивание вы можете найти здесь:

http://www.xml.com/pub/a/2003/08/06/exslt.html

1 голос
/ 23 марта 2012

Ну, Saxon 9 - это процессор XSLT 2.0, а в XSLT 2.0 одно из главных улучшений состоит в том, что различие между наборами узлов и фрагментами дерева результатов прошло, и вам вообще не нужны никакие функции расширения, так как вы этого не делаете нужно больше принуждать к принуждению. Таким образом, при использовании таблиц стилей, предназначенных для любого процессора XSLT 2.0, вы должны просто отбросить любую попытку использовать такую ​​функцию расширения, тогда таблица стилей будет работать. Если вы хотите запустить одну и ту же таблицу стилей с процессорами XSLT 1.0 и 2.0, я вижу проблему, но не думаю, что есть простое решение. Вам нужно будет использовать http://www.w3.org/TR/xslt#function-function-available и системное свойство для различения процессоров и доступности функций расширения.

0 голосов
/ 29 августа 2013

Ну, вы можете легко сделать это без каких-либо проверок. Просто следуйте шаблону, описанному здесь: http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html

<xsl:stylesheet
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exslt="http://exslt.org/common"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="exslt msxsl">


<msxsl:script language="JScript" implements-prefix="exslt">
 this['node-set'] =  function (x) {
  return x;
  }
</msxsl:script>


<xsl:variable name="x">
  <y/>
</xsl:variable>

<xsl:template match="x">
  <html>
    <head><title>test exslt node set</title></head>
    <body>
      <xsl:apply-templates select="exslt:node-set($x)/*"/>
    </body>
  </html>
</xsl:template>

<xsl:template match="y">
  <p>node set!</p>
</xsl:template>

</xsl:stylesheet>

Это определенно работает в FF, Chrome и IE7 +

...