0

这是对“选择当前元素和当前元素的下一个元素之间的所有元素”提出的后续问题。即使我不确定创建一个新问题是否是我这样做的正确方式。因为最初的问题得到了回答,但后来又改变了。所以在我看来,改变的问题是开放的。此外,我认为如果更改后的问题适合答案,则应将其放回统计数据中。

问题是如何创建分层 xml 形式的“平面”xml,如书籍描述。

输入 xml 类似于

<root>
    <heading_1>Section 1</heading_1>
    <para>...</para>
    <list_1>...</list_1>
    <heading_2>Section 1.1</heading_2>
    <para>...</para>
    <heading_3>Section 1.1.1</heading_3>
    <para>...</para>
    <list_1>...</list_1>
    <heading_2>Section 1.2</heading_2>
    <para>...</para>
    <footnote>...</footnote>
    <heading_1>Section 2</heading_1>
    <para>...</para>
    <list_1>...</list_1>
    <heading_2>Section 2.1</heading_2>
    <para>...</para>
    <list_1>...</list_1>
    <list_2>...</list_2>
    <heading_3>Seciton 2.1.1</heading_3>
    <para>...</para>
    <heading_2>Section 2.2</heading_2>
    <para>...</para>
    <footnote>...</footnote>
</root>

每个都<heading_*>应该被解释为<section> 预期输出 xml 的开头。

<section>
    <title>Section 1</title>
    <para>...</para>
    <list_1>...</list_1>
    <section>
        <title>Section 1.1</title>
        <para>...</para>
        <section>
            <title>Section 1.1.1</title>
            <para>...</para>
            <list_1>...</list_1>
        </section>
    </section>
    <section>
        <title>Section 1.2</title>
        <para>...</para>
        <footnote>...</footnote>
    </section>
</section>
<section>
    <title>Section 2</title>
    <para>...</para>
    <list_1>...</list_1>
    <section>
        <title>Section 2.1</title>
        <para>...</para>
        <list_1>...</list_1>
        <list_2>...</list_2>
        <section>
            <title>Section 2.1.1</title>
            <para>...</para>
        </section>
    </section>
    <section>
        <title>Section 2.2</title>
        <para>...</para>
        <footnote>...</footnote>
    </section>
</section>

我还尝试了一段时间根据@JLRishe的原始解决方案找到解决方案 。所以我找到了一个,并喜欢把它放在这里作为一种可能性的答案。我希望有一个更易于理解的解决方案。

4

2 回答 2

3

这是适用于任何航向深度的通用解决方案:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="kChildHeader" 
           match="/*/*[starts-with(local-name(), 'heading_')]"
           use="generate-id(preceding-sibling::*
                       [local-name() = 
                        concat('heading_', 
                               substring-after(local-name(current()), '_') - 1
                              )][1]
                            )"/>
  <xsl:key name="kChildItem" 
           match="/*/*[not(starts-with(local-name(), 'heading_'))]"
           use="generate-id(preceding-sibling::*
                             [starts-with(local-name(), 'heading_')][1])"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="heading_1" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[starts-with(local-name(), 'heading_')]">
    <xsl:copy>
      <xsl:apply-templates select="key('kChildHeader', generate-id()) |
                                   key('kChildItem', generate-id())"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

在您的示例输入上运行时,这会产生:

<root>
  <heading_1>
    <para>...</para>
    <list_1>...</list_1>
    <heading_2>
      <para>...</para>
      <heading_3>
        <para>...</para>
        <list_1>...</list_1>
      </heading_3>
    </heading_2>
    <heading_2>
      <para>...</para>
      <footnote>...</footnote>
    </heading_2>
  </heading_1>
  <heading_1>
    <para>...</para>
    <list_1>...</list_1>
    <heading_2>
      <para>...</para>
      <list_1>...</list_1>
      <list_2>...</list_2>
      <heading_3>
        <para>...</para>
      </heading_3>
    </heading_2>
    <heading_2>
      <para>...</para>
      <footnote>...</footnote>
    </heading_2>
  </heading_1>
</root>
于 2013-04-24T10:48:25.583 回答
1

这是我目前的解决方案

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    extension-element-prefixes="exsl">

    <xsl:output method="xml" indent="yes"/>

    <xsl:variable name="headerLevel_txt">
        <heading name="__none__" level="0"/>
        <heading name="heading_1" level="1"/>
        <heading name="heading_2" level="2"/>
        <heading name="heading_3" level="3"/>
    </xsl:variable>

    <xsl:variable name="headerLevel" select="exsl:node-set($headerLevel_txt)" />


    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()" >
                <xsl:with-param name="ch" select="h1" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates select="heading_1" />
        </xsl:copy>
    </xsl:template>


    <xsl:template match="heading_1 | heading_2 | heading_3" >
        <xsl:param name="previousheaader" select="'__none__'" />

        <xsl:variable name="endOfLevel" >
            <xsl:call-template name="endOfLevel">
                <xsl:with-param name="currentheaader" select="name()" />
                <xsl:with-param name="previousheaader" select="$previousheaader" />
            </xsl:call-template>
        </xsl:variable>

        <xsl:if test ="$endOfLevel != 'end'" >
            <section>
                <title>
                    <xsl:value-of select="normalize-space(.)"/>
                </title>

                <!-- following siblings including next heading  -->
                <xsl:variable name="fsinh" select="following-sibling::*[ 
                              generate-id( preceding-sibling::*
                                           [
                                             name() = 'heading_1' or name() = 'heading_2' or  name() = 'heading_3'
                                           ][1]
                                          ) = generate-id(current()) ]" />

                    <xsl:apply-templates select="$fsinh[ position()!=last()]" >
                        <xsl:with-param name="previousheaader" select="name()" />
                    </xsl:apply-templates>

                <!-- following siblings heading same as next   -->
                <xsl:variable name="fshsan" select="following-sibling::*[  
                              name() = name($fsinh[last()]) and
                              generate-id( preceding-sibling::*
                                           [
                                             name() = name(current())
                                           ][1]
                                          ) = generate-id(current()) ]" />
                <xsl:apply-templates select="$fshsan" >
                    <xsl:with-param name="previousheaader" select="name()" />
                </xsl:apply-templates>

            </section>
        </xsl:if>

    </xsl:template>

    <xsl:template name="endOfLevel">
        <xsl:param name ="currentheaader"/>
        <xsl:param name ="previousheaader"/>
        <!-- The previous heading ends if the current has an higher level (smaller level number)-->
        <xsl:variable name ="cl" select="number($headerLevel/heading[@name=$currentheaader]/@level)"/>
        <xsl:variable name ="pl" select="number($headerLevel/heading[@name=$previousheaader]/@level)"/>
        <xsl:if test ="$cl &lt; $pl">end</xsl:if>
    </xsl:template>

</xsl:stylesheet>

它将生成以下输出:

<root>
  <section>
    <title>Section 1</title>
    <para>...</para>
    <list_1>...</list_1>
    <section>
      <title>Section 1.1</title>
      <para>...</para>
      <section>
        <title>Section 1.1.1</title>
        <para>...</para>
        <list_1>...</list_1>
      </section>
    </section>
    <section>
      <title>Section 1.2</title>
      <para>...</para>
      <footnote>...</footnote>
    </section>
  </section>
  <section>
    <title>Section 2</title>
    <para>...</para>
    <list_1>...</list_1>
    <section>
      <title>Section 2.1</title>
      <para>...</para>
      <list_1>...</list_1>
      <list_2>...</list_2>
      <section>
        <title>Seciton 2.1.1</title>
        <para>...</para>
      </section>
    </section>
    <section>
      <title>Section 2.2</title>
      <para>...</para>
      <footnote>...</footnote>
    </section>
  </section>
</root>
于 2013-04-24T09:34:01.763 回答