#xslt
#xslt
Вопрос:
Я хочу выбрать все узлы для данного идентификатора, но это может закончиться дополнительным числом. Как я могу это сделать?
Пример:
<group id="list">
<group id="list1">
<group id="list2">
<group id="map">
<group id="map1">
Объявление, которое я имею сейчас:
<xsl:variable name="rule">
<data>
<node>list</node>
<node>map</node>
</data>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select=".//group[ @id = exslt:node-set($rule)/data/node]"/>
</xsl:template>
и это позволяет my работать только с узлами, указанными в списке «правило». [XSLT v1.0]
Пожалуйста, сообщите.
Ответ №1:
I. Решение XSLT 1.0:
Это преобразование:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pIds">
<id>list</id>
<id>map</id>
</xsl:param>
<xsl:variable name="vIds" select=
"document('')/*/xsl:param[@name='pIds']/*"/>
<xsl:template match="group">
<xsl:if test=
"$vIds[. = current()/@id
or
starts-with(current()/@id, .)
and
substring-after(current()/@id, .)
=
floor(substring-after(current()/@id, .))
]
">
<!-- Processing here: -->
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
при применении к этому XML-документу:
<t>
<group id="list"/>
<group id="list1"/>
<group id="listX"/>
<group id="list2"/>
<group id="map"/>
<group id="map123Z"/>
<group id="map1"/>
</t>
обрабатывает (в этом примере копирует) точно совпадающие узлы:
<group id="list"/>
<group id="list1"/>
<group id="list2"/>
<group id="map"/>
<group id="map1"/>
Объяснение:
-
Использование стандартных функций XPath
starts-with()
substring-after()
иfloor()
. -
Простой тест, если строка преобразуется в целое число,:
floor($s) = $s
II. Решение XSLT 2.0:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pIds" select="'list', 'map'"/>
<xsl:variable name="vIds" select=
"document('')/*/xsl:param[@name='pIds']/*"/>
<xsl:template match=
"group
[@id = $pIds
or
$pIds
[starts-with(current()/@id, .)
and
substring-after(current()/@id, .)
castable as
xs:integer
]
]
">
<!-- Processing here: -->
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Объяснение: Это решение очень похоже на решение XSLT 1.0 со следующими основными отличиями:
-
В XSLT 2.0 разрешено иметь ссылки на переменные / параметры в шаблоне сопоставления. Используя это, мы избегаем
<xsl:if>
внутри тела шаблона. -
Мы определяем параметр так, чтобы он содержал последовательность желаемых строк.
-
Мы используем стандартный оператор XPath 2.0
castable as
.