这是向"Select all of an element between the current element and the next of the current element"提问的后续问题。即使我不确定创建一个新问题是否是正确的方法我仍然这样做。因为原来的问题得到了回答,但事后发生了变化。所以在我看来,改变的问题是开放的。此外,我认为改变的问题应该放回到统计数据中,如果它符合答案。
问题是如何创建一个层次结构的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的原始解决方案找到解决方案。所以我找到了一个并且喜欢把它作为答案作为一种可能性。我希望有一个更易于理解的解决方案。
答案 0 :(得分: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>
答案 1 :(得分: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 < $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>