Как я должен группировать данные в xslt?

#xslt #xslt-1.0 #xslt-grouping

#xslt #xslt-1.0 #xslt-группировка

Вопрос:

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

Ввод

 <TEST>
     <RESPONSE>
        <NUMBER>XXXX</NUMBER>
        <HISTORY>
             <Period Year="2013" Month="Apr" Value="77"></Period>
             <Period Year="2013" Month="Mar" Value="99"></Period>
             <Period Year="2013" Month="Feb" Value="88"></Period>
             <Period Year="2012" Month="Jan" Value="11"></Period>
             <Period Year="2012" Month="Mar" Value="22"></Period>
             <Period Year="2011" Month="Apr" Value="444"></Period>
         </HISTORY>
     </RESPONSE>
     <RESPONSE>
        <NUMBER>ZZZZ</NUMBER>
        <HISTORY>
             <Period Year="2016" Month="Jan" Value="999"></Period>
             <Period Year="2016" Month="Mar" Value="454"></Period>
             <Period Year="2015" Month="Dec" Value="234"></Period>
             <Period Year="2014" Month="Jan" Value="767"></Period>
             <Period Year="2014" Month="Sep" Value="667"></Period>
             <Period Year="2013" Month="May" Value="112"></Period>
         </HISTORY>
     </RESPONSE>
</TEST>
  

Ожидаемый результат

 <TEST>
     <RESPONSE>
        <NUMBER>XXXX</NUMBER>
        <HISTORY>
             <Period Year="2013" Month="Apr" Value="77"></Period>
             <Period Year="2013" Month="Mar" Value="99"></Period>
             <Period Year="2013" Month="Feb" Value="88"></Period>
             <Period Year="2012" Month="Jan" Value="11"></Period>
             <Period Year="2012" Month="Mar" Value="22"></Period>
             <Period Year="2011" Month="Apr" Value="444"></Period>
         </HISTORY>
         <GROUP-HISTORY>
                <YEAR Value="2013">
                        <Months Month="Apr" Value="77"/>
                        <Months Month="Mar" Value="99"/>
                        <Months Month="Feb" Value="88"/>
                </YEAR>
                <YEAR Value="2012">
                        <Months Month="Jan" Value="11"/>
                        <Months Month="Mar" Value="22"/>
                </YEAR>
                <YEAR Value="2011">
                        <Months Month="Apr" Value="444"/>       
                </YEAR>
         </GROUP-HISTORY>
     </RESPONSE>
     <RESPONSE>
        <NUMBER>ZZZZ</NUMBER>
        <HISTORY>
             <Period Year="2016" Month="Jan" Value="999"></Period>
             <Period Year="2016" Month="Mar" Value="454"></Period>
             <Period Year="2015" Month="Dec" Value="234"></Period>
             <Period Year="2014" Month="Jan" Value="767"></Period>
             <Period Year="2014" Month="Sep" Value="667"></Period>
             <Period Year="2013" Month="May" Value="112"></Period>
         </HISTORY>
         <GROUP-HISTORY>
                <YEAR Value="2016">
                        <Months Month="Jan" Value="999"/>
                        <Months Month="Mar" Value="454"/>   
                </YEAR>
                <YEAR Value="2015">
                        <Months Month="Dec" Value="234"/>       
                </YEAR>
                <YEAR Value="2014">
                        <Months Month="Jan" Value="767"/>   
                        <Months Month="Sep" Value="667"/>                               
                </YEAR>
                <YEAR Value="2013">
                        <Months Month="May" Value="112"/>       
                </YEAR>
         </GROUP-HISTORY>
     </RESPONSE>
</TEST>
  

