Группировка и сумма узлов XML с использованием xslt - PullRequest
1 голос
/ 29 сентября 2019

Я довольно новичок в XSLT и застрял сразу.

У меня есть один входной XML-файл, как показано ниже

<Roots>
    <Root>
        <Value1>Links1</Value1>
        <Value2>notadmin</Value2>
        <Count>1</Count>
    </Root>
    <Root>
        <Value1>Links1</Value1>
        <Value2>notadmin</Value2>
        <Count>10</Count>
    </Root>
    <Root>
        <Value1>Links2</Value1>
        <Value2>userxyz</Value2>
        <Count>10</Count>
    </Root>
    <Root>
        <Value1>Links2</Value1>
        <Value2>usermnp</Value2>
        <Count>10</Count>
    </Root>
    <Root>
        <Value1>Links3</Value1>
        <Value2>user123</Value2>
        <Count>5</Count>
    </Root>
    ...
            ...
            ...
</Roots>

Теперь я хочу суммировать значение счетчика дляаналогичные значения Value1 и Value2, чтобы он выглядел следующим образом:

<Roots>
    <Root>
        <Value1>Links1</Value1>
        <Value2>notadmin</Value2>
        <Count>11</Count>
    </Root>

    <Root>
        <Value1>Links2</Value1>
        <Value2>userxyz</Value2>
        <Count>20</Count>
    </Root>

    <Root>
        <Value1>Links3</Value1>
        <Value2>user123</Value2>
        <Count>5</Count>
    </Root>

</Roots>

Я много пытался преобразовать этот XML, и вот мой код:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>

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

<xsl:template match="Roots">
<Roots>
<Root>
<xsl:for-each-group select="Root" group-by=
    "concat(Value1, '+', Value2)">
        <xsl:copy-of select=
    "current-group()[1]/*[starts-with(name(),'key')]"/>

    <Count>
        <xsl:value-of select="sum(current-group()/Count)"/>
    </Count>


</xsl:for-each-group>

    </Root>
</Roots>
</xsl:template>
</xsl:stylesheet>

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

Спасибо

Ответы [ 2 ]

0 голосов
/ 29 сентября 2019

Ваш XSLT был близок, но переместите определение элемента <Root> в xsl:for-each-group. Я не мог понять ваш xsl:copy-of..., поэтому я просто воспроизводил элементы один за другим. Так что используйте эту простую таблицу стилей XSLT-2.0:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

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

    <xsl:template match="/Roots">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:for-each-group select="Root" group-by="Value1">
                <Root>
                    <Value1><xsl:value-of select="current-grouping-key()" /></Value1>
                    <Value2><xsl:value-of select="current-group()[1]/Value2" /></Value2>
                    <Count><xsl:value-of select="sum(current-group()/Count)" /></Count>
                </Root>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Это вывод:

<Roots>
   <Root>
      <Value1>Links1</Value1>
      <Value2>notadmin</Value2>
      <Count>11</Count>
   </Root>
   <Root>
      <Value1>Links2</Value1>
      <Value2>userxyz</Value2>
      <Count>20</Count>
   </Root>
   <Root>
      <Value1>Links3</Value1>
      <Value2>user123</Value2>
      <Count>5</Count>
   </Root>
</Roots>
0 голосов
/ 29 сентября 2019

В данный момент ваша группировка concat(Value1, '+', Value2) не даст трех узлов, поскольку узлы на Links2 поддерживают два разных значения value2 . Кроме того, ваш шаблон преобразования идентификаторов является избыточным, поскольку вы переписываете дерево XML непосредственно из корня, Корни .

Одна группировка (только Значение1)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result-prefixes="xs">
   <xsl:output omit-xml-declaration="yes" indent="yes" />

   <xsl:template match="Roots">
      <Roots>
        <xsl:for-each-group select="Root" group-by="Value1">
            <Root>
                  <xsl:copy-of select="Value1|Value2"/>
                   <Count>
                      <xsl:value-of select="sum(current-group()/Count)" />
                   </Count>
            </Root>
        </xsl:for-each-group>
      </Roots>
   </xsl:template>

</xsl:stylesheet>

Возвращается с первым возвращенным значением2 :

<Roots>
   <Root>
      <Value1>Links1</Value1>
      <Value2>notadmin</Value2>
      <Count>11</Count>
   </Root>
   <Root>
      <Value1>Links2</Value1>
      <Value2>userxyz</Value2>
      <Count>20</Count>
   </Root>
   <Root>
      <Value1>Links3</Value1>
      <Value2>user123</Value2>
      <Count>5</Count>
   </Root>
</Roots>

Две группировки (Значение1 и Значение2)

Сохранение исходной группировки:

<xsl:for-each-group select="Root" group-by="concat(Value1, '+', Value2)">

Возвращает четыре узла

<Roots>
   <Root>
      <Value1>Links1</Value1>
      <Value2>notadmin</Value2>
      <Count>11</Count>
   </Root>
   <Root>
      <Value1>Links2</Value1>
      <Value2>userxyz</Value2>
      <Count>10</Count>
   </Root>
   <Root>
      <Value1>Links2</Value1>
      <Value2>usermnp</Value2>
      <Count>10</Count>
   </Root>
   <Root>
      <Value1>Links3</Value1>
      <Value2>user123</Value2>
      <Count>5</Count>
   </Root>
</Roots>
...