Группировка XSLT и удаление дубликатов

У меня есть следующий входной файл XML:

<mappings>
    <mapping>
        <key>6718</key>
        <value attribute="content_type">Info Page</value>
    </mapping>
    <mapping>
        <key>35905</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>6718</key>
        <value attribute="content_type">Info Page</value>
    </mapping>
    <mapping>
        <key>36941</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>24920</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>40244</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>36639</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>1861</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>2280</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>42062</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
</mappings>

Я хотел бы создать следующий XML:

<reductions>
    <reduction>
        <group>Info Page</group>
        <key>6718</key>
    </reduction>
    <reduction>
        <group>Press releases</group>
        <key>35905</key>
        <key>36941</key>
        <key>24920</key>
        <key>40244</key>
        <key>36639</key>
        <key>1861</key>
        <key>2280</key>
        <key>42062</key>
    </reduction>
</reductions>

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

Я использую XSLT 2.0 с Saxon 9 HE.

Кто-нибудь может мне помочь?

[EDIT]

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform 
    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:template match="/">
        <xsl:variable name="mappings">
            <mappings>
                <xsl:apply-templates select="resource/R"/>
            </mappings>
        </xsl:variable>
        <reductions>
            <xsl:apply-templates select="$mappings/*"/>
        </reductions>
    </xsl:template>

    <xsl:template match="R">
        <mapping>
            <key><xsl:value-of select="MT[@N='content_id']/@V"/></key>
            <value>
                <xsl:attribute name="attribute">content_type</xsl:attribute>
                <xsl:value-of select="MT[@N='content_type']/@V"/>
            </value>
        </mapping>
        <!--mapping>
            <key><xsl:value-of select="MT[@N='content_id']/@V"/></key>
            <value>
                <xsl:attribute name="attribute">modified_timestamp</xsl:attribute>
                <xsl:value-of select="format-dateTime(MT[@N='modified_timestamp']/@V, '[Y0001]-[M01]-[D01]')"/>
            </value>
        </mapping-->
    </xsl:template>

    <xsl:template match="mapping">
        <xsl:for-each-group select="." group-by="value">
            <reduction>
                <group><xsl:value-of select="current-grouping-key()"/></group>
                <xsl:for-each-group select="current-group()/key" group-by=".">
                    <xsl:copy-of select="."/>
                </xsl:for-each-group>
            </reduction>
        </xsl:for-each-group>
    </xsl:template>

</xsl:transform>

person mmjmanders    schedule 30.05.2012    source источник


Ответы (1)


Вот таблица стилей, дважды использующая for-each-group:

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

<xsl:output indent="yes"/>

<xsl:template match="mappings">
  <reductions>
    <xsl:for-each-group select="mapping" group-by="value">
      <reduction>
        <group><xsl:value-of select="current-grouping-key()"/></group>
        <xsl:for-each-group select="current-group()/key" group-by=".">
          <xsl:copy-of select="."/>
        </xsl:for-each-group>
      </reduction>
    </xsl:for-each-group>
  </reductions>
</xsl:template>

</xsl:stylesheet>

[править] Когда я запускаю опубликованную таблицу стилей с помощью Saxon 9.4 HE против ввода

<mappings>
    <mapping>
        <key>6718</key>
        <value attribute="content_type">Info Page</value>
    </mapping>
    <mapping>
        <key>35905</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>6718</key>
        <value attribute="content_type">Info Page</value>
    </mapping>
    <mapping>
        <key>36941</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>24920</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>40244</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>36639</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>1861</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>2280</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
    <mapping>
        <key>42062</key>
        <value attribute="content_type">Press releases</value>
    </mapping>
</mappings>

я получаю результат

<reductions>
   <reduction>
      <group>Info Page</group>
      <key>6718</key>
   </reduction>
   <reduction>
      <group>Press releases</group>
      <key>35905</key>
      <key>36941</key>
      <key>24920</key>
      <key>40244</key>
      <key>36639</key>
      <key>1861</key>
      <key>2280</key>
      <key>42062</key>
   </reduction>
</reductions>

что правильно, насколько я понимаю ваши требования.

person Martin Honnen    schedule 30.05.2012
comment
Это не ожидаемый результат. Я получаю столько же узлов «редукции», сколько и узлов «отображения» во входных данных, каждый из которых имеет ровно один элемент «группа» и один элемент «ключ». Они вообще не сгруппированы. - person mmjmanders; 30.05.2012
comment
Извините, я не понимаю, почему вы получили такой результат. Я тестировал Saxon 9.4, и результат, который я сейчас включил в свой ответ, кажется вам тем, что вы хотите. Предоставьте подробную информацию об используемом вами процессоре XSLT 2.0 и о том, есть ли какие-либо подробности, такие как пространства имен, во входных данных, которые вы пропустили в своем сообщении. - person Martin Honnen; 30.05.2012
comment
Когда я запускаю командную строку, она работает, но при вызове из приложения Java она не работает. - person mmjmanders; 30.05.2012
comment
Странно, написали ли вы код для приложения Java в соответствии с рекомендациями на saxonica. com/documentation/using-xsl/embedding.xml? Вы уверены, что это один и тот же входной документ, который вы обрабатываете из командной строки и из приложения? - person Martin Honnen; 30.05.2012
comment
Я приложил свой XSL, который я использую, он немного отличается, но я не понимаю, почему он не работает. - person mmjmanders; 30.05.2012
comment
Ну, вы поместили первый for-each-group в неправильное место, вы хотите сгруппировать mapping дочерние узлы элемента mappings, но в своем коде вы пытаетесь применить группировку к каждому отдельному mapping. Поэтому используйте код, который я опубликовал, с «для каждой группы», выполненным в шаблоне, соответствующем mappings, а не в шаблоне, соответствующем mapping, поскольку тогда у вас нет нужного группового населения. - person Martin Honnen; 30.05.2012