Работаю над более крупным преобразованием, но смог воспроизвести это в макете. Если я использую атрибут «mode» в своем шаблоне XSLT, результатом будет просто необработанный текст (без разметки) исходного XML, который предполагается преобразовать. Если вместо этого я использую атрибут «имя», он преобразуется, как и ожидалось.
XML
<Parent>
<ParentCon>Parent Content</ParentCon>
<Child>
<ChildCon>Child Content</ChildCon>
<Grandchild>Some Grandchild Content</Grandchild>
</Child>
</Parent>
XSLT (с атрибутом режима)
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:template match = "Parent" mode = "xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
Вывод (с атрибутом режима)
<?xml version = "1.0" encoding = "UTF-8"?>
Parent Content
Child Content
Some Grandchild Content
XSLT (с атрибутом имени)
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:template match = "Parent" name = "xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
Вывод (с атрибутом имени)
<?xml version = "1.0" encoding = "UTF-8"?><ExportParent><ExportChild/></ExportParent>
Поиск в Google показывает, что имя и режим функционально одинаковы, за исключением того, что режим допускает повторное использование.
Я ожидал, что результат будет одинаковым для обоих атрибутов.
Вам необходимо применить шаблоны в этом режиме, чтобы использовать шаблоны в этом режиме. XSLT 3.0 также позволяет объявить режим по умолчанию:
<xsl:stylesheet version = "3.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" default-mode = "xyz">
<xsl:template match = "Parent" mode = "xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
Обработка по умолчанию применяет шаблоны, которые не находятся в режиме. Существуют встроенные срабатывающие шаблоны, которые применяют шаблоны к дочерним узлам, и шаблон по умолчанию для text()
, который возвращает текст. Итак, когда эти шаблоны по умолчанию совпадают, он просто выдает text()
.
Если вы хотите получить ожидаемый результат, вы можете создать шаблон, соответствующий корневому узлу /
, а затем внутри этого шаблона применить шаблоны в режиме «xyz», и он будет соответствовать Parent
и применить этот шаблон в этом режиме:
<xsl:stylesheet version = "1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:template match = "/">
<xsl:apply-templates mode = "xyz"/>
</xsl:template>
<xsl:template match = "Parent" mode = "xyz">
<ExportParent>
<ExportChild>
</ExportChild>
</ExportParent>
</xsl:template>
</xsl:stylesheet>
Проблема с вашим шаблоном с атрибутом mode
в том, что он никогда не применяется, и все преобразование выполняется только с использованием встроенных правил шаблона.
Спецификация XSLT 1.0 гласит, что:
если элемент
xsl:apply-templates
не имеет атрибутаmode
, то это применимо только к тем правилам шаблона из элементовxsl:template
у которых нет атрибутаmode
.
В вашем XSLT нет инструкции xsl:apply-templates
, а встроенное правило шаблона применяет шаблоны без mode
.
Результатом обработки XML с использованием только встроенных правил шаблона является копия всех текстовых узлов входного документа.
Имя шаблона не играет никакой роли, если вы не называете шаблон по его имени.
См.:
https://www.w3.org/TR/1999/REC-xslt-19991116/#modes
https://www.w3.org/TR/1999/REC-xslt-19991116/#built-in-rule
https://www.w3.org/TR/1999/REC-xslt-19991116/#named-templates
Атрибуты name
и mode
шаблонов XSLT несколько похожи в том, что они оба являются своего рода идентификатором и оба используются для управления обстоятельствами, в которых применяется шаблон, но они работают совершенно по-разному.
XSLT — необычный язык программирования, поскольку он предлагает гораздо большую гибкость при вызове блока кода, чем большинство других языков. Это одна из самых странных особенностей, которую программистам с другим опытом иногда трудно понять. См. https://en.wikipedia.org/wiki/Multiple_dispatch
Многие языки позволяют вызывать функцию по имени, а многие позволяют иметь несколько функций с одинаковым именем и направлять вызов функции соответствующей функции на основе имени функции, а также параметров, которые вы указываете при ее вызове. В объектно-ориентированных языках объект также предоставляет способ идентификации соответствующего метода для вызова (независимо от того, прикреплен ли метод к объекту напрямую или к одному из классов объекта).
В XSLT у вас есть два разных способа вызвать шаблон:
<xsl:call-template name = "my-template"/>
Это вызовет шаблон, @name
которого равен my-template
. Это так просто.
Единственная сложность заключается в том, что если у вас есть таблица стилей, содержащая шаблон с именем my-template
, и ваша таблица стилей импортирует другую таблицу стилей, которая содержит шаблон, также называемый my-template
, тогда шаблон основной таблицы стилей будет иметь более высокий приоритет и будет вызываться вместо шаблона в импортированная таблица стилей. Это сделано для того, чтобы вы могли импортировать другую таблицу стилей и переопределить некоторые ее функции, эффективно заменив некоторые из именованных шаблонов.
Обратите внимание, что шаблон по закону может иметь атрибут name
, а также атрибут mode
, но это необычная практика кодирования. В любом случае, когда вы вызываете шаблон по имени, mode
игнорируется. Атрибут mode
вступает в действие только тогда, когда вы вызываете шаблон с помощью apply-templates
, и в этих случаях mode
используется вместе с match
, чтобы решить, применяется ли данный шаблон.
Самый распространенный способ вызова шаблона — не по имени, а путем сопоставления с образцом.
Атрибут mode
шаблона имеет значение только тогда, когда шаблон вызывается путем сопоставления с образцом, путем вызова apply-templates
:
<xsl:apply-templates select = "$my-nodes"/>
Когда вы используете apply-templates
для вызова шаблона, процессор таблицы стилей использует атрибут match
шаблонов, чтобы решить, какой шаблон вызывать. Он найдет шаблоны, чей шаблон match
соответствует узлам, указанным в атрибуте select
атрибута apply-templates
, и из числа соответствующих шаблонов вызовет шаблон с наивысшим приоритетом (либо тот, у которого самый высокий атрибут priority
, либо тот, у которого самое сложное match
выражение). Когда вы вызываете шаблон с помощью apply-templates
, атрибут name
(если таковой имеется) шаблона игнорируется.
Атрибут mode
обеспечивает уточнение:
<xsl:apply-templates select = "$my-nodes" mode = "my-mode"/>
Когда вы вызываете apply-templates
с определенным режимом, процессор таблицы стилей учитывает только шаблоны с соответствующим атрибутом mode
. Таким образом, mode
позволяет сгруппировать набор связанных шаблонов вместе.
Если вы не укажете режим в apply-templates
или в элементе template
, это фактически относится к анонимному режиму.
mode
и подумать mode
Как программисты XSLT используют mode
? Если у вас есть опыт объектно-ориентированного программирования, вам может оказаться полезным получить интуитивное понимание mode
, (примерно) сопоставив его с объектно-ориентированной структурой:
Таблица стилей XSLT, содержащая набор шаблонов без атрибутов mode
(т. е. все они принадлежат анонимному режиму по умолчанию), подобна набору классов, каждый из которых имеет один метод (назовем его default_mode
), которые все наследуют от базы node()
класс, метод default_mode
которого просто вызывает метод default_mode
для своих дочерних узлов, и где класс text()
предоставляет реализацию метода default_mode
, который выводит текстовое значение текстового узла.
Для встроенного анонимного режима и для любого нового mode
, который вы определяете явно, сам язык XSLT предоставляет встроенные реализации нескольких шаблонов для вас (а в XSLT 3 вы можете выбрать одну из нескольких таких реализаций). .
Здесь шаблон match
шаблона является эквивалентом имени класса в объектно-ориентированном языке (да, шаблон match
намного сложнее, чем имя класса, но ради аргументации, поскольку я фокусируюсь на mode
, я Я собираюсь игнорировать эту разницу).
class `document_or_element` {
method `default_mode` ($node) {
return `default_mode`($node/child::node());
}
}
class `text_or_attribute` extends `node()` {
method `default_mode`($node) {
return string-value-of($node);
}
}
class `comment_or_processing_instruction` extends `node()` {
method `default_mode`($node) {
return null;
}
}
Таблица стилей XSLT с двумя разными режимами подобна набору классов, которые все наследуют от базового класса с двумя методами (например, default_mode
и some_other_mode
).
Таким образом, в обычной практике XSLT mode
используется для определения определенного типа обработки, точно так же, как класс определяет несколько методов для выполнения различных типов обработки (например, преобразование узлов в определенный вид выходного формата или извлечение определенного вида обработки). какая-то информация от узлов или что-то в этом роде).
Написание шаблона в определенном mode
похоже на написание метода для нового класса, который переопределяет одноименный метод в суперклассе; он предназначен для предоставления конкретной реализации того же общего вида обработки, который обеспечивает метод суперкласса.
name
иmode
совсем не одно и то же. Лучше всего прочитать саму спецификацию, а не полагаться на случайные источники, найденные в Google.