XSL преобразование

Рейтинг: 0Ответов: 1Опубликовано: 03.07.2023

Имеется входной xml документ след.вида

<root xmlns="mnemoschema">
    <name>test110</name>
    <name1>test111</name1>
    <name2>test112</name2>
    <name>test210</name>
    <name1>test211</name1>
    <name2>test212</name2>
    <name>test310</name>
    <name1>test311</name1>
    <name2>test312</name2>
    <test>name1</test>
    <test1>name11</test1>
    <test2>name12</test2>
    <test>name2</test>
    <test1>name21</test1>
    <test2>name22</test2>
    <test>name3</test>
    <test1>name31</test1>
    <test2>name32</test2>
</root>

из него хочу получить посредством xslt преобразование след.документ

<root xmlns="mnemoschema">
    <x1>
        <name>test110</name>
        <name1>test111</name1>
        <name2>test112</name2>
    </x1>
    <x1>
        <name>test210</name>
        <name1>test211</name1>
        <name2>test212</name2>
    </x1>
    <x1>
        <name>test310</name>
        <name1>test311</name1>
        <name2>test312</name2>
    </x1>
</root>

Написал вот такой xsl шаблон

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:str="http://exslt.org/strings">
    <xsl:output method="xml" indent="yes"/>
    <xsl:param name="rule"/>
    <xsl:param name="testRule"/>

    <xsl:template match="/">
        <root>
            <xsl:for-each select="str:tokenize($rule, ',')">

                <xsl:variable name="fileName" select="normalize-space(.)"/>

                <xsl:apply-templates select="document($fileName)//*[starts-with(name(), 'name')]"/>

            </xsl:for-each>

            <xsl:for-each select="str:tokenize($testRule, ',')">

                <xsl:variable name="fileName" select="normalize-space(.)"/>

                <xsl:apply-templates select="document($fileName)//*[starts-with(name(), 'name')]"/>

            </xsl:for-each>
        </root>
    </xsl:template>

    <xsl:template match="*">
        <x1>
            <xsl:copy-of select="."/>
            <xsl:copy-of select="following-sibling::name1[1]"/>
            <xsl:copy-of select="following-sibling::name2[1]"/>
        </x1>
    </xsl:template>

</xsl:stylesheet>

Параметры в шаблоне это список uri на документы, их много может быть. Вот <xsl:template match="*"> отрабатывает некорректно. Не пойму что не так написал...На выходе получаю вот это

<?xml version="1.0" encoding="UTF-8"?><root xmlns:str="http://exslt.org/strings">
    <x1>
        <name xmlns="mnemoschema">test110</name>
    </x1>
    <x1>
        <name1 xmlns="mnemoschema">test111</name1>
    </x1>
    <x1>
        <name2 xmlns="mnemoschema">test112</name2>
    </x1>
    <x1>
        <name xmlns="mnemoschema">test210</name>
    </x1>
    <x1>
        <name1 xmlns="mnemoschema">test211</name1>
    </x1>
    <x1>
        <name2 xmlns="mnemoschema">test212</name2>
    </x1>
    <x1>
        <name xmlns="mnemoschema">test310</name>
    </x1>
    <x1>
        <name1 xmlns="mnemoschema">test311</name1>
    </x1>
    <x1>
        <name2 xmlns="mnemoschema">test312</name2>
    </x1>
</root>

Т.е. у меня каждая запись оборачивается в тег x1, а мне нужно чтобы было по группам. Подскажите что не так?

Ответы

▲ 1

Гораздо лучше использовать modulus оператор чтобы получить группы из трех последовательных XML элементов.

Входной XML

<?xml version="1.0"?>
<root xmlns="mnemoschema">
    <name>test110</name>
    <name1>test111</name1>
    <name2>test112</name2>
    <name>test210</name>
    <name1>test211</name1>
    <name2>test212</name2>
    <name>test310</name>
    <name1>test311</name1>
    <name2>test312</name2>
    <test>name1</test>
    <test1>name11</test1>
    <test2>name12</test2>
    <test>name2</test>
    <test1>name21</test1>
    <test2>name22</test2>
    <test>name3</test>
    <test1>name31</test1>
    <test2>name32</test2>
</root>

XSLT 1.0

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="mnemoschema" xmlns:ns1="mnemoschema" exclude-result-prefixes="ns1">
    <xsl:output indent="yes" method="xml"/>

    <xsl:template match="/ns1:root">
        <xsl:copy>
            <xsl:for-each select="*[(position() mod 3) = 1 and starts-with(local-name(.), 'name')]">
                <x1>
                    <xsl:copy-of select="."/>
                    <xsl:copy-of select="./following-sibling::*[1]"/>
                    <xsl:copy-of select="./following-sibling::*[2]"/>
                </x1>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Выходной XML

<?xml version="1.0" encoding="utf-8"?>
<root xmlns="mnemoschema">
  <x1>
    <name>test110</name>
    <name1>test111</name1>
    <name2>test112</name2>
  </x1>
  <x1>
    <name>test210</name>
    <name1>test211</name1>
    <name2>test212</name2>
  </x1>
  <x1>
    <name>test310</name>
    <name1>test311</name1>
    <name2>test312</name2>
  </x1>
</root>