Использование xsl: for-each-group для выбора и агрегирования значений из атрибута - PullRequest
0 голосов
/ 20 февраля 2019

Я пытаюсь использовать xsl: for-each-group, чтобы получить среднюю оценку для каждого пользователя для каждого типа.

Пример XML:

    <Ratings>
    <Rating name="Type1">
        <items userID="001" rating="5"/>
        <items userID="001" rating="3"/>
        <items userID="002" rating="2"/>
        <items userID="003" rating="5"/>
    </Rating>
    <Rating name="Type2">
        <items userID="002" rating="3"/>
        <items userID="003" rating="4"/>
        <items userID="003" rating="3"/>
    </Rating>
    <Rating name="Type3">
        <items userID="002" rating="5"/>
        <items userID="003" rating="5"/>
    </Rating>
</Ratings>

Я получил какнасколько XSLT ниже (начинается с общего шаблона копирования, не показан).

<xsl:template match="Rating">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:attribute name="averageRating">
            <xsl:value-of select="round(avg(items/@rating), 2)"/>
        </xsl:attribute>
        <xsl:for-each-group select="items" group-by="@userID">
            <userRating userID="{@userID}">
                <xsl:for-each select="current-group()">
                    <xsl:attribute name="averageRating">
                        <xsl:value-of select="round(avg(current()/@rating),2)"/>
                    </xsl:attribute>
                </xsl:for-each>
            </userRating>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

Это сближает меня (казалось бы?) - каждый пользователь попадает в список по одному разу, и его оценки для Типа, под которым они сгруппированы, отображаются в атрибуте averageRating.ЗА ИСКЛЮЧЕНИЕМ, когда пользователь внутри Типа имеет более одного рейтинга, отображается только последний рейтинг вместо среднего значения всех оценок этого типа этим пользователем.

Текущий вывод:

    <Ratings>
    <Rating name="Type1" averageRating="3.75">
      <userRating userID="001" averageRating="3"/>
      <userRating userID="002" averageRating="2"/>
      <userRating userID="003" averageRating="5"/>
   </Rating>
    <Rating name="Type2" averageRating="3.33">
      <userRating userID="002" averageRating="3"/>
      <userRating userID="003" averageRating="3"/>
   </Rating>
    <Rating name="Type3" averageRating="5">
      <userRating userID="002" averageRating="5"/>
      <userRating userID="003" averageRating="5"/>
   </Rating>
</Ratings>

Желаемый результат:

    <Ratings>
    <Rating name="Type1" averageRating="3.75">
      <userRating userID="001" averageRating="4"/> <!-- average of 5 and 3 -->
      <userRating userID="002" averageRating="2"/>
      <userRating userID="003" averageRating="5"/>
   </Rating>
    <Rating name="Type2" averageRating="3">
      <userRating userID="002" averageRating="3"/>
      <userRating userID="003" averageRating="3.5"/> <!-- average of 4 and 3 -->
   </Rating>
    <Rating name="Type3" averageRating="5">
      <userRating userID="002" averageRating="5"/>
      <userRating userID="003" averageRating="5"/>
   </Rating>
</Ratings>

Когда я добавляю значение оценок в качестве значения элемента (а не в качестве атрибута), все рейтинги отображаются, но в виде строки, то есть вычисления все ещене работает, например:

      <userRating userID="001">53</userRating>

Спасибо

1 Ответ

0 голосов
/ 20 февраля 2019

Вместо

    <userRating userID="{@userID}">
            <xsl:for-each select="current-group()">
                <xsl:attribute name="averageRating">
                    <xsl:value-of select="round(avg(current()/@rating),2)"/>
                </xsl:attribute>
            </xsl:for-each>
        </userRating>

вы просто хотите

<userRating userID="{@userID}" averageRating="{round(avg(current-group()/@rating),2)}">
...