Как я могу отсортировать элементы по новым подсчитанным значениям в их дочерних элементах. XSLT 1.0 - PullRequest
3 голосов
/ 17 июня 2011

У меня есть лист XML такого типа:

<houses>
    <house number="1">
        <mainroom>
            <roomprice>5</roomprice>
            <roomtax>2</roomtax>
        </mainroom>
        <roompricefull>
            <price value="8"/>
        </roompricefull>
    </house>
    <house number="2">
        <mainroom>
            <roomprice>3</roomprice>
            <roomtax>1</roomtax>
        </mainroom>
        <roompricefull>
            <price value="7"/>
        </roompricefull>
    </house>
    <house number="3">
        <mainroom>
            <roomprice>9</roomprice>
            <roomtax>1</roomtax>
        </mainroom>
        <roompricefull>
            <price value="4"/>
        </roompricefull>
    </house>
    <house number="4">
        <mainroom>
            <roomprice>12</roomprice>
            <roomtax>3</roomtax>
        </mainroom>
        <roompricefull>
            <price value="6"/>
        </roompricefull>
    </house>
</houses>

поэтому мне пришлось изменить значение атрибута "value" в элементе "price" в каждом из "house" с суммой значений "roomprice" и "roomtax"

Я написал xsl-преобразование такого вида:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template name="PriceChange" match="price[parent::roompricefull]">
        <xsl:copy>
            <xsl:variable name="sn" select="../../@number"/>
            <xsl:variable name="TaxValue" select="number(//house[@number=string($sn)]/mainroom/roomtax)"/>
            <xsl:variable name="BaseValue" select="number(//house[@number=string($sn)]/mainroom/roomprice)"/>
            <xsl:attribute name="value">
                <xsl:value-of select="string($TaxValue+$BaseValue)"/>
            </xsl:attribute>
            <!--xsl:for-each select="/houses/house">
            <xsl:sort select="houses/house[$sn]/roompricefull/@value"/>
        </xsl:for-each-->
        </xsl:copy> 
    </xsl:template>
</xsl:stylesheet>

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

Я получил это:

<houses>
    <house number="1">
        <mainroom>
            <roomprice>5</roomprice>
            <roomtax>2</roomtax>
        </mainroom>
        <roompricefull>
            <price value="7"/>
        </roompricefull>
    </house>
    <house number="2">
        <mainroom>
            <roomprice>3</roomprice>
            <roomtax>1</roomtax>
        </mainroom>
        <roompricefull>
            <price value="4"/>
        </roompricefull>
    </house>
    <house number="3">
        <mainroom>
            <roomprice>9</roomprice>
            <roomtax>1</roomtax>
        </mainroom>
        <roompricefull>
            <price value="10"/>
        </roompricefull>
    </house>
    <house number="4">
        <mainroom>
            <roomprice>12</roomprice>
            <roomtax>3</roomtax>
        </mainroom>
        <roompricefull>
            <price value="15"/>
        </roompricefull>
    </house>
</houses>

Но ожидаемый результат был:

<houses>
    <house number="4">
        <mainroom>
            <roomprice>12</roomprice>
            <roomtax>3</roomtax>
        </mainroom>
        <roompricefull>
            <price value="15"/>
        </roompricefull>
    </house>   
    <house number="3">
        <mainroom>
            <roomprice>9</roomprice>
            <roomtax>1</roomtax>
        </mainroom>
        <roompricefull>
            <price value="10"/>
        </roompricefull>
    </house>
    <house number="1">
        <mainroom>
            <roomprice>5</roomprice>
            <roomtax>2</roomtax>
        </mainroom>
        <roompricefull>
            <price value="7"/>
        </roompricefull>
    </house>
    <house number="2">
        <mainroom>
            <roomprice>3</roomprice>
            <roomtax>1</roomtax>
        </mainroom>
        <roompricefull>
            <price value="4"/>
        </roompricefull>
    </house>
</houses>

Было бы здорово, если бы вы помогли мне разобраться и объяснить, почему мой пример не работает. Кажется, я не понимаю значения , но все, что я нахожу, говорит мне об использовании этого без каких-либо объяснений. Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 18 июня 2011

было бы здорово, если бы вы могли помочь мне с сортировкой

Это правильный подход XSLT 1.0.

Обратите внимание на правильное использованиеxsl:sort, для которого необходимо:

  • тип данных, который должен быть указан, являющийся строкой по умолчанию, в то время как нам нужно здесь число
  • лучшее использование сортировки в xsl:apply-templates
  • применении сортировки с ключами сортировки входного документа, объединенными по мере необходимости (сумма).
  • порядок сортировки также длябыть заданным по умолчанию ascending

    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="houses">
       <xsl:copy>
        <xsl:apply-templates select="house">
            <xsl:sort select="mainroom/roomprice + mainroom/roomtax" 
             data-type="number"
             order="descending"/>
        </xsl:apply-templates>
       </xsl:copy>
    </xsl:template>
    
    <xsl:template match="price/@value">
        <xsl:value-of select="
            ../../../mainroom/roomprice 
            + 
            ../../../mainroom/roomtax"/>
    </xsl:template>
    


, объясняя, почему мой пример неworking

Ваше преобразование не работает главным образом потому, что вы пытаетесь отсортировать элементы в неправильном контексте (внутри шаблона, соответствующего глубокому дочернему элементу в дереве).Более того:

  • вы пытаетесь отсортировать, указав ключ сортировки по шаблону абсолютного XPath.
  • вы не указываете необходимые xsl:sort атрибуты
  • , вы хотите, чтобы конечные элементы были отсортированы в соответствии со значением, рассчитанным впоследствии и не представленным во входном документе.Это не правильный подход.Вы всегда должны использовать значения, присутствующие во входном документе, в конечном итоге правильно их комбинируя.
0 голосов
/ 17 июня 2011

Сортировать по новой цене:

<xsl:template match="/">
  <xsl:for-each select="house">
    <xsl:sort select="mainroom/roomprice + mainroom/roomtax"/>
    <xsl:apply-templates select="."/>
  </xsl:for-each>
</xsl:template>

Как и прежде:

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

Отрегулируйте цену на выходе:

<xsl:template match="roompricefull">
  <roompricefull>
    <price value="{../mainroom/roomprice + ../mainroom/roomtax}"/>
  </roompricefull>
</xsl:template>
...