我尝试嵌套此示例XML文件。我试图使用简单的模板,它会传递当前节点。
<?xml version="1.0" encoding="UTF-8"?>
<chapter>
<h1>h1</h1>
<p>text1</p>
<p>text2</p>
<p>text3</p>
<h2>h2</h2>
<p>text1</p>
<p>text2</p>
<p>text3</p>
<p>text4</p>
<p>text5</p>
<p>text6</p>
<h1>h1</h1>
<p>text1</p>
<p>text2</p>
<p>text3</p>
<h2>h2</h2>
<h3>h3</h3>
<p>text1</p>
<p>text2</p>
<p>text3</p>
<h2>h2</h2>
<p>text1</p>
<p>text2</p>
<p>text3</p>
</chapter>
使用以下样式表:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:template match="/">
<chapter>
<xsl:apply-templates/>
</chapter>
</xsl:template>
<xsl:template match="h1">
<level_1>
<head>
<xsl:value-of select="."/>
</head>
<xsl:apply-templates select="following::*"/>
</level_1>
</xsl:template>
<xsl:template match="h2">
<head>
<xsl:value-of select="."/>
</head>
<level_2>
<head>
<xsl:value-of select="."/>
</head>
<xsl:apply-templates select="following::*"/>
</level_2>
</xsl:template>
<xsl:template match="h3">
<head>
<xsl:value-of select="."/>
</head>
<level_3>
<head>
<xsl:value-of select="."/>
</head>
<xsl:apply-templates select="following::*"/>
</level_3>
</xsl:template>
<xsl:template match="p">
<text>
<xsl:value-of select="."></xsl:value-of>
</text>
</xsl:template>
</xsl:stylesheet>
但结果根本不起作用。 following::*
不起作用,因为h1
也跟随h2
,那么模板如何知道,何时关闭?
输出应为:
<chapter>
<level_1>
<head>h1</head>
<text>text1</text>
<text>text2</text>
<text>text3</text>
<level_2>
<head>h2</head>
<text>text1</text>
<text>text2</text>
<text>text3</text>
<text>text4</text>
<text>text5</text>
<text>text6</text>
</level_2>
...
</level_1>
</chapter>
非常感谢!
答案 0 :(得分:1)
好的,这里有。
定义实用程序函数以测试元素是否为hN:
<xsl:function name="f:isLevel" as="xs:boolean">
<xsl:param name="h" as="element(*)"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:sequence select="name($h) = concat('h', $level)"/>
</xsl:function>
定义一个递归函数,对N级执行分组:
<xsl:function name="f:group" as="element(*)*">
<xsl:param name="input" as="element(*)*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group
group-starting-with="*[f:isLevel(., $level)]">
<xsl:choose>
<xsl:when test="f:isLevel(., $level)">
<xsl:element name="level_{$level}">
<head><xsl:copy-of select="."/></head>
<xsl:sequence select="
f:group(remove(current-group(), 1), $level+1)"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
这是如何工作的?给定类似(p,p,h1,p,p,h1,p)的输入,它创建三组:(p,p,p),(h1,p,p)和(h1,p)。以h1开头的组采用xsl:when分支:它创建一个包含第一个元素(h1)内容的levelN元素,然后递归地将分组应用于h1元素后面的其余组。
初始组(没有前导h1)接受xsl:otherwise分支,只是复制到输出。
当没有名为h {N}的元素时,递归终止:在这种情况下,for-each-group指令只创建一个组,该组在xsl:otherwise分支中处理,不会导致进一步的递归。
要运行此功能,您需要类似
的功能<xsl:template match="body">
<xsl:copy-of select="f:group(*, 1)"/>
</xsl:template>
答案 1 :(得分:1)
这是你可以看到它的一种方式:
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:key name="h2" match="h2" use="generate-id(preceding-sibling::h1[1])" />
<xsl:key name="h3" match="h3" use="generate-id(preceding-sibling::h2[1])" />
<xsl:key name="p" match="p" use="generate-id(preceding-sibling::*[starts-with(name(), 'h')][1])" />
<xsl:template match="/chapter">
<xsl:copy>
<xsl:apply-templates select="h1"/>
</xsl:copy>
</xsl:template>
<xsl:template match="h1">
<level_1>
<head>
<xsl:value-of select="."/>
</head>
<xsl:apply-templates select="key('h2', generate-id()) | key('p', generate-id())"/>
</level_1>
</xsl:template>
<xsl:template match="h2">
<level_2>
<head>
<xsl:value-of select="."/>
</head>
<xsl:apply-templates select="key('h3', generate-id()) | key('p', generate-id())"/>
</level_2>
</xsl:template>
<xsl:template match="h3">
<level_3>
<head>
<xsl:value-of select="."/>
</head>
<xsl:apply-templates select="key('p', generate-id())"/>
</level_3>
</xsl:template>
<xsl:template match="p">
<text>
<xsl:value-of select="."/>
</text>
</xsl:template>
</xsl:stylesheet>