Не удается сгруппировать похожие записи в XSLT

#xslt #xslt-1.0 #xslt-grouping

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

Вопрос:

Я пытаюсь сгруппировать все похожие записи на основе языка. Но я не могу сгруппировать в XSLT. Я использую функцию XSL KEY для группировки записи в XSLT. Я пытаюсь выполнить цикл и добавить записи каждой группы в одну группу.

У меня есть следующий входной xml.

 <root>
    <element name="David" language="German"></element>
    <element name="Sarah" language="German"></element>
    <element name="Isaac" language="English"></element>
    <element name="Abraham" language="German"></element>
    <element name="Jackson" language="English"></element>
    <element name="Deweher" language="English"></element>
    <element name="Jonathan" language="Hindi"></element>
    <element name="Mike" language="Hindi"></element>
</root>
  

XSLT:

 <?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"
    exclude-result-prefixes="xs"
    version="1.0">
    <xsl:key name="lang" match="element" use="@language"></xsl:key>    
    <xsl:template match="/">    
        <root>
            <xsl:for-each select="key('lang',//element/@language)">
                <Group>
                    <xsl:attribute name="name" select=".//@language"></xsl:attribute>
                    <member><xsl:value-of select=".//@name"/></member>                
                </Group>    
            </xsl:for-each>
        </root>
    </xsl:template>
</xsl:stylesheet>
  

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

 <root>
   <Group name="German">
      <member>David</member>
      <member>Sarah</member>
      <member>Abraham</member>
   </Group>
   <Group name="English">
      <member>Isaac</member>
      <member>Jackson</member>
      <member>Deweher</member>
   </Group>
   <Group name="Hindi">
      <member>Jonathan</member>
      <member>Mike</member>
   </Group>
</root>
  

Фактический результат :

 <root>
    <Group name="German">
        <member>David</member>
    </Group>
    <Group name="German">
        <member>Sarah</member>
    </Group>
    <Group name="English">
        <member>Isaac</member>
    </Group>
    <Group name="German">
        <member>Abraham</member>
    </Group>
    <Group name="English">
        <member>Jackson</member>
    </Group>
    <Group name="English">
        <member>Deweher</member>
    </Group>
    <Group name="Hindi">
        <member>Jonathan</member>
    </Group>
    <Group name="Hindi">
        <member>Mike</member>
    </Group>
</root>
  

Я получаю каждую запись отдельно.
Может кто-нибудь, пожалуйста, дайте мне знать, что пошло не так в XSL. Спасибо 🙂

Ответ №1:

Я внес некоторые изменения в вашу таблицу стилей. Это должно привести к ожидаемому результату:

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output indent="yes"/>

    <xsl:key name="lang" match="element" use="@language"></xsl:key>    

    <xsl:template match="root">    
        <xsl:copy>
            <xsl:for-each select="element[count(. | key('lang', @language)[1]) = 1]">
                <Group name="{@language}">
                    <xsl:for-each select="key('lang', @language)">
                        <member><xsl:value-of select="@name"/></member>                
                    </xsl:for-each>
                </Group>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
  

Первый цикл выбирает каждый уникальный язык (набор узлов размером 3) и создает контекст для внутреннего цикла. Внутренний цикл перебирает каждый элемент и выбирает только те, которые имеют тот же язык.

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

ОБНОВЛЕНИЕ: вот решение без использования for-each циклов:

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

    <xsl:output indent="yes"/>

    <xsl:key name="lang" match="element" use="@language"></xsl:key>    

    <xsl:template match="root">    
        <xsl:copy>
            <xsl:apply-templates select="element[generate-id(.) = generate-id(key('lang', @language)[1])]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="element">
        <Group name="{@language}">
            <xsl:apply-templates select="key('lang', @language)" mode="member"/>
        </Group>
    </xsl:template>

    <xsl:template match="element" mode="member">
        <member><xsl:value-of select="@name"/></member>  
    </xsl:template>

</xsl:stylesheet>
  

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

1. Есть ли какой-либо другой способ, которого мы можем достичь только одним циклом for.

2. ДА. На самом деле вы можете избавиться от них всех, используя шаблоны.

3. Спасибо. Это мне помогает.