XSLT: рекурсивные шаблоны на параметризованных узлах - PullRequest
1 голос
/ 31 января 2020

Я пытаюсь рекурсивно вызвать шаблон в параметризованном списке типов узлов.

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

Как заставить рекурсию работать при сопоставлении с параметризованным значением?

(я использую саксонская версия 9.9.1.6 (домашняя версия) для применения преобразования XSLT)

Ввод HTML

<p>
<p>paragraph1</p>
<p>paragraph2</p>
<a>link here</a>
</p>

XSLT с прямым значением для шаблона:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="container" select="p|a"/>    
<xsl:template match="p|a">
    Name: <xsl:value-of select="name()"/>
    Value: <xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

Вывод:

<?xml version="1.0" encoding="UTF-8"?>
    Name: p
    Value: 

    Name: p
    Value: paragraph1

    Name: p
    Value: paragraph2

    Name: a
    Value: link here

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

XSLT с параметризованным значением для шаблона:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="container" select="p|a"/>    
<xsl:template match="$container">
    Name: <xsl:value-of select="name()"/>
    Value: <xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

Выход:

<?xml version="1.0" encoding="UTF-8"?>
    Name: p
    Value: 
paragraph1
paragraph2
link here

Ответы [ 2 ]

2 голосов
/ 31 января 2020

match="$variable" - это новый синтаксис в XSLT 3.0, который соответствует узлам в наборе узлов, содержащемся в глобальной переменной. Переменная содержит совпадающие узлы, а не их имена.

Кроме того, select = "p | a" выбирает узлы в контексте документа, а это не то, что вам нужно. Используйте select="'p|a'", чтобы установить переменную в строку. Это помогает использовать атрибут as, например. as="node()*" или as="xs:string", чтобы избежать путаницы относительно того, что переменная на самом деле должна содержать.

Чтобы сопоставить имена, используйте match="*[local-name()=tokenize($container, '\|')]"

В качестве альтернативы вы можете определить состояние c параметр и теневой атрибут:

<xsl:param name="container" select="'p|a'" static="yes"/>

<xsl:template _match="{$container}">...</xsl:template>

Или, если вы предпочитаете, вы можете инициализировать переменную для набора совпадающих узлов, например:

<xsl:param name="matching-nodes" select="//p | //a"/>

, а затем сопоставить, используя

<xsl:template match="$matching-nodes"/>

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

1 голос
/ 31 января 2020

РЕДАКТИРОВАТЬ : Я не видел ответа доктора Кея, поэтому воспринимайте это как расширение своего.


Результат - ожидаемый. С https://www.w3.org/TR/2017/REC-xslt-30-20170608/#patterns

  • $xyz соответствует любому узлу, присутствующему в значении переменной $xyz.

С https://www.w3.org/TR/2017/REC-xslt-30-20170608/#dt -global-variable

Для глобальной переменной или значения по умолчанию параметра таблицы стилей вычисляется выражение или конструктор последовательности, задающий значение переменной с одиночным фокусом следующим образом:

  • Если объявление появляется в пакете верхнего уровня (в том числе в элементе xsl:override в пакете верхнего уровня), тогда фокус
    основан на для элемента глобального контекста, если он указан или отсутствует
    в противном случае.
  • Если объявление появляется в пакете библиотеки, то фокус отсутствует.

Текущий Спецификация хорошо предупреждает о возможной разнице между глобальным контекстным элементом (контекстом для объявления вашей глобальной переменной) и начальным выбором соответствия (первые элементы, которые должны быть обработаны), но это позволяет вам d чтобы посмотреть в собственной документации вашего процессора XSLT, какие настройки по умолчанию ...

Я приму ситуацию, выраженную в виде примечания в specs :

Примечание:

В предыдущих выпусках этой спецификации обычно предоставлялся один узел для представления исходного документа для преобразования. Этот узел использовался в качестве целевого узла для неявного вызова на xsl:apply-templates, который использовался для запуска процесса преобразования (теперь называется первоначальным выбором совпадения), а узел root содержащего дерева использовался в качестве элемента контекста для оценки глобальные переменные (теперь они называются глобальным контекстным элементом). [...]

Это в сочетании с Встроенные правила шаблонов приводит к следующему рабочему процессу :

  1. Переменная $container задается в контексте узла документа или root: выражение выбирает элемент документа p.
  2. Узел документа или root соответствует встроенному правилу. Примените шаблоны к детям.
  3. Элемент документа p соответствует вашему шаблону. Выведите свой шаблон содержимого и примените шаблоны к дочерним элементам.
  4. Каждые пять дочерних элементов элемента p соответствуют встроенному правилу: выводятся только два пробельных текстовых узла, три элемента игнорируются.
  5. Выводятся три текстовых узла paragraph1, paragraph2 и link here.
...