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
.
ОБНОВЛЕНИЕ : ОП пояснил в комментарии, что его самая большая проблема - найти максимум.
<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, отсутствует элемент top верхнего уровня):
<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»
Теперь вы должны увидеть код с отступом.