Я работаю над автоматическим преобразованием измерений с использованием XSLT. Преобразование единичных измерений из одной системы (например, в имперскую) в другую (например, метрическую) работает нормальноНо имперские измерения могут принимать форму «5 футов 10 дюймов», и я хотел бы преобразовать это в одно значение метрики.
В моей модели XML я учитываю такие комбинированные измерения, допуская либо одно значение, либо несколькодочерние узлы. Поэтому, когда я обнаружил, что у меня есть дочерние узлы, мне нужно преобразовать каждый из этих дочерних элементов в метрические единицы, а затем сложить значения, чтобы получить один единственный результат метрики.
Я изо всех сил пытаюсь найти лучший способобработать несколько дочерних узлов и сложить результирующие значения. В итеративном языке я бы просто обрабатывал от первого до следующего и обновлял глобальную переменную, но в XSLT я не знаю, существует ли такая вещь, как глобальная переменная, которую можно обновлять при последующих вызовах того же шаблона.
Вот (упрощенное) преобразование - оно обрабатывает только [ft_i] и [in_i] в м.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*,node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="measurement">
<xsl:copy>
<xsl:choose>
<xsl:when test="measurement">
<xsl:apply-templates select="*"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="normalise">
<xsl:with-param name="val" as="xs:double" select="number(text())"/>
<xsl:with-param name="unitin" select="@ucum"/>
<xsl:with-param name="count" as="xs:integer" select="1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
<xsl:template name="normalise">
<xsl:param name="val" as="xs:double"/>
<xsl:param name="unitin"/>
<xsl:param name="count" as="xs:integer"/>
<xsl:choose>
<xsl:when test="$unitin eq '[ft_i]'">
<xsl:attribute name="ucum">
<xsl:value-of select="'m'"/>
</xsl:attribute>
<xsl:attribute name="unit">
<xsl:value-of select="'m'"/>
</xsl:attribute>
<xsl:value-of select="$val * 0.3048"/>
</xsl:when>
<xsl:when test="$unitin eq '[in_i]'">
<xsl:attribute name="ucum">
<xsl:value-of select="'m'"/>
</xsl:attribute>
<xsl:attribute name="unit">
<xsl:value-of select="'m'"/>
</xsl:attribute>
<xsl:value-of select="$val * 0.0254"/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Простой тестовый файл:
<topic>
<p>This piece is
<measurement>
<measurement unit="ft"
ucum=" [ft_i]">10</measurement>
<measurement unit="in"
ucum="[in_i]">2</measurement>
</measurement>
long
</p>
</topic>
Преобразование дает это:
<topic>
<p>This piece is
<measurement>
<measurement ucum="m"
unit="m">3.048</measurement>
<measurement ucum="m"
unit="m">0.0508</measurement>
</measurement>
long
</p>
</topic>
Очевидно, я хотел бы видеть это:
<topic>
<p>This piece is
<measurement ucum="m"
unit="m">3.0988</measurement>
long
</p>
</topic>
Я мог бы использовать xsl: for-each на дочерних узлах измерения, но какЯ добавляю отдельные значения к глобальному значению, которое затем может выводиться из основного шаблона?