2012-03-23 1 views
4

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

Упрощение проблемы (но см. Ссылку выше для полной истории), я хочу иметь встроенное дерево, содержащее список значений цвета. Поскольку это должно использоваться в выражениях Xpath, мне пришлось создать набор узлов из него специально для MSXML x.x xsl engine (встроенный XML-шпион имел меньше проблем с интерпретацией выражений Xpath, связанных с переменными, построенными как rtf's).
Еще одна тема stackoverflow: automating-exsltnode-set помогла мне там. Результирующий набор узлов используется при создании новой переменной rtf из входного XML.
Снова, MSXML жалуется, когда новая переменная используется в выражениях Xpath, поэтому я использовал функцию набора узлов для создания набора узлов из нее.
До сих пор так хорошо, и MSXML x.x больше не исправляет ошибок.
Но когда я бегу то же самое в 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 встроенного Xsl двигатель:

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' 
+0

Просто для будущих читателей, работает в «XML-22036 (ошибка) не удается преобразовать результат фрагмент дерева в NodeSet "в Oracle 11g R1 BPEL XSLT 1.0 Transform: это может быть вызвано ошибкой. По-видимому, имя параметра в XSLT должно соответствовать параметру, который передается при его вызове, включая идентификацию «части». Итак, если какой-либо ответ зафиксирован в 'body' части переменной message-type' response', то для использования этого в последующем преобразовании параметр в XSLT также должен быть назван 'response.body'. Затем его можно просто называть «$ response.body/some/xpath». – Arjan

ответ

5

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

Вы можете проверить, какие функции доступны с помощью функции доступный():

<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'"> 
+0

ОК, поэтому, если я получу это правильно, я должен использовать функцию набора узлов при использовании MSXML и делать что-то по-другому для других движков - позвольте мне попытаться добавить выбор, чтобы сделать именно это ... – Maestro13

+0

Кстати - узел Функция -set НЕ доступна в saxon9he и встроенном XML-шпионах - по крайней мере, не с указанным пространством имен - это правильно? Нет функции набора узлов там, потому что она вам не нужна? Или это доступно под другим пространством имен? Обратите внимание, что я изменил пространства имен на \t xmlns: exslt = "http: //www.exslt.org" \t xmlns: msxsl = "urn: schemas-microsoft-com: xslt" – Maestro13

1

Ну 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 и системное свойство, чтобы отличать процессоры и доступность функций расширения.

3

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

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

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

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 двигатель просто проигнорирует его.

+0

Да, Google привел меня в поток вашего блога уже :-), но я проигнорировал его, потому что я не хотел вводить javascript, а функция afaik xsl: функция - только 2.0, не так ли? Тем не менее - ценный намек для этого. – Maestro13

+0

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

+0

звучит хорошо - я попробую! – Maestro13

1

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

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

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

-1

Ну, вы легко можете сделать это без каких-либо проверок. Просто следовать схеме, описанной здесь: 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 +

+0

Теперь лучше? – user2724798

+0

да, намного лучше :-) – kleopatra