Что означает "@* | node()" в XSLT-методе выбора шаблона?
Я прочитал несколько примеров XSLT и нашел, что код:
<xsl:apply-template select="@*|node()"/>
Что это значит?
Ответы
Ответ 1
В выражении XPath @* | node()
выбирается объединение узлов атрибутов (@*
) и всех других типов узлов XML (node()
).
Это сокращение для attribute::* | child::node()
.
В XSLT XPath относится к контексту node, а ось выбора , например, в <xsl:apply-templates>
)
соответствует всем атрибутам и другим узлам независимо от контекста (при использовании в качестве выражения match=""
в <xsl:template>
) - обратите внимание, что существует разница между выбором узлов и их сопоставлением: контекст node имеет значение только для выбора.
Представьте, что следующий node - это контекст node:
<xml attr="value">[
]<child />[
]<!-- comment -->[
]<child>
<descendant />
</child>[
]</xml>
выражение node()
будет не только выбирать узлы <child>
, но также и четыре текстовых узла только для пробелов (обозначаемых [
и ]
для видимости) и комментарий. <descendant>
не выбран.
Особенностью XML является то, что узлы атрибутов не являются дочерними элементами элементов, к которым они принадлежат (хотя родителем атрибута является тот элемент, к которому он принадлежит).
Это асимметричное соотношение делает необходимым выбирать их отдельно, следовательно @*
.
Он соответствует любому атрибуту node, принадлежащему контексту node, поэтому также будет выбран attr="value"
.
|
- оператор объединения XPath. Он создает сингл node из двух отдельных наборов node.
<xsl:apply-templates>
затем находит подходящий <xsl:template>
для каждого выбранного node и запускает его для этого node. Это совпадающая с шаблоном часть, упомянутая выше.
Ответ 2
Чтобы добавить к Tomalak отличный ответ:
В большинстве случаев можно было бы увидеть <xsl:apply-template select="@*|node()"/>
в шаблоне, подобном этому:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
Это называется правило идентификации или "шаблон идентификации".
Одним из наиболее фундаментальных и мощных шаблонов проектирования XSLT является использование и переопределение правила идентификации.
Если преобразование состоит только из правила идентичности, результатом преобразования является сам исходный XML-документ - вот почему шаблон известен как "правило идентификации".
Почему возникает этот результат?
Короткий ответ: из-за модели обработки XSLT.
Более подробное объяснение должно начинаться с верхнего:
node()
соответствует любому элементу, text- node, комментарию или обработке-инструкции. Документ (корневой) - node также соответствует node()
.
Мы можем представить "листовые" узлы любого дерева документов - это любые узлы, у которых нет самих детей, таких как text- node, комментарий и инструкция обработки. Пустой элемент также следует рассматривать как лист node.
Правило идентичности первоначально выбирается для выполнения (применяется) ко всем дочерним узлам узлов документа (это самые верхние элементы и любые комментарии или братья-переводчики-инструкции, которые он мог бы иметь). Согласованный node неглубоко скопирован, и если это неэлементный лист node, команда <xsl:apply-templates select="node()|@*"/>
не выбирает ни узлы, ни атрибуты.
Если совпадающий node - это элемент, он неглубоко копируется, то команда <xsl:apply-templates select="node()|@*"/>
вызывает тот же шаблон (как и никакой другой шаблон в коде преобразования), который применяется к каждому из его атрибутов и каждый из его дочерних узлов.
Это рекурсия, которая управляет обработкой каждого node документа XML до тех пор, пока не будут достигнуты листовые узлы или атрибуты, и в этом месте <xsl:apply-templates select="node()|@*"/>
не будет выбран ни один из дочерних элементов или узлов-атрибутов.
Ответ 3
Поздравляем @Tomalak за первый правильный ответ. Тик должен идти по его ответу. Я просто добавлю некоторые пояснения к его ответу.
Примечание 1
... @* | node() выбирает объединение...
The | оператор не просто возвращает объединение двух операндов, но сортирует в порядке документа и удаляет дубликаты. Дедупликационная часть здесь неактуальна, потому что нет дубликатов для удаления, но следует отметить часть сортировки. Более правильным вариантом было бы сказать...
... @* | node() выбирает объединение, отсортированное по порядку документа...
Примечание два
... и все другие типы дочерних узлов XML (node())
Это в целом верно, но вводит в заблуждение. Когда большинство людей читают "дочерние узлы XML", они считают дочерние узлы в смысле DOM. Но это не то, что выбрано. Выбраны только узлы XDM. Для иллюстрации взгляните на следующий документ.
<?xml version="1.0" encoding="ISO-8859-1"?>
<root-element my-attrib="myattrib-vaue" xmlns:hi="www.abc.com"><child-element />
abc'def
</root-element>
Теперь предположим, что элемент контекста является "корневым элементом". Читателю ответа Томалака задается вопрос: что выбрано "@* | node()"? Импликация ответа Томалака для тех, кто думает о модели DOM, состоит в том, что выбрано 6 вещей:
- Атрибут my-attrib
- Атрибут node -space (который является истинным атрибутом в DOM)
- Детский элемент node
- бит 'abc'
- Ссылка на сущность
- бит "def".
Но в XSLT это не так. Фактически выбран...
- Атрибут my-attrib
- Детский элемент node
- Текст XDM node, являющийся конкатенацией трех текстовых узлов DOM, таких как: "abc'def"
Таким образом, более точное утверждение будет...
Выражение XPath @* | node() выбирает объединение, отсортированное по порядку документа, (узлов атрибута элемента контекста и дочерних узлов XML элемента контекста в смысле XDM). XD-модель игнорирует некоторые типы node, такие как определения сущностей, которые находятся в DOM, а непрерывные текстовые узлы DOM объединяются в один текст XDM node.