Это преобразование показывает, как использовать глобальный параметр (смоделированный здесь со встроенным элементом) для указания (возможно, нескольких) обновлений :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:updates>
<update place="Berlin" dt="11-Dec-2011"/>
</my:updates>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"location
[place = document('')/*/my:updates/update/@place]
/dt/text()
">
<xsl:value-of select=
"document('')/*/my:updates/update
[@place = current()/../../place]
/@dt
"/>
</xsl:template>
</xsl:stylesheet>
При применении к предоставленному документу XML (исправлено, чтобы сделать его правильно сформированным):
<Locations>
<location>
<place>Newyork</place>
<dt>01-Dec-2011</dt>
</location>
<location>
<place>Berlin</place>
<dt>02-Dec-2011</dt>
</location>
<location>
<place>Tokyo</place>
<dt>04-Dec-2011</dt>
</location>
</Locations>
желаемый, правильный результат получается :
<Locations>
<location>
<place>Newyork</place>
<dt>01-Dec-2011</dt>
</location>
<location>
<place>Berlin</place>
<dt>11-Dec-2011</dt>
</location>
<location>
<place>Tokyo</place>
<dt>04-Dec-2011</dt>
</location>
</Locations>
Объяснение
Правило идентификации копирует каждый узел "как есть"".
Существует только один переопределяющий шаблон - соответствующий дочернему элементу текстового узла любого dt
, чье строковое значение брата place
имеет соответствующий элемент my:updates/update
. В этом шаблоне мы выводим значение атрибута dt
соответствующего элемента my:updates/update
.
Do note : При преобразовании реального мира встроенный элемент my:updates
будет лучше заменен внешним глобальным параметром. Прочитайте документацию вашего процессора XSLT, как передать внешний параметр в преобразование - это зависит от реализации.
ОБНОВЛЕНИЕ : Поскольку операционному оператору трудно преобразовать это решение в глобальное, переданное извне xsl:param
, вот это преобразованное решение:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pUpdates">
<update place="Berlin" dt="11-Dec-2011"/>
</xsl:param>
<xsl:variable name="vUpdates" select=
"ext:node-set($pUpdates)/*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="dt/text()">
<xsl:choose>
<xsl:when test="../../place=$vUpdates/@place">
<xsl:value-of select=
"$vUpdates[@place = current()/../../place]/@dt"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к тому же XML-документу (см. Выше), получается тот же правильный и требуемый результат :
<Locations>
<location>
<place>Newyork</place>
<dt>01-Dec-2011</dt>
</location>
<location>
<place>Berlin</place>
<dt>11-Dec-2011</dt>
</location>
<location>
<place>Tokyo</place>
<dt>04-Dec-2011</dt>
</location>
</Locations>
Обратите внимание : в этом решении значение xsl:param
по-прежнему жестко закодировано, и это единственная причина, по которой мы используем функцию расширения ext:node-set()
. Если параметр действительно передается извне, то это преобразование из RTF в обычное дерево не требуется, и на этот параметр следует ссылаться напрямую.
Кроме того, в XSLT 1.0 мы должны более точно соответствовать и использовать сравнения (xsl:choose
) внутри тела шаблона. Это так, потому что в XSLT 1.0 не разрешено ссылаться на переменные / параметры внутри шаблона сопоставления.
В XSLT 2.0 это ограничение было устранено , поэтому мы можем просто сделать намного более простое преобразование:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pUpdates">
<update place="Berlin" dt="11-Dec-2011"/>
</xsl:param>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"location[place=$pUpdates/*/@place]/dt/text()">
<xsl:value-of select=
"$pUpdates/*[@place = current()/../../place]/@dt"/>
</xsl:template>
</xsl:stylesheet>