XSL с именем "with-param" с использованием "apply-templates"

Мои вопросы находятся внизу этой публикации, если вы хотите прочитать их перед полным объяснением.

Я конвертирую XML-документ на симпатичную веб-страницу с помощью XSL, и у меня возникают проблемы с правильной передачей переменной. У меня есть много xsl:template, и нужно передать конкретный параметр только одному из них. Я надеялся, что смогу передать именованный параметр, который предположительно будет отправлен на все xsl:template s, но будет использоваться только одним и игнорироваться другими. Однако, пытаясь проверить это для себя (и мое ограниченное понимание XSL), я не смог вообще передать этот параметр, не говоря уже о том, что он случайно нарушил другие xsl:template s.

Ниже приведен упрощенный примерный код (типизированный для этого вопроса, он может содержать опечатку или два). У меня много разных xsl:template, определенных для работы с узлами в XML, и все работает до сих пор. Он заключается в добавлении параметра к этим шаблонам, которые, как представляется, возникают с проблемами.

XML файл:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="main.xsl"?>
<wrapperNode>
  <testNode>
    <subNode/>
  </testNode>
</wrapperNode>

main.xsl:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="test.xsl"/>
<xsl:output method="html" indent="yes"/>

<xsl:template match="/">

<html>
  <body>
      <xsl:apply-templates>
        <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param>
      </xsl:apply-templates>
  </body>
</html>

</xsl:template>
</xsl:stylesheet>

test.xsl:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="testNode">
  <xsl:param name="testParam" />
  TEST1
  <xsl:value-of select="$testParam" />
  TEST2
</xsl:template>
</xsl:stylesheet>

Выход (фактический):

TEST1 TEST2

Выход (ожидаемый/желаемый):

TEST1 TEST_PARAMETER TEST2

Мои вопросы относительно этого:

  • Можно ли отправить имя параметр для всех моих xsl:template с использованием xsl:apply-templates с xsl:with-param, но выберите это значение конкретно name= внутри фактический шаблон, чтобы он мог быть явно использована в одном шаблон и игнорируется всеми остальными (даже если бы я хотел добавить другое, по-разному названные, параметры для другие шаблоны позже)?

  • Что я делаю неправильно с моим текущим примером кода, который, кажется, вообще не принимает параметр?

  • Есть ли лучший способ сделать это?

Изменить: Я хочу пояснить, что из-за другого вывода в шаблоне test.xsl: testNode я точно знаю, что он успешно вызван. Это ТОЛЬКО параметр, который не работает. Я не хочу тратить время на то, чтобы выяснить, почему этот шаблон не называется. Это.

Обновление: В ответ на полученные мной ответы, в которых указывалось, что пример, который я составил, был не совсем правильным (моя ошибка) и не очень четко показывал проблему (то есть: вызывается правильный шаблон, но видно, что только параметр не работает), я заменил примеры гораздо лучшими. Этот пример более четко показывает, что шаблон testNode успешно вызывается, но этот параметр, кажется, не передается. Я проверил это много раз, до и после рассмотрения предыдущих ответов на этот вопрос. Я абсолютно тупик, поскольку все кажется правильным из того, что я читал в другом месте и что люди предлагали до сих пор.

Ответ 1

Мои вопросы относительно этого:

  • Можно ли отправить именованный параметр ко всем моим xsl: шаблонам используя xsl: apply-templates с xsl: with-param, но выберите это значение а именно name= в пределах фактический шаблон, чтобы он мог явно используется в одном шаблоне и игнорируются всеми другими (даже если я хотел добавить другое, иначе named, параметры для других шаблонов позже)?

Да. В XSLT 2.0 можно использовать так называемые "параметры туннеля", но в XSLT 1.0 это способ, чтобы некоторые параметры достигли некоторого удаленного шаблона в цепочке.

Другой способ состоит в том, чтобы иметь глобальные параметры, чтобы они не проходили через каждый шаблон в цепочке.

0,2. Что я делаю неправильно с моим текущим примером кода, который он не делает кажется, вообще-то получают параметр?

