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

Мои вопросы по этому поводу:

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

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

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

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

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

2 ответа

Решение

Мои вопросы по этому поводу:

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

Да В 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

ОБНОВИТЬ:

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

Теперь очевидно, что проблема вызвана тем, что для встроенного шаблона 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>

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

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

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

<html><body>

  TEST1
  TEST_PARAMETER
  TEST2

</body></html>
Другие вопросы по тегам