XSLT1, группировка по Мюнху, список сгруппированных узлов в цикле foreach

Учитывая xml-код

<z>
<f hit="1">
<g>hola1</g>
</f>
<f hit="2">
<g>hola2</g>
</f>
<f hit="3">
<g>hola1</g>
</f>
</z>

Я хочу иметь вывод xml

<z>
hola1
hola2
</z>

с помощью xslt1. Тогда простым решением будет мюнхианская группировка

<xsl:key name="thisone" match="/z/f/g" use="." />
<z>
<xsl:for-each select="/z/f[generate-id(g)=generate-id(key('thisone',g)[1])]">
<xsl:value-of select="g" />
</xsl:for-each>
</z>

Однако, когда я применяю это к большому набору данных, система (firefox) продолжает думать вечно. Я предполагаю, что это связано с действительно большим набором данных. Однако количество различных значений «g» действительно невелико.

Мой вопрос: есть ли способ сделать цикл для каждого узла мюнхианской группировки? Что-то типа

<xsl:for-each select="nodes_of_key('thisone')">

Это позволит избежать сравнения всех значений всех узлов «g», что занимает вечность?

Спасибо


person GWorking    schedule 20.11.2012    source источник


Ответы (1)


Для решения этой проблемы не требуется никаких <xsl:for-each> инструкций (и этой инструкции лучше избегать):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kFByG" match="f" use="g"/>

 <xsl:template match="/*">
     <z>
      <xsl:apply-templates/>
      <xsl:text>&#xA;</xsl:text>
     </z>
 </xsl:template>

 <xsl:template match="f[generate-id()=generate-id(key('kFByG',g)[1])]">
     <xsl:text>&#xA;</xsl:text>
     <xsl:value-of select="g"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному XML-документу:

<z>
    <f hit="1">
        <g>hola1</g>
    </f>
    <f hit="2">
        <g>hola2</g>
    </f>
    <f hit="3">
        <g>hola1</g>
    </f>
</z>

получен желаемый правильный результат:

<z>
hola1
hola2
</z>
person Dimitre Novatchev    schedule 20.11.2012
comment
Да, но используется то же сравнение. Моя проблема в том, что это работает, когда у меня есть небольшой файл для обработки, но когда этот файл больше, браузер продолжает обрабатывать вечно. Поэтому мой вопрос, есть ли способ избежать сравнения всех узлов и просто просмотреть те, которые хранятся в ключе xsl: (если такое возможно) - person GWorking; 21.11.2012
comment
@Gerard, это решение на основе ключей, и оно на несколько порядков быстрее (близко к O (1)), чем сравнение значения со всеми другими значениями (O (N ^ 2)). - person Dimitre Novatchev; 21.11.2012
comment
@ Джерард, просмотр всех узлов линейный - это очень быстро, вероятно, доли секунды даже для размера сотен МБ. - person Dimitre Novatchev; 21.11.2012
comment
Но тогда, что я могу сделать? Я понимаю (я ошибаюсь?), что инструкция foreach не рекомендуется из-за стиля (шаблоны имеют больше смысла в xslt), но если она не имеет последствий в эффективности (я ошибаюсь?), то key-based сравнение занимает вечность в файле размером 7 МБ из 20 000 записей (каждая запись станет узлом для сравнения). Что я мог сделать? - person GWorking; 21.11.2012
comment
@ Джерард, это не имеет ничего общего с тем, используется ли xsl:for-each. 7-мегабайтный файл можно обработать за долю секунды — это совсем не большой файл. Несколько сотен МБ можно обработать за 2-3 секунды. Если ваша трансформация занимает так много времени, есть какая-то другая проблема, а не мюнхианская группировка. Проблема может быть вообще не связана с XSLT-преобразованием. Я видел случаи, когда генерировалась огромная таблица: преобразование занимает меньше секунды, но браузеру требуется вечность, чтобы отформатировать таблицу для отображения. Есть лекарства от этого (какой-то стиль?), которого я не помню. - person Dimitre Novatchev; 21.11.2012
comment
@Gerard, например, не создавайте одну огромную таблицу, а создавайте несколько таблиц (разделите большую таблицу на дюжину меньших). Или вообще не генерировать таблицу, а генерировать последовательность абзацев. - person Dimitre Novatchev; 21.11.2012
comment
@ Джерард, я только что провел эксперимент. Мюнховское группирование 20000 элементов по значению заняло 237 миллисекунд — это примерно одна пятая секунды. - person Dimitre Novatchev; 21.11.2012
comment
Спасибо, Дмитрий (я пропустил последние сообщения и читаю их сейчас). Иногда я слишком сосредоточен на использовании xslt для всего. Я поверил вам в том смысле, что виноват не xslt, а firefox. Затем, поскольку я создаю файл xml с помощью javascript, я просто создаю группу узлов с уникальными именами в xml, поэтому xslt может легко получить доступ к этому массиву, не задумываясь. А то файрфокс просто быстро работает. Простой обходной путь, я думаю :) - person GWorking; 22.11.2012
comment
@ Джерард, пожалуйста. И не нужно мне верить. Просто проведите эксперимент (как это сделал я) и выполните преобразование отдельно от браузера, и посмотрите, сколько времени это займет. Если преобразование включает только мюнховскую группировку, то время, затрачиваемое на это, будет меньше секунды. - person Dimitre Novatchev; 22.11.2012