Причина в коде, который вы нам не показали. Или, может быть, исходный XML-документ, который у вас есть в вашем реальном случае, не тот, который указан здесь. Я выполнил предоставленный код, и я не смог воспроизвести проблему вообще - выдается желаемый результат.

Я предполагаю, что перед шаблоном, который соответствует testNode, выбран еще один шаблон.. Этот шаблон ничего не знает о переданном параметре и не передает его шаблонам, это, в свою очередь, применяется. Таким образом, параметр не передается вообще для соответствия шаблону testNode.

Я предполагаю, что если вы замените:

  <xsl:apply-templates> 
    <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param> 
  </xsl:apply-templates> 

с

  <xsl:apply-templates select="testNode"> 
    <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param> 
  </xsl:apply-templates> 

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

Кроме того, вы можете отслеживать с помощью отладчика XSLT (например, в Visual Studio) и видеть, какой именно шаблон выбран.

0,3. Есть ли лучший способ сделать это?

Как я уже говорил, глобальные параметры могут использоваться как альтернатива - я не уверен, что это лучше.

Наконец, вот код, который я запускал, который не может воспроизвести вашу проблему:

Таблица стилей XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>

 <xsl:template match="/">
      This is text1
      <xsl:apply-templates>
        <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param>
      </xsl:apply-templates>
      This is text2
 </xsl:template>

 <xsl:template match="testNode">
  <xsl:param name="testParam" />
  <xsl:value-of select="$testParam" />
 </xsl:template>
</xsl:stylesheet>

XML-документ:

<?xml-stylesheet type="text/xsl" href="main.xsl"?>
<testNode>
  <subNode/>
</testNode>

Результат

  This is text1
  TEST_PARAMETER
  This is text2

UPDATE:

ОП предоставил более точную информацию, которая предвосхищает мои предположения.

Теперь очевидно, что проблема вызвана тем, что для w630 > можно выбрать XSLT встроенный шаблон для wrapperNode. Этот шаблон, естественно, не знает о каких-либо параметрах и не использует параметр testParam и не пропускает этот параметр. Таким образом, <xsl:apply-templates/> во встроенном шаблоне вызывает выбор шаблона testNode, не передавая ему никаких параметров. Это объясняет сообщаемое поведение/результат.

Решение. Решение состоит в том, чтобы указать шаблон, соответствующий wrapperNode, который принимает параметр с именем testParam и передает его при применении шаблонов:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" indent="yes"/>

 <xsl:template match="/">
  <html>
    <body>
        <xsl:apply-templates>
          <xsl:with-param name="testParam" select="'TEST_PARAMETER'"/>
        </xsl:apply-templates>
    </body>
  </html>
 </xsl:template>

 <xsl:template match="testNode">
  <xsl:param name="testParam" />
  TEST1
  <xsl:value-of select="$testParam" />
  TEST2
 </xsl:template>

 <xsl:template match="wrapperNode">
  <xsl:param name="testParam" />

  <xsl:apply-templates>
   <xsl:with-param name="testParam" select="$testParam"/>
  </xsl:apply-templates>
 </xsl:template>
</xsl:stylesheet>

Теперь, когда это преобразование применяется к предоставленному XML-документу, ожидаемый результат получается:

<html>
<body>
  TEST1
  TEST_PARAMETER
  TEST2
 </body>
</html>

Ответ 2

Тэги <html> и <body> не могут встречаться там, где они находятся в таблице стилей XSL. Когда я удаляю их и закрываю теги и запускаю их в Oxygen/XML, я получаю ваш "желаемый" вывод. Я думаю, вы хотите поместить теги INSIDE в шаблон верхнего уровня, и в этом случае он будет генерировать вывод в тегах html и body.

Какой движок XSLT вы использовали, который не жаловался на недопустимую таблицу стилей?

Ответ 3

Я выполнил постер 3 примера выше как есть и получил этот результат, используя Notepad++ 7.7.1 в Wine под Ubuntu 18.04 с установленными инструментами XML.

TEST1 TEST_PARAMETER TEST2