遍历兄弟姐妹直到特定元素类型
Iterate through siblings until a specific element type
我有一个扁平的 XML 结构,如下所示:
<root>
<header>First header</header>
<type1>Element 1:1</type1>
<type2>Element 1:2</type2>
<header>Second header</header>
<type1>Element 2:1</type1>
<type3>Element 3:1</type3>
<header>Third header</header>
<type1>Element 3:1</type1>
<type2>Element 3:2</type2>
<type1>Element 3:3</type1>
<type2>Element 3:4</type2>
</root>
本质上有一个未知数量的header。在每个 header 下都有未知数量的元素(树的不同类型)。每个 header 下可以有零到多个每种类型的元素。我无法控制这个结构,所以我不能 change/improve 它。
我要生成的是 HTML:
<h2>First header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 1:1</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 1:2</td>
</tr>
</table>
<h2>Second header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 2:1</td>
</tr>
<tr>
<th>Type 3</th>
<td>Element 2:2</td>
</tr>
</table>
<h2>third header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 3:1</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 3:2</td>
</tr>
<tr>
<th>Type 1</th>
<td>Element 3:3</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 3:4</td>
</tr>
</table>
每个 header 将是一个 HTML header(级别 2)然后我想要所有其他元素 直到下一个 header 显示在 table.
我的第一个想法是制作一个匹配 header 元素的模板:
<xsl:template match="header">
<h2><xsl:value-of select="text()" /></h2>
<table>
???
</table>
</xsl:template>
我想我可以替换“???”代码遍历所有 以下兄弟姐妹,直到下一个 header 元素 并将它们变成 table 行。
这是个好主意吗?
如果是,我该怎么做?
如果不是,什么是更好的解决方案?
我正在使用 XSLT 1.0。
实现此目的的一种方法是使用键将 non-header 元素按其前面的第一个 header
元素分组
<xsl:key name="type" match="*[not(self::header)]" use="generate-id(preceding-sibling::header[1])" />
然后您只需选择 header
个元素
<xsl:apply-templates select="header" />
然后在匹配此 header
元素的模板中,您可以使用键
获取与 header 对应的所有 type
元素
<xsl:for-each select="key('type', generate-id())">
试试这个 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:key name="type" match="*[not(self::header)]" use="generate-id(preceding-sibling::header[1])" />
<xsl:template match="root">
<xsl:apply-templates select="header" />
</xsl:template>
<xsl:template match="header">
<h2><xsl:value-of select="." /></h2>
<table>
<xsl:for-each select="key('type', generate-id())">
<tr>
<th><xsl:value-of select="local-name()" /></th>
<th><xsl:value-of select="." /></th>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
注意,这不包括将节点名称 type1
转换为 Type 1
的问题,但我会把这个练习留给你....
我有一个扁平的 XML 结构,如下所示:
<root>
<header>First header</header>
<type1>Element 1:1</type1>
<type2>Element 1:2</type2>
<header>Second header</header>
<type1>Element 2:1</type1>
<type3>Element 3:1</type3>
<header>Third header</header>
<type1>Element 3:1</type1>
<type2>Element 3:2</type2>
<type1>Element 3:3</type1>
<type2>Element 3:4</type2>
</root>
本质上有一个未知数量的header。在每个 header 下都有未知数量的元素(树的不同类型)。每个 header 下可以有零到多个每种类型的元素。我无法控制这个结构,所以我不能 change/improve 它。
我要生成的是 HTML:
<h2>First header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 1:1</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 1:2</td>
</tr>
</table>
<h2>Second header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 2:1</td>
</tr>
<tr>
<th>Type 3</th>
<td>Element 2:2</td>
</tr>
</table>
<h2>third header</h2>
<table>
<tr>
<th>Type 1</th>
<td>Element 3:1</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 3:2</td>
</tr>
<tr>
<th>Type 1</th>
<td>Element 3:3</td>
</tr>
<tr>
<th>Type 2</th>
<td>Element 3:4</td>
</tr>
</table>
每个 header 将是一个 HTML header(级别 2)然后我想要所有其他元素 直到下一个 header 显示在 table.
我的第一个想法是制作一个匹配 header 元素的模板:
<xsl:template match="header">
<h2><xsl:value-of select="text()" /></h2>
<table>
???
</table>
</xsl:template>
我想我可以替换“???”代码遍历所有 以下兄弟姐妹,直到下一个 header 元素 并将它们变成 table 行。
这是个好主意吗?
如果是,我该怎么做? 如果不是,什么是更好的解决方案?
我正在使用 XSLT 1.0。
实现此目的的一种方法是使用键将 non-header 元素按其前面的第一个 header
元素分组
<xsl:key name="type" match="*[not(self::header)]" use="generate-id(preceding-sibling::header[1])" />
然后您只需选择 header
个元素
<xsl:apply-templates select="header" />
然后在匹配此 header
元素的模板中,您可以使用键
type
元素
<xsl:for-each select="key('type', generate-id())">
试试这个 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:key name="type" match="*[not(self::header)]" use="generate-id(preceding-sibling::header[1])" />
<xsl:template match="root">
<xsl:apply-templates select="header" />
</xsl:template>
<xsl:template match="header">
<h2><xsl:value-of select="." /></h2>
<table>
<xsl:for-each select="key('type', generate-id())">
<tr>
<th><xsl:value-of select="local-name()" /></th>
<th><xsl:value-of select="." /></th>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
注意,这不包括将节点名称 type1
转换为 Type 1
的问题,但我会把这个练习留给你....