Полный xslt новичок. Как мне объединить эти 2 источника xml в xslt версии 1.0. применяя группировку и сортировку?

Источник трансформации

Данные1.xml

 <DEALERSHIP reg_number="01234567">
 <MANUFACTURER name="VAUXHALL">
     <CAR>
        <CAR_VIN>12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>ASTRA</CAR_MODEL>
        <CAR_REG_DATE>20060331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>HH54 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
    <CAR>
        <CAR_VIN>12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>ASTRA</CAR_MODEL>
        <CAR_REG_DATE>20040331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>HH54 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
     <CAR>
        <CAR_VIN>12345678901234567</CAR_VIN>
        <CAR_ENG>2.5</CAR_ENG>
        <CAR_MODEL>CALIBRA</CAR_MODEL>
        <CAR_REG_DATE>20030331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>HH54 RRY</CAR_REG>
        <COLOUR>BLUE</COLOUR>
    </CAR>
</MANUFACTURER>
<MANUFACTURER name="FORD">
     <CAR>
        <CAR_VIN>12345678901234567</CAR_VIN>
        <CAR_ENG>2.5</CAR_ENG>
        <CAR_MODEL>CMAX</CAR_MODEL>
        <CAR_REG_DATE>20050331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>HH54 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
    </MANUFACTURER>

The external data Data2.xml

<DEALERSHIP reg_number="01234567">
<MANUFACTURER name="VAUXHALL">
    <CAR>
        <CAR_VIN>XXX12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>ASTRA</CAR_MODEL>
        <CAR_REG_DATE>20060331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>SS00 RRY</CAR_REG>
        <COLOUR>BLUE</COLOUR>
    </CAR>
    <CAR>
        <CAR_VIN>XXX12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>ASTRA</CAR_MODEL>
        <CAR_REG_DATE>20060331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>SS00 RRY</CAR_REG>
        <COLOUR>BLUE</COLOUR>
    </CAR>
</MANUFACTURER>
<MANUFACTURER name="TOYOTA">
    <CAR>
        <CAR_VIN>XXX12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>Corolla</CAR_MODEL>
        <CAR_REG_DATE>20030812</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>SS00 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
</MANUFACTURER>

required output

<DEALERSHIP reg_number="01234567">
<MANUFACTURER name="VAUXHALL">
    <CAR>
        <CAR_VIN>XXX12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>ASTRA</CAR_MODEL>
        <CAR_REG_DATE>20060331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>SS00 RRY</CAR_REG>
        <COLOUR>BLUE</COLOUR>
    </CAR>
    <CAR>
        <CAR_VIN>XXX12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>ASTRA</CAR_MODEL>
        <CAR_REG_DATE>20060331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>SS00 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
    <CAR>
        <CAR_VIN>12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>ASTRA</CAR_MODEL>
        <CAR_REG_DATE>20040331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>HH54 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
    <CAR>
        <CAR_VIN>12345678901234567</CAR_VIN>
        <CAR_ENG>2.5</CAR_ENG>
        <CAR_MODEL>CALIBRA</CAR_MODEL>
        <CAR_REG_DATE>20030331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>HH54 RRY</CAR_REG>
        <COLOUR>BLUE</COLOUR>
    </CAR>

</MANUFACTURER>
<MANUFACTURER name="FORD">
    <CAR>
        <CAR_VIN>12345678901234567</CAR_VIN>
        <CAR_ENG>2.5</CAR_ENG>
        <CAR_MODEL>CMAX</CAR_MODEL>
        <CAR_REG_DATE>20050331</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>HH54 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
</MANUFACTURER>
<MANUFACTURER name="TOYOTA">
    <CAR>
        <CAR_VIN>XXX12345678901234567</CAR_VIN>
        <CAR_ENG>1.9</CAR_ENG>
        <CAR_MODEL>Corolla</CAR_MODEL>
        <CAR_REG_DATE>20030812</CAR_REG_DATE>
        <TRANSMISSION>A</TRANSMISSION>
        <CAR_REG>SS00 RRY</CAR_REG>
        <COLOUR>RED</COLOUR>
    </CAR>
</MANUFACTURER>

My first attempt xsl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0" xmlns:externalSupplier="externalSupplier://uk.co.skyline.XslConnector"
xmlns:consol="consol://uk.co.skyline.Xslconsolidated"
exclude-result-prefixes="externalSupplier consol">

<xsl:output method="xml" />



<!-- *** Parameters *** -->
<!-- ****************** -->
<xsl:param name="dealerNo"></xsl:param>  <!-- ** dealer Reg No being processed -->
<xsl:param name="supplier"></xsl:param> 
<xsl:param name="cust"></xsl:param>          


<!-- Load xml from external into variables -->
<!-- ************************************* -->
<!--
    <xsl:variable name="externalStuff" select="externalSupplier:getData(
    $dealerNo,  $supplier, $cust)"></xsl:variable>
-->

<xsl:variable name="externalStuff" 
select="document('Data2.xml')/*"></xsl:variable>



<xsl:template match="/">


    <xsl:for-each select="DEALERSHIP">

        <xsl:variable name="RegNum" select="@reg_number" />

        <xsl:element name="{name()}">
            <xsl:apply-templates select="." mode="copyAttributes" />

            <xsl:for-each select="MANUFACTURER">
                <xsl:variable name="manName" select="@name" />
                <xsl:apply-templates select=".">

                    <xsl:with-param name="externalMan"
                        select="$externalStuff[@reg_number = 
                        $RegNum]/MANUFACTURER[@name = $manName]" />
                </xsl:apply-templates>
            </xsl:for-each>
        </xsl:element>

    </xsl:for-each>

</xsl:template>

<!-- Process the MANUFACTURER elements -->
<!-- **************************** -->
<xsl:template match="MANUFACTURER">
    <xsl:param name="externalMan" />

    <!-- Get the reg number of the dealer -->
    <xsl:variable name="regNum" select="../@reg_number" />

    <!-- Get the manufacturer name -->
    <xsl:variable name="eManName" select="@name" />

    <xsl:element name="{name()}">
        <xsl:apply-templates select="." mode="copyAttributes" />

        <xsl:variable name="cars" select="CAR" />


        <xsl:apply-templates
            select="CAR | $externalMan/CAR[not (CAR_REG_DATE = 
            $cars/CAR_REG_DATE and CAR_MODEL = $cars/CAR_MODEL ) ]">

            <xsl:sort select="CAR_REG_DATE" data-type="number" 
            order="descending" />
            <xsl:sort select="CAR_MODEL" data-type="number" 
            order="descending" />
        </xsl:apply-templates>

    </xsl:element>

</xsl:template>


<!-- Process the CAR elements -->
<!-- **************************** -->
<xsl:template match="CAR">
    <xsl:param name="externalMan" />

    <xsl:choose>


        <xsl:when test="CAR_VIN">
            <xsl:copy-of select="." />
        </xsl:when>
        <xsl:otherwise>


            <xsl:if
                test="string-length(CAR_REG_DATE) = 8">

                <CAR>
                    <xsl:copy-of select="*" />
                    <CAR_VIN>
                        <xsl:value-of
                            select="consol:getConSol(../../@reg_number, 
                            CAR_REG_DATE, CAR_MODEL)" />
                    </CAR_VIN>
                </CAR>

            </xsl:if>

        </xsl:otherwise>
    </xsl:choose>
</xsl:template>




<!-- Copy the element's attributes to the output -->
<!-- ******************************************* -->
<xsl:template match="DEALERSHIP | MANUFACTURER" mode="copyAttributes">

    <xsl:for-each select="attribute::*">
        <xsl:attribute name="{name()}"><xsl:value-of select="." />
        </xsl:attribute>
    </xsl:for-each>
</xsl:template>

This transformation happens server side initiated through java.