Пример xslt

 <xsl:stylesheet xmlns:xalan="http://xml.apache.org/xalan"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
    version="1.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:key name="years" match="/TEST/RESPONSE/HISTORY/Period" use="@Year"/>
    <xsl:template match="TEST">
        <xsl:element name="TEST">
            <xsl:apply-templates select="RESPONSE"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="HISTORY">
        <xsl:element name="GROUP-HISTORY">
            <xsl:for-each
                select="/TEST/RESPONSE/HISTORY/Period[generate-id(.) = generate-id(key('years', @Year)[1])]">
                <xsl:sort select="@Year" order="descending"/>
                <xsl:variable name="currY" select="@Year"/>
                <xsl:element name="Year">
                    <xsl:attribute name="Value">
                        <xsl:value-of select="$currY"/>
                    </xsl:attribute>
                    <xsl:for-each select="/TEST/RESPONSE/HISTORY/Period[@Year = $currY]">
                        <xsl:element name="Months">
                            <xsl:attribute name="Month">
                                <xsl:value-of select="@Month"/>
                            </xsl:attribute>
                            <xsl:attribute name="Value">
                                <xsl:value-of select="@Value"/>
                            </xsl:attribute>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>
  

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

1. Не могли бы вы, пожалуйста, опубликовать свой XSLT, чтобы мы могли исправить любую проблему, которая в нем есть? Если вы используете xsl:key , то вы, возможно, на самом деле не являетесь этим для решения. Спасибо!

2. вы можете найти xslt выше

Ответ №1:

Основная проблема заключается в том, что вам необходимо учитывать NUMBER в вашем ключе, иначе вы сгруппируете все совпадающие годы по всему вашему документу

 <xsl:key name="years" match="Period" use="concat(../../NUMBER, '|', @Year)"/>
  

Кроме того, для вашего первого xsl:for-each , вы начинаете выражение select с /TEST/RESPONSE/HISTORY/Period , которое также будет проверять все периоды в документе, когда вам действительно нужно, чтобы они были относительно текущего HISTORY , вот так:

 <xsl:for-each select="Period[generate-id(.) = generate-id(key('years', concat(../../NUMBER, '|', @Year))[1])]">
  

Попробуйте этот XSLT

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

    <xsl:key name="years" match="Period" use="concat(../../NUMBER, '|', @Year)"/>

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

    <xsl:template match="HISTORY">
        <xsl:call-template name="identity" />
        <GROUP-HISTORY>
            <xsl:for-each select="Period[generate-id(.) = generate-id(key('years', concat(../../NUMBER, '|', @Year))[1])]">
                <xsl:sort select="@Year" order="descending"/>
                <xsl:variable name="currY" select="@Year"/>
                <Year Value="{$currY}">
                    <xsl:for-each select="key('years', concat(../../NUMBER, '|', $currY))">
                        <Months Month="{@Month}" Value="{@Value}" />
                    </xsl:for-each>
                </Year>
            </xsl:for-each>
        </GROUP-HISTORY>
    </xsl:template>
</xsl:stylesheet>
  

Обратите внимание:

  1. Вам не нужно указывать полный путь к соответствующему элементу в xsl:key (если только у вас нет других элементов с таким же именем, но разными путями, которые вы не хотите сопоставлять).
  2. Ваше сопоставление с шаблоном TEST было ненужным, поскольку шаблон идентификации делал бы то же самое.
  3. Вам не нужно использовать, xsl:element где имя элемента является статическим. Просто выпишите тег элемента напрямую.
  4. Вы можете использовать шаблоны значений атрибутов для упрощения создания атрибутов.

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

1. Привет, Тим, спасибо за твой вклад, но в некоторых случаях я получаю ЧИСЛО в виде дубликатов, тогда как мне с этим справиться

2. Вы можете увидеть это в действии на xsltfiddle. liberty-development.net/ej9EGcn . Вы добавили еще какие-нибудь шаблоны в XSLT?

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

4. Тогда у вас может быть несколько RESPONSE элементов с одинаковыми NUMBER значениями в вашем реальном XML?

5. да, у меня есть несколько элементов ОТВЕТА с одинаковым номером в реальном XML