Параметры, не передаваемые в шаблон при использовании .NET, преобразовывают классы

Я использую.Net XslCompiledTranform для выполнения некоторого простого XSLT (см. ниже для упрощенного примера).

Пример, который XSLT предназначен, чтобы сделать просто, показывает значение параметра, который передается в шаблону. Вывод - то, чем я ожидаю, что это будет (т.е.

<result xmlns:p1="http://www.doesnotexist.com">
  <valueOfParamA>valueA</valueOfParamA>
</result>

когда я использую сакса 9.0, но когда я использую XslCompiledTransform (XslTransform) в .net I, добираются

<result xmlns:p1="http://www.doesnotexist.com">
  <valueOfParamA></valueOfParamA>
</result>

Проблема состоит в том, что это, значение параметра paramA не передается в шаблон, когда я использую классы .NET. Я полностью озадачил относительно почему. когда я ступаю через в Visual Studio, отладчик говорит, что шаблон назовут с paramA ='valueA', но когда выполнение переключится на шаблон, значение paramA является пробелом.

Кто-либо может объяснить, почему это происходит? Действительно ли это - ошибка в реализации MS, или (более вероятно) я делаю что-то, что запрещается в XSLT?

Любая справка значительно ценится.

Это - XSLT, который я использую

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:extfn="http://exslt.org/common"  exclude-result-prefixes="extfn" xmlns:p1="http://www.doesnotexist.com">
<!-- 
    Replace msxml with
    xmlns:extfn="http://exslt.org/common" 
    xmlns:extfn="urn:schemas-microsoft-com:xslt" 
 -->
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
    <xsl:variable name="resultTreeFragment">
        <p1:foo>
        </p1:foo>
    </xsl:variable>
    <xsl:variable name="nodeset" select="extfn:node-set($resultTreeFragment)"/>
    <result>
        <xsl:apply-templates select="$nodeset" mode="AParticularMode">
            <xsl:with-param name="paramA" select="'valueA'"/>
        </xsl:apply-templates>
    </result>
</xsl:template>

<xsl:template match="p1:foo" mode="AParticularMode">
    <xsl:param name="paramA"/>

    <valueOfParamA>
        <xsl:value-of select="$paramA"/>
    </valueOfParamA>
</xsl:template>
</xsl:stylesheet>
5
задан InfantPro'Aravind' 9 March 2010 в 13:06
поделиться

3 ответа

Нет ничего странного - это ожидаемое поведение любого процессора, совместимого с XSLT 1.0.

Объяснение : Переменная $ nodeset определена как:

в XSLT 1.0 содержит полный XML-документ - узел документа, обозначенный в XPath 1.0 как / .

Следовательно,

<xsl:apply-templates select="$nodeset" mode="AParticularMode">
  <xsl:with-param name="paramA" select="'valueA'"/>
</xsl:apply-templates>

применит шаблон, соответствующий дереву (узел документа / ) в указанном режиме, если такой шаблон существует. В вашем случае такого шаблона не существует. Поэтому применяется встроенный шаблон XSLT 1.0 для / (который принадлежит каждому режиму ).

Текст встроенного шаблона можно найти в спецификации :

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

Согласно спецификации: " Существует также встроенное правило шаблона для каждый режим, который позволяет рекурсивной обработке продолжаться в том же режиме при отсутствии успешного сопоставления с шаблоном с помощью явного правила шаблона в таблице стилей. Это правило шаблона применяется как к узлам элемента, так и к корневому узлу. встроенное правило шаблона для режима m .

<xsl:template match="*|/" mode="m">
  <xsl:apply-templates mode="m"/>
</xsl:template>

"

Конечно, встроенный шаблон ничего не знает о вашем параметре $ paramA и не передает его вплоть до применяемых шаблонов.

Итак, наконец, для обработки выбирается ваш шаблон, соответствующий p1: foo " в mode =" AParticularMode ".В качестве значения параметра ничего не передается, поэтому он не имеет значения - таким образом, не создает ни одного символа или узла.

Чтобы исправить эту проблему, просто добавьте сопоставление с шаблоном / и в режиме «AParticularMode» :

<xsl:template match="/" mode="AParticularMode">
  <xsl:param name="paramA"/>

  <xsl:apply-templates mode="AParticularMode">
    <xsl:with-param name="paramA" select="$paramA"/>
  </xsl:apply-templates>
</xsl:template>

, и теперь вы получите желаемый результат.

В XSLT 2.0 (Saxon 9) вы наблюдаете другое поведение , потому что встроенные шаблоны в XSLT 2.0 по определению повторно передают все параметры, с которыми они были применены - см. XSLT 2.0 Spec :

"Если встроенное правило было вызвано с параметрами, эти параметры передаются в неявной инструкции xsl: apply-templates."

4
ответ дан 15 December 2019 в 00:58
поделиться

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

 <xsl:apply-templates select="$nodeset/*" mode="AParticularMode">
        <xsl:with-param name="paramA" select="'valueA'"/>
 </xsl:apply-templates>

(обратите внимание на select = "$ nodeset / *" вместо select = "nodeset" ) заставил его работать так, как я хотел, в .Net и Saxon.

Тем не менее, я был бы признателен, если бы кто-нибудь мог объяснить , почему моя первая попытка не удалась.

0
ответ дан 15 December 2019 в 00:58
поделиться

Ответ на ваш вопрос:

Почему моя первая попытка не удалась?

Поскольку вы удобно используете node-set () в своем коде, я думаю, вы, возможно, хорошо знаете о фрагменте дерева результатов. Если нет, то пройдите по этой ссылке .

Хорошо. Используя преимущество RTF [фрагмент дерева результатов], вы можете рассматривать «foo» как узел.

Переменная $ nodeset хранит древовидную структуру узла, так что вы можете рассматривать ее значение как набор узлов, тогда как переменная $ nodeset по-прежнему является переменной. Если вы хотите применить шаблон, затем примените его, его дочерние узлы [именно элементы] отображаются как его значение,

Вместо * вы могли бы использовать,

<xsl:apply-templates select="$nodeset/p1:foo" mode="AParticularMode">

Это более точно,

{{ 1}}
0
ответ дан 15 December 2019 в 00:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: