Мога ли да събирам елементи в ‹xsl:variable›, докато рекурсивно анализирам XML файлове, за да ги трансформирам по-късно

Имам няколко xml файла със структура като тази:

1.xml

  <root>
<includeFile name="2.xml" />
<a>
    <items>
        <item id="1" />
        <item id="2" />
    </items>
    <items>
        <item id="3" />
        <item id="4" />
        <item id="5" />
    </items>
</a>
<b>
    <items>
        <item id="6" />
        <item id="7" />
    </items>
    <items>
        <item id="8" />
    </items>
</b>
<c>
    <items>
        <item id="9" />
        <item id="10" />
    </items>
</c>

Всички тагове a, b и c не са задължителни. Трябва да анализирам файл за елементи и след това рекурсивно да анализирам файла, посочен в етикета за включване. Опитвам се да събера всички тези елементи в един файл под съответните им родители (a, b и c) с помощта на XSLT. Мога да получа всички елементи от всички файлове, но проблемът ми е, че не мога да ги комбинирам под единични родителски тагове. Опитах да използвам, но те не изглеждат в състояние да решат проблема ми. Моят XSLT изглежда така (този е непълен)

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt">
    <xsl:output method="xml" indent="yes" xalan:indent-amount="4" />

    <xsl:template match="/">
        <xsl:call-template name="fileTemp" />
        <xsl:for-each select="root/includeFile">
        <xsl:value-of select="@name" />
            <xsl:apply-templates select="document(@name)" />
        </xsl:for-each>
    </xsl:template>
    <xsl:variable name="mi" />
    <xsl:template name="fileTemp">
                <xsl:variable name="mi" select="root/items" />
    </xsl:template>
</xsl:stylesheet>

Как мога да събера всички елементи в променлива или нещо в рамките на XSLT, докато анализирам различни XML и след това прилагам трансформациите си върху него?

Например: анализиране на 1.xml, което ще включва 2.xml като

    <root>
<a>
    <items>
        <item id="100" />
        <item id="200" />
    </items>
</a>
<b>
    <items>
        <item id="80" />
    </items>
</b>
<c>
    <items>
        <item id="90" />
    </items>
</c>

...трябва да произвежда

    <root>
<a>
    <items>
        <item id="1" />
        <item id="2" />
    </items>
    <items>
        <item id="3" />
        <item id="4" />
        <item id="5" />
    </items>
     <items>
        <item id="100" />
        <item id="200" />
    </items>
</a>
<b>
    <items>
        <item id="6" />
        <item id="7" />
    </items>
    <items>
        <item id="8" />
    </items>
    <items>
        <item id="80" />
    </items>
</b>
<c>
    <items>
        <item id="9" />
        <item id="" />
    </items>
    <items>
        <item id="90" />
    </items>
</c>
</root>

person ishan    schedule 26.02.2015    source източник
comment
Преди да задавате нови въпроси, моля, приемете или по друг начин отговорете на отговора на предишния ви въпрос.   -  person Mathias Müller    schedule 26.02.2015
comment
Помислете дали да ни покажете структурата на резултата, която искате за три или четири входни примерни макета.   -  person Martin Honnen    schedule 26.02.2015
comment
Вашият стилов лист твърди, че е XSLT 2.0, но след това използвате специфично за Xalan разширение в xsl:output, а Xalan прилага само XSLT 1.0. Кой процесор всъщност използвате тук?   -  person Ian Roberts    schedule 26.02.2015


Отговори (1)


Ето лист със стилове XSLT 2.0 (да се използва със Saxon 9 или XmlPrime или който и да е друг процесор XSLT 2.0), който използва рекурсивна функция за събиране на различните елементи от посочените документи:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="xs mf">

<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:function name="mf:collect" as="element()*">
  <xsl:param name="docs" as="document-node()*"/>

  <xsl:sequence select="$docs/*/a, $docs/*/b, $docs/*/c"/>

  <xsl:variable name="included-docs" as="document-node()*" select="document($docs/*/includeFile/@name)"/>
  <xsl:sequence select="if (exists($included-docs)) then mf:collect($included-docs) else ()"/>
</xsl:function>

<xsl:variable name="collected-items" select="mf:collect(/)"/>

<xsl:template match="/*">
  <xsl:copy>
     <a>
      <xsl:copy-of select="$collected-items[self::a]/items"/>
    </a>
    <b>
      <xsl:copy-of select="$collected-items[self::b]/items"/>
    </b>
    <c>
      <xsl:copy-of select="$collected-items[self::c]/items"/>
    </c>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

За да направите същото с XSLT 1.0, ще трябва да напишете рекурсивен шаблон, за да конструирате фрагмент от дърво с резултати и след това трябва да използвате exsl:node-set или подобен, за да можете да избирате и извеждате различните елементи от фрагмента от дърво с резултати

person Martin Honnen    schedule 27.02.2015