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
шаблон успешно вызывается, но этот параметр, похоже, не передан. Я проверял это много раз, до и после рассмотрения предыдущих ответов на этот вопрос. Я абсолютно в замешательстве, так как все кажется правильным из того, что я читал в другом месте и что люди предложили до сих пор.
2 ответа
Мои вопросы по этому поводу:
- Можно ли отправить именованный параметр всем моим 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>