Условный итог XSL

#xslt #conditional

#xslt #условные операторы

Вопрос:

Возможно ли выполнить условное суммирование в xsl?

У меня есть следующий образец xml:

 <?xml version="1.0" encoding="utf-8"?>
<export>
<stats set="1">
  <columns>
    <column id="0">
      <sum>100</sum>
    </column>
    <column id="1">
      <sum>102</sum>
    </column>
    <column id="2">
      <sum>12</sum>
    </column>
  </columns>
</stats>
  <stats set="2">
    <columns>
      <column id="0">
        <sum>100</sum>
      </column>
      <column id="1">
        <sum>101</sum>
      </column>
      <column id="2">
        <sum>19</sum>
      </column>
    </columns>
  </stats>
</export>
  

Возможно ли вычислить общее количество всех столбцов в каждом наборе статистики, где они не равны друг другу? Таким образом, это привело бы к следующему:

                Set 1       Set 2       Diff(Set 1 - Set 2)
Total (Diff)   114         120           -6
column 2       102         101            1  
column 3       12          19            -7 
  

Таким образом, в выходном столбце 1 будет опущен, поскольку сумма в двух наборах статистики одинакова.

Я могу заставить свой xsl выводить столбцы, которые отличаются, но не уверен, как их суммировать и поместить в итоговую строку.

Большое спасибо,

Иез

Комментарии:

1. Отредактируйте свой пост, чтобы включить свой XSL

2. Отличный вопрос, 1. Смотрите мой ответ для получения полного и эффективного решения и подробных объяснений. 🙂

Ответ №1:

Это преобразование (64 строки):

 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:key name="kColByPosAndVal" match="column"
  use="concat(count(preceding-sibling::*),
              ' ',
              sum)"/>
 <xsl:key name="kIdByVal" match="column/@id"
  use="."/>

 <xsl:template match="/*">
  <xsl:variable name="vsum1" select=
   "sum(stats[@set=1]/*/column
                  [not(key('kColByPosAndVal',
                            concat(count(preceding-sibling::*),
                                  ' ',
                                   sum)
                           )[2]
                       )])"/>
  <xsl:variable name="vsum2" select=
   "sum(stats[@set=2]/*/column
                  [not(key('kColByPosAndVal',
                            concat(count(preceding-sibling::*),
                                  ' ',
                                   sum)
                           )[2]
                       )])"/>

                 Set 1          Set 2       Diff(Set 1 - Set 2)
  Total (Diff)   <xsl:text/>
  <xsl:value-of select="$vsum1"/>
  <xsl:text>             </xsl:text>
  <xsl:value-of select="$vsum2"/>
  <xsl:text>             </xsl:text>
  <xsl:value-of select="$vsum1 -$vsum2"/>
  <xsl:text>amp;#xA;</xsl:text>

  <xsl:for-each select=
   "*/*/column/@id
       [generate-id()
       = generate-id(key('kIdByVal',.)[1])
       ]
       [not(key('kColByPosAndVal',
                concat(count(../preceding-sibling::*),
                       ' ',
                       ../sum)
                )[2]
            )]">
    <xsl:variable name="vcolSet1" select=
     "/*/stats[@set=1]/*/column[@id=current()]/sum"/>

    <xsl:variable name="vcolSet2" select=
     "/*/stats[@set=2]/*/column[@id=current()]/sum"/>
  Column <xsl:value-of select=". 1"/><xsl:text/>
    <xsl:text>       </xsl:text>
    <xsl:value-of select="$vcolSet1"/>
    <xsl:text>             </xsl:text>
    <xsl:value-of select="$vcolSet2"/>
    <xsl:text>             </xsl:text>
    <xsl:value-of select="$vcolSet1 -$vcolSet2"/>
    <xsl:text>amp;#xA;</xsl:text>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>
  

при применении к предоставленному XML-документу:

 <export>
<stats set="1">
  <columns>
    <column id="0">
      <sum>100</sum>
    </column>
    <column id="1">
      <sum>102</sum>
    </column>
    <column id="2">
      <sum>12</sum>
    </column>
  </columns>
</stats>
  <stats set="2">
    <columns>
      <column id="0">
        <sum>100</sum>
      </column>
      <column id="1">
        <sum>101</sum>
      </column>
      <column id="2">
        <sum>19</sum>
      </column>
    </columns>
  </stats>
</export>
  

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

                  Set 1          Set 2       Diff(Set 1 - Set 2)
  Total (Diff)   114             120             -6

  Column 2       102             101             1

  Column 3       12             19             -7
  

Объяснение:

  1. Ключ с именем kColByPosAndVal используется для выбора всех столбцов, которые имеют заданную позицию (среди всех column братьев и сестер) и заданное значение для их sum дочернего элемента.

  2. Указанный ключ kIdByVal используется в группировке по-мюнхенски для поиска всех различных значений для id атрибута.

  3. Два итога вычисляются с суммированием только тех столбцов, kColByPosAndVal ключ которых выбирает только один column элемент (если он выбирает два column элемента, они оба находятся в одной позиции и имеют одинаковый размер sum ).

  4. Остальное должно быть легко понять.

Комментарии:

1. Спасибо за это, Дмитрий. Я попробую это в ближайшее время.

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

3. отлично, спасибо. Я попробовал, и это делает то, на что я надеялся. Кроме того, спасибо за пояснения — они действительно помогают — я все еще относительно новичок в XSL. Приветствую, Андез