Группировка внутри каждого цикла: xsl 1.0

У меня есть этот XML, сгруппированный по странам. При сохранении последовательности узел со значением @country является родительским, а дочерние элементы — это элементы с пустой страной под ним.

<catalog> 
<cd> 
    <country>USA</country> 
    <artist>Bob Dylan</artist> 
</cd> 
<cd> 
    <country></country> 
    <artist>Percy Sledge</artist> 
</cd> 
<cd> 
    <country></country> 
    <artist>Joe Cocker</artist> 
</cd> 
<cd> 
    <country>UK</country> 
    <artist>Kenny Rogers</artist> 
</cd> 
<cd> 
    <country></country> 
    <artist>Bonnie Tyler</artist> 
</cd> 
</catalog>

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

Страна Художник США Боб Дилан, Перси Следж, Джо Кокер Великобритания Кенни Роджерс, Бонни Тайлер

Это то, что я имел в виду. Первый цикл foreach фильтрует все узлы по стране, а второй для каждого цикла предназначен для поиска всех узлов с одной и той же страной и всех пустых стран под этим узлом. У меня проблемы со вторым для каждого цикла. не мог понять, как сделать цикл.

Я ценю всю помощь. Спасибо.

<table> 
<tr > <th>country</th> <th>Artist</th> </tr> 
<xsl:for-each select = "catalog/cd[not(country='')]"> 
    <xsl:variable name = "cntry" select = "country"/> 
    <tr> 
        <td><xsl:value-of select = "$cntry" /></td> 
        <xsl:for-each select = "catalog/cd[country='$cntry' or catalog/cd[country='']]"> 
            <td><xsl:value-of select = "artist" /></td> 
        </xsl:for-each> 
    </tr> 
</xsl:for-each> 
</table>

Почему ваш вопрос также помечен как xslt-2.0, хотя xsl 1.0 есть и в заголовке, и в тексте? Это тривиальная проблема в XSLT 2.0, где вы можете использовать xsl:for-each-group с group-starting-with.

michael.hor257k 04.05.2024 22:40
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Адаптация ответа (для XSLT 1.0) из https://stackoverflow.com/a/74612904/3016153:

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

<xsl:key name = "k1" match = "cd[not(country/text())]" use = "preceding-sibling::cd[country/text()][1]/country" />

<xsl:template match = "/catalog">
    <table border = "1">
        <tr>
            <th>Country</th>
            <th>Artist</th> 
        </tr>
        <xsl:for-each select = "cd[country/text()]">
            <tr> 
                <td>
                    <xsl:value-of select = "country"/>
                </td> 
                <td>
                    <xsl:for-each select = ". | key('k1', country)">
                        <xsl:value-of select = "artist"/>
                        <xsl:if test = "position() != last()">, </xsl:if>
                    </xsl:for-each> 
                </td>
            </tr>
        </xsl:for-each>
    </table>
</xsl:template>

</xsl:stylesheet>

Лучше всего это решить с помощью метода, называемого одноуровневой рекурсией, как описано, например, в Группируйте определенные элементы в таблицах с помощью xslt 1.0

Основной подход:

Для родительского элемента примените шаблоны к первому дочернему элементу.

<xsl:template match = "catalog">
  <table><xsl:apply-templates select = "cd[1]"/></table>
</xsl:template>

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

<xsl:template match = "cd[normalize-space(country)]">
  <tr>
    <td><xsl:value-of select = "country"/></td>
    <td>
       <xsl:value-of select = "artist"/>
       <xsl:value-of select = "following-sibling::cd
                             [1][not(normalize-space(country))]"/>
    </td>
  </tr>
  <xsl:apply-templates select = "following-sibling::cd
                               [normalize-space(country)][1]"/>
</xsl:template>

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

<xsl:template match = "cd[not(normalize-space(country))]">
   <xsl:text>, </xsl:text>
   <xsl:value-of select = "artist"/>
   <xsl:apply-templates select = "following-sibling::cd
                                [1][not(normalize-space(country))]"/>
</xsl:template>

Обратите внимание на различие между following-sibling::*[condition][1], который выбирает первого следующего брата, удовлетворяющего условию, и following-sibling::*[1][condition], который выбирает первого следующего брата, при условии, что он удовлетворяет условию.

Спасибо. Я узнал что-то новое сегодня. Я ценю ваш ответ.

t2lhe 07.05.2024 03:24

Другие вопросы по теме