XSLT-таблица поиска и суммы (предыдущий-брат :: ...)? - PullRequest
1 голос
/ 28 октября 2010

У меня есть XML-документ, в котором есть узлы, которые выглядят так:

<Variable name="var1" dataType="INT32"/>
<Variable name="var2" dataType="INT16"/>
<Variable name="var3" dataType="INT8"/>

Я могу циклически перебирать переменные и отображать имя и тип данных просто отлично, но я хотел бы отобразитьразмер переменной, а также ее смещение (первая переменная имеет смещение нуля, 2-я имеет смещение, равное размеру первой, 3-я имеет смещение, равное размеру двух предыдущих).В приведенном выше примере var1 имеет размер 4 и смещение нуля, var2 имеет размер 2 и смещение 4, var3 имеет размер 1 и смещение 6.

Для печатиразмер, это сработало:

<xsl:variable name="fieldSize">
  <xsl:choose>
    <xsl:when test="contains(@dataType, 'INT8')">
        <xsl:value-of select="'1'"/>
    </xsl:when>
    <xsl:when test="contains(@dataType, 'INT16')">
        <xsl:value-of select="'2'"/>
    </xsl:when>
    <xsl:when test="contains(@dataType, 'INT32')">
        <xsl:value-of select="'4'"/>
    </xsl:when>
    <xsl:otherwise><xsl:value-of select="'unknown'"/></xsl:otherwise>
  </xsl:choose>
</xsl:variable>
<xsl:value-of select="$fieldSize"/>

Однако я понятия не имею, как распечатать смещение!Если бы размер поля был атрибутом, я мог бы сделать что-то вроде:

<xsl:variable name="offset" select="sum(preceding-sibling::Variable/@fieldSize)"/>

Поскольку это переменная, а не атрибут, я не могу сделать сумму по сравнению с предыдущими братьями и сестрами для вычисления смещения.Моя следующая идея - попытаться создать выражение, которое может соответствовать размеру на основе атрибута @dataType, и, возможно, я смогу передать это в выражение "sum ()" (хотя и не знаю, сработает ли это).

Я попытался создать NodeSet для fieldSizes, чтобы я мог найти размер по атрибуту:

<xsl:variable name="fieldSizes">
    <i ref="INT8">1</i>
    <i ref="INT16">2</i>
    <i ref="INT32">4</i>
</xsl:variable>

<xsl:value-of select="$fieldSizes[@ref=@dataType]"/>

Однако последняя строка вызывает ошибку во время преобразования XSLT: XPathОжидалось, что выражение вернет NodeSet. Все приведенные ниже варианты вызывают одну и ту же ошибку:

<xsl:value-of select="$fieldSizes[@ref='INT8']"/>
<xsl:value-of select="$fieldSizes[@ref=INT8]"/>
<xsl:value-of select="$fieldSizes[1]"/>

Как вывести размер поля переменной на основе ее dataType?И как только это сработает, как я могу рассчитать значение смещения?Возможно что-то вроде:

<xsl:variable name="offset" select="sum(preceding-sibling::Variable/$fieldSizes[@ref=@dataType])"/>

Ответы [ 3 ]

3 голосов
/ 28 октября 2010

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="msxsl" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:variable name="vDigits" select="'0123456789'"/>

 <xsl:template match="Variable">
  <xsl:variable name="vOffset">
     <xsl:call-template name="getOffset"/>
  </xsl:variable>

  <Variable name="{@name}" dataType="{@dataType}"
    size="{translate(@dataType, translate(@dataType,$vDigits,''),'') div 8}"
    offset="{$vOffset}"
  />
 </xsl:template>


 <xsl:template name="getOffset">
  <xsl:variable name="vrtfprevSizes">
   <xsl:for-each select="preceding-sibling::Variable">
     <v size="{translate(@dataType, translate(@dataType,$vDigits,''),'') div 8}"/>
   </xsl:for-each>
  </xsl:variable>

  <xsl:value-of select="sum(msxsl:node-set($vrtfprevSizes)/v/@size)"/>
 </xsl:template>
</xsl:stylesheet>

при применении к этому документу XML :