Как вы можете видеть из таблицы стилей, я должен включить Data2.xml через вызов некоторой обработки Java. Я использовал document() для целей отладки.

Мне удалось заставить работать вызовы из/в входы java и основную структуру вывода xslt. Если CAR_VIN отсутствует в каких-либо данных, вызов java происходит при преобразовании каждого элемента CAR. Данные включают в себя все CAR_VIN, чтобы избежать обращений к этому java.

Это логика xsl и код, конкретно относящиеся к слиянию, в котором я новичок, и мне нужна помощь.

Логика слияния заключается в объединении источников данных ПРОИЗВОДИТЕЛИ и дочерних элементов. Если оба источника имеют идентичные элементы CAR, чьи дочерние элементы, содержимое CAR_REG_DATE и CAR_MODEL одинаковы, тогда включаются только данные из Data1.xml или Data2.xml, в зависимости от того, что имеет наибольшее количество этой уникальной комбинации. Если комбинация имеет одинаковый объем данных в обоих источниках данных, используйте источник преобразования xml, в приведенном выше случае Data1.xml. Полученные элементы должны быть упорядочены по CAR_REG_DATE по убыванию в каждом отдельном элементе MANUFATURER. Таким образом, в приведенном выше примере данных вы можете видеть, что необходимые выходные данные включают всех ПРОИЗВОДИТЕЛЕЙ; Воксхолл, Форд, Тойота. В случае Vauxhall Astra 20060331 выходные данные содержат данные из Data2.xml ASTRA 20060331, за исключением той же комбинации данных из Data1.xml. каждый MANUFACTURER, заказанный CAR_REG_DATE, нисходящие данные Ford Manaufacturer включены в выходные данные из Data1, заказанного CAR_REG_DATE desc. Данные производителя Toyota включены в выходные данные Data2, заказанные CAR_REG_DATE desc.

Первоначально мне пришла в голову идея слияния с использованием оператора объединения, где значение содержимого Data2.xml CAR_REG_DATE и CAR_MODEL не совпадает с Data1.xml CAR_REG_DATE, но это исключило бы любые данные из Data2.xml, когда не было совпадающих данных CAR_REG_DATE и CAR_MODEL. комбинация в Data1.xml. Кроме того (когда я думал об этом), он всегда будет исключать данные из Data2.xsml, когда одна и та же комбинация CAR_REG_DATE и CAR_MODEL была в DATA1.xml, независимо от количества в любом источнике данных, что определенно не то, что я хочу.

Результат применения таблицы стилей.xsl

<?xml version="1.0" encoding="UTF-8"?>

123456789012345678901234567 1,9 ASTRA 20060331 A HH54 RRY RED 12345678901234567 ASTRA 20040331 A HH54 Rry Red 12345678901234567 2,5 Calibra 20030331 A HH54 Rry Blue 12345678901234567 2,5 Cmax 20050331 A HH54 Rry Rry Rry

Затем мне пришла в голову идея объединить исходный документ и внешний документ вместе в локальную переменную и передать этот объединенный ПРОИЗВОДИТЕЛЬ в шаблон и пройтись по каждому элементу CAR. Я могу различать элементы CAR Data1.xml и Data2.xml по содержимому CAR_VIN, начиная с XXX. Поэтому я подумал, что буду перебирать каждый объединенный элемент CAR и выбирать количество для исходного документа и внешнего документа и включать внешний или исключать источник на основе результат.

Возможно ли это и как мне это сделать, или есть ли правильный способ сделать это, учитывая, что я полный новичок в обработке xslt?

Любая помощь с этой проблемой будет очень признательна.

Привет, спасибо за ответ

Я отредактировал набор данных, чтобы избежать rsi.

В двух словах мне нужно реализовать следующую логику -

Независимо от того, какой источник Data1.xml или Data2.xml имеет большее количество уникальных комбинаций CAR_REG_DATE и CAR_MODEL (внутри CAR), включите данные этого источника в выходные данные — исключите данные других источников с такой же комбинацией.

Все уникальные комбинации CAR_REG_DATE - CAR_MODEL должны быть включены из обоих источников. Упорядочено CAR_REG_DATE по убыванию в каждом MANUFACTURER после объединения

Итак, взяв Vauxhall MANUFACTURER

уникальная комбинация Astra- 20060331 - Data1.xml имеет 1, а Data2.xml имеет 2.

Мне нужно вывести Astras 20060331 из набора Data2.xml для этой комбинации и игнорировать Data1.xml Astras 20060331 1, как показано в файле requiredoutput.xml выше.

Дими, я ценю твой комментарий. Я думаю, что это моя проблема; Я пытаюсь взглянуть на проблему и разбить ее на более мелкие части, но здесь у меня ничего не получается. Я все еще в шоке от того, что обнаружил, что xsl:variable неизменяема. (или так кажется).


person stevd    schedule 27.01.2011    source источник
comment
Было бы лучше, если бы вы могли разделить эту сложную задачу на более мелкие задачи и задать отдельные вопросы по каждой такой задаче. Я не очень хорошо понимаю требования и правила слияния. Не могли бы вы привести очень простой пример и объяснить правила?   -  person Dimitre Novatchev    schedule 27.01.2011
comment
Да, это возможно. Но для того, чтобы помочь вам, нам нужна уменьшенная выборка ввода и желаемый вывод: мне потребовалось некоторое время даже для прокрутки вниз...   -  person    schedule 27.01.2011
comment
Привет, будучи новичком в stackoverflow, я добавил свои ответы к вашим комментариям в разделе вопросов. Это правильное место?   -  person stevd    schedule 27.01.2011
comment
да. Только в следующий раз добавьте метку, как мы с Дмитрием, в комментарии, чтобы люди, которым вы отвечаете, получали уведомления. Я вернусь с ответом.   -  person    schedule 28.01.2011


Ответы (1)


Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kCarByMan-Mod-Date"
             match="CAR"
             use="concat(../@name,'+',CAR_MODEL,'+',CAR_REG_DATE)"/>
    <xsl:variable name="vSource2" select="document('Data2.xml')"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node()|@*" mode="copy">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="DEALERSHIP">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pSource2" select="$vSource2"/>
            </xsl:apply-templates>
            <xsl:apply-templates
                 select="$vSource2/*/MANUFACTURER[
                                        not(@name = current()/*/@name)
                                     ]">
                <xsl:with-param name="pSource2" select="/"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="MANUFACTURER">
        <xsl:param name="pSource2"/>
        <xsl:copy>
            <xsl:apply-templates select="node()|@*">
                <xsl:with-param name="pSource2" select="$pSource2"/>
            </xsl:apply-templates>
            <xsl:apply-templates
                 select="$pSource2/*/MANUFACTURER[
                                        @name = current()/@name
                                     ]/node()">
                <xsl:with-param name="pSource2" select="/"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="CAR"/>
    <xsl:template
         match="CAR[count(.|key('kCarByMan-Mod-Date',
                                concat(../@name,'+',CAR_MODEL,'+',CAR_REG_DATE)
                            )[1]
                    ) = 1]">
        <xsl:param name="pSource2"/>
        <xsl:variable
             name="vKey"
             select="concat(../@name,'+',CAR_MODEL,'+',CAR_REG_DATE)"/>
        <xsl:variable name="vGroup" select="key('kCarByMan-Mod-Date',$vKey)"/>
        <xsl:for-each select="$pSource2">
            <xsl:variable name="vGroup2"
                          select="key('kCarByMan-Mod-Date',$vKey)"/>
            <xsl:apply-templates
                 select="$vGroup[not(count($vGroup2) > count($vGroup))]"
                 mode="copy"/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Вывод:

<DEALERSHIP reg_number="01234567">
    <MANUFACTURER name="VAUXHALL">
        <CAR>
            <CAR_VIN>12345678901234567</CAR_VIN>
            <CAR_ENG>1.9</CAR_ENG>
            <CAR_MODEL>ASTRA</CAR_MODEL>
            <CAR_REG_DATE>20040331</CAR_REG_DATE>
            <TRANSMISSION>A</TRANSMISSION>
            <CAR_REG>HH54 RRY</CAR_REG>
            <COLOUR>RED</COLOUR>
        </CAR>
        <CAR>
            <CAR_VIN>12345678901234567</CAR_VIN>
            <CAR_ENG>2.5</CAR_ENG>
            <CAR_MODEL>CALIBRA</CAR_MODEL>
            <CAR_REG_DATE>20030331</CAR_REG_DATE>
            <TRANSMISSION>A</TRANSMISSION>
            <CAR_REG>HH54 RRY</CAR_REG>
            <COLOUR>BLUE</COLOUR>
        </CAR>
        <CAR>
            <CAR_VIN>XXX12345678901234567</CAR_VIN>
            <CAR_ENG>1.9</CAR_ENG>
            <CAR_MODEL>ASTRA</CAR_MODEL>
            <CAR_REG_DATE>20060331</CAR_REG_DATE>
            <TRANSMISSION>A</TRANSMISSION>
            <CAR_REG>SS00 RRY</CAR_REG>
            <COLOUR>BLUE</COLOUR>
        </CAR>
        <CAR>
            <CAR_VIN>XXX12345678901234567</CAR_VIN>
            <CAR_ENG>1.9</CAR_ENG>
            <CAR_MODEL>ASTRA</CAR_MODEL>
            <CAR_REG_DATE>20060331</CAR_REG_DATE>
            <TRANSMISSION>A</TRANSMISSION>
            <CAR_REG>SS00 RRY</CAR_REG>
            <COLOUR>BLUE</COLOUR>
        </CAR>
    </MANUFACTURER>
    <MANUFACTURER name="FORD">
        <CAR>
            <CAR_VIN>12345678901234567</CAR_VIN>
            <CAR_ENG>2.5</CAR_ENG>
            <CAR_MODEL>CMAX</CAR_MODEL>
            <CAR_REG_DATE>20050331</CAR_REG_DATE>
            <TRANSMISSION>A</TRANSMISSION>
            <CAR_REG>HH54 RRY</CAR_REG>
            <COLOUR>RED</COLOUR>
        </CAR>
    </MANUFACTURER>
    <MANUFACTURER name="TOYOTA">
        <CAR>
            <CAR_VIN>XXX12345678901234567</CAR_VIN>
            <CAR_ENG>1.9</CAR_ENG>
            <CAR_MODEL>Corolla</CAR_MODEL>
            <CAR_REG_DATE>20030812</CAR_REG_DATE>
            <TRANSMISSION>A</TRANSMISSION>
            <CAR_REG>SS00 RRY</CAR_REG>
            <COLOUR>RED</COLOUR>
        </CAR>
    </MANUFACTURER>
</DEALERSHIP>

Примечание. Группировка по производителю, модели и дате. Пересечение Data1.xml. Правило DEALERSHIP (соответствует только узлу из Data1.xml): скопировать себя, применить шаблоны к дочернему элементу с Data2.xml в качестве второго источника, применить шаблоны к производителям из Data2.xml, которых нет в Data1.xml. Правило MANUFACTURER (совпадение узлов как из Data1.xml, так и из Data2.xml): скопировать себя, применить шаблоны к дочерним элементам с параметром pSource2 в качестве второго источника, применить шаблоны к CAR, принадлежащим тому же производителю во втором источнике (это будет пустым для производителей из Data2.xml, отсутствующих в Data1.xml). Пустое CAR правило по умолчанию. Правило "Первый в своем роде" CAR: копировать текущую группу, если в той же группе больше нет элементов из второго источника (это означает, что при одинаковом количестве копируются оба. Уточните поведение, если это нежелательно.)

person Community    schedule 28.01.2011