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:strip-space elements="*"/>
<xsl:variable name="vrtfMap">
<entry key="A" value="1"/>
<entry key="B" value="2"/>
<entry key="C" value="3"/>
<entry key="X" value="8"/>
</xsl:variable>
<xsl:variable name="vMap" select=
"document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@foo">
<xsl:attribute name="foo">
<xsl:value-of select="$vMap[@key = current()]/@value"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
при нанесении на следующий документ XML (как вы не предоставили какой-либо):
<t foo="X">
<a foo="A">
<b foo="B"/>
</a>
<c foo="C"/>
</t>
дает желаемый, правильный результат:
<t foo="8">
<a foo="1">
<b foo="2"/>
</a>
<c foo="3"/>
</t>
Объяснение: Надлежащее использование XSLT current()
функции.
II. 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:strip-space elements="*"/>
<xsl:key name="kValFromKey" match="entry/@value" use="../@key"/>
<xsl:variable name="vrtfMap">
<entry key="A" value="1"/>
<entry key="B" value="2"/>
<entry key="C" value="3"/>
<entry key="X" value="8"/>
</xsl:variable>
<xsl:variable name="vMap" select=
"document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@foo">
<xsl:variable name="vCur" select="."/>
<xsl:attribute name="foo">
<xsl:for-each select="document('')">
<xsl:value-of select="key('kValFromKey', $vCur)"/>
</xsl:for-each>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется на том же самом документе XML (выше), то же правильный результат получается.
Объяснение:
Использование <xsl:for-each select="document('')">
для установки текущего документа в таблице стилей, так что функция key()
будет использовать индекс ключа, построенный для этого документа.
Сохранение узла, совпавшего с шаблоном в переменной, так что мы можем использовать его внутри xsl:for-each
- current()
не может быть правильно использован здесь, потому что он получает текущий узел, на котором xsl:for-each
работает.
UPDATE: ОП теперь уточнено в комментарии, что его самая большая проблема заключается в нахождении максимума.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vrtfMap">
<entry key="A" value="1"/>
<entry key="B" value="2"/>
<entry key="C" value="3"/>
</xsl:variable>
<xsl:variable name="vMap" select=
"document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>
<xsl:template match="/">
<xsl:variable name="vDoc" select="."/>
<xsl:variable name="vFoosMapped"
select="$vMap[@key = $vDoc/*/*/@foo]"/>
<max>
<xsl:value-of select=
"$vFoosMapped
[not($vFoosMapped/@value > @value)]
/@value
"/>
</max>
</xsl:template>
</xsl:stylesheet>
При введении этого XML-документ (тот, предоставленный OP отсутствует singlr верхний элемент):
<t>
<tag foo="A">apples</tag>
<tag foo="C">oranges</tag>
<tag foo="B">trees</tag>
</t>
полезный, правильный результат, полученный:
<max>3</max>
Примечание: более эффективный способ расчета тин максимум (или минимум - аналогичным образом) в 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:strip-space elements="*"/>
<xsl:variable name="vrtfMap">
<entry key="A" value="1"/>
<entry key="B" value="2"/>
<entry key="C" value="3"/>
</xsl:variable>
<xsl:variable name="vMap" select=
"document('')/*/xsl:variable[@name = 'vrtfMap']/*"/>
<xsl:template match="/">
<xsl:variable name="vDoc" select="."/>
<xsl:variable name="vFoosMapped"
select="$vMap[@key = $vDoc/*/*/@foo]"/>
<max>
<xsl:for-each select="$vFoosMapped">
<xsl:sort select="@value" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="@value"/>
</xsl:if>
</xsl:for-each>
</max>
</xsl:template>
</xsl:stylesheet>
Другой вопрос, почему я не могу отступы мой код? Я помещаю пробелы, но он не работает.
Это ошибка, которую они не смогли исправить в течение многих месяцев.
Возможно, вы используете IE. Если ваша версия 9, а затем выполните следующие действия:
Нажмите F12.
В появившемся окне нажмите на правой наиболее меню и выберите: «Режим документа: IE9 Standards»
Теперь вы должны быть в состоянии увидеть код с отступом.
Функция 'max()' недоступна в XSLT 1.0. Можете ли вы использовать решение XSLT 2.0? Если да, то почему этот вопрос помечен как «xslt-1.0»? –
Я видел функцию max, но еще не использовал ее, потому что мне не удалось пройти шаг 2. Итак, если я не могу использовать функцию max в XSLT 1.0, это будет сложно:/ – Thirlan