<t>
    <Variable name="var1" dataType="INT32"/>
    <Variable name="var2" dataType="INT16"/>
    <Variable name="var3" dataType="INT8"/>
</t>

дает желаемый, правильный результат :

<Variable name="var1" dataType="INT32" size="4" offset="0" />
<Variable name="var2" dataType="INT16" size="2" offset="4" />
<Variable name="var3" dataType="INT8" size="1" offset="6" />

Примечание :

  1. Нет рекурсии .

  2. В XSLT 1.0 xxx:node-set() требуется для преобразования RTF в обычный набор узлов.

  3. При очень большом количестве элементов Variable это решение является медленным, поскольку одна и та же частичная сумма вычисляется много раз. Однако гарантированно не произойдет сбой из-за слишком глубокого стека вызовов.

2 голосов
/ 28 октября 2010

Два решения: для двухпроходного преобразования (так что вы можете использовать fn:sum()) вам понадобится функция расширения node-set();режимы использования.

Эта таблица стилей:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my">
    <my:s size="4" dataType="INT32"/>
    <my:s size="2" dataType="INT16"/>
    <my:s size="1" dataType="INT8"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Variable/@*[last()]">
        <xsl:call-template name="identity"/>
        <xsl:attribute name="size">
            <xsl:value-of select="document('')/*/my:s
                                     [@dataType = current()/../@dataType]
                                        /@size"/>
        </xsl:attribute>
        <xsl:attribute name="offset">
            <xsl:apply-templates select=".." mode="offset"/>
        </xsl:attribute>
    </xsl:template>
    <xsl:template match="Variable" mode="offset">
        <xsl:param name="pCounter" select="0"/>
        <xsl:variable name="vPrev" select="preceding-sibling::Variable[1]"/>
        <xsl:apply-templates select="$vPrev" mode="offset">
            <xsl:with-param name="pCounter"
                            select="$pCounter + document('')/*/my:s
                                                  [@dataType = $vPrev/@dataType]
                                                     /@size"/>
        </xsl:apply-templates>
        <xsl:if test="not($vPrev)">
            <xsl:value-of select="$pCounter"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

С этим входом:

<root>
    <Variable name="var1" dataType="INT32"/>
    <Variable name="var2" dataType="INT16"/>
    <Variable name="var3" dataType="INT8"/>
</root>

Выход:

<root>
    <Variable name="var1" dataType="INT32" size="4" offset="0"></Variable>
    <Variable name="var2" dataType="INT16" size="2" offset="4"></Variable>
    <Variable name="var3" dataType="INT8" size="1" offset="6"></Variable>
</root>

РЕДАКТ. 3: Также эта таблица стилей (режим вперед, лучшая производительность, заимствованный расчет размера Димитра)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:template match="*">
        <xsl:apply-templates select="*[1]|following-sibling::*[1]"/>
    </xsl:template>
    <xsl:template match="Variable">
        <xsl:param name="pOffset" select="0"/>
        <xsl:variable name="vSize" 
                      select="substring-after(@dataType,'INT') div 8"/>
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:attribute name="size">
                <xsl:value-of select="$vSize"/>
            </xsl:attribute>
            <xsl:attribute name="offset">
                <xsl:value-of select="$pOffset"/>
            </xsl:attribute>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::Variable[1]">
            <xsl:with-param name="pOffset" select="$pOffset + $vSize"/>
        </xsl:apply-templates>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<Variable name="var1" dataType="INT32" size="4" offset="0" />
<Variable name="var2" dataType="INT16" size="2" offset="4" />
<Variable name="var3" dataType="INT8" size="1" offset="6" />
0 голосов
/ 28 октября 2010

Я не думаю, что вы можете сделать это с простой суммой, но вы можете создать шаблон с параметрами, которые принимают список узлов и предыдущее смещение.Он вычисляет смещение первого элемента в списке, а затем рекурсивно вызывает себя с новым смещением и оставшимися элементами в списке узлов.

Вы можете увидеть пример шаблона с параметрами на веб-сайте w3schools.Это достаточно хорошее место для поиска информации о большинстве веб-технологий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...