如何使用XSLT 1.0将平面XML结构转换为分层XML?

问题描述:

从示例性的,格式不正确的XML结构开始:

Starting from an exemplary, ungainly formatted XML structure:

<list>
    <topic>
        <title>
            Paragraph 1
        </title>
    </topic>
    <topic>
        <main>
            Content 1
        </main>
    </topic>
    <topic>
        <main>
            Content 2
        </main>
    </topic>
    <!-- ... -->
    <topic>
        <main>
            Content n
        </main>
    </topic>
    <topic>
        <title>
            Paragraph 2
        </title>
    </topic>
    <topic>
        <main>
            Content 1
        </main>
    </topic>
    <!-- ... -->
    <topic>
        <main>
            Content n
        </main>
    </topic>
</list>

"title"和"main"的内容仅是占位符. 每个节点中标题"的内容都不同. 主要"的内容可以改变也可以不改变. 主要"元素的数量是不确定的.

The contents of "title" and "main" are merely placeholders. The content of "title" is different in every node. The content of "main" may or may not vary. The number of "main" elements is indefinite.

目标是在主题/标题元素之后总结主题/主要元素,如下所示:

The goal is to summarize the topic / main elements following a topic / title element as follows:

<list>
    <paragraph name="1">
        <item>Content 1</item>
        <item>Content 2</item>
        <item>Content n</item>
    </paragraph>
    <paragraph name="2">
        <item>Content 1</item>
        <item>Content n</item>
    </paragraph>
</list>

边界条件是对xslt和xpath版本1的限制.

Boundary condition is the restriction to version 1 of xslt and xpath.

此问题以前曾以类似的形式提出过.我没有找到满意的答案.

This question has been asked in similar form before. I did not find a satisfactory answer.

基本上,您正在寻找group-starting-with的XSLT 1.0实现.可以按照以下步骤进行操作:

Basically, you're looking for an XSLT 1.0 implementation of group-starting-with. This can be done as following:

XSLT 1.0

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

<xsl:key name="topic-by-leader" match="topic[main]" use="generate-id(preceding-sibling::topic[title][1])" />

<xsl:template match="/list">
    <xsl:copy>
        <xsl:for-each select="topic[title]">
            <paragraph name="{position()}">
                <xsl:for-each select="key('topic-by-leader', generate-id())" >
                    <item>
                        <xsl:value-of select="normalize-space(main)" />
                    </item>
                </xsl:for-each>
            </paragraph>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>