XSLT:从不同的节点创建组合 table
XSLT: Create combined table from distinct nodes
我想创建一个组合 table,其中包含来自 xml 源中不同子节点的数据。
来源(大致)如下:请注意,我已经简化了示例。 "Modes" 节点在更大的 xml 文档中向下几层,"BLOCK" 节点包含的不仅仅是 "CODE" children。
数据是从三个不同的节点 Mode1、Mode2 和 Mode3 收集的。源文档中有更多 ModeX (X=1..10) 节点,但它们没有进入这个特定的 table.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="sample.xsl" type="text/xsl"?>
<root>
<!-- there are "a lot" more levels between root and Modes -->
<Modes>
<Mode1>
<KOMMENTAR>Header 1</KOMMENTAR>
<TEST>
<NUMBER>5</NUMBER>
<FLAG>0</FLAG>
</TEST>
<TEST>
<NUMBER>6</NUMBER>
<FLAG>0</FLAG>
</TEST>
<TEST>
<NUMBER>7</NUMBER>
<FLAG>1</FLAG>
<BLOCK>
<CODE>1.7.1 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>8</NUMBER>
<FLAG>1</FLAG>
<BLOCK>
<CODE>1.8.1 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>1.8.2 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>9</NUMBER>
<FLAG>0</FLAG>
<BLOCK>
<CODE>1.9.1 - Message</CODE>
</BLOCK>
</TEST>
</Mode1>
<Mode2>
<KOMMENTAR>Header 2</KOMMENTAR>
<TEST>
<NUMBER>5</NUMBER>
</TEST>
<TEST>
<NUMBER>6</NUMBER>
<BLOCK>
<CODE>2.6.1 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>2.6.2 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>2.6.2 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>7</NUMBER>
<BLOCK>
<CODE>2.7.1 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>8</NUMBER>
</TEST>
<TEST>
<NUMBER>9</NUMBER>
</TEST>
</Mode2>
<Mode3>
<KOMMENTAR>Header 3</KOMMENTAR>
<TEST>
<NUMBER>5</NUMBER>
</TEST>
<TEST>
<NUMBER>6</NUMBER>
</TEST>
<TEST>
<NUMBER>7</NUMBER>
<BLOCK>
<CODE>3.7.1 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>3.7.2 - Message that spans over several lines</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>8</NUMBER>
</TEST>
<TEST>
<NUMBER>9</NUMBER>
</TEST>
</Mode3>
<Mode9>
Contains some other data
</Mode9>
</Modes>
</root>
所需的输出是 table,如下所示(在 HTML 中):
| Header 1 | Header 2 | Header 3 |
Test | Flag | Nr. | Message | Nr. | Message | Nr. | Message |
5 | 0 | | | | | | |
6 | 0 | | | 1 | 2.6.1 - Message | | |
| | | | 2 | 2.6.2 - Message | | |
| | | | 3 | 2.6.3 - Message | | |
7 | 1 | 1 | 1.7.1 - Message | 1 | 2.7.1 - Message | 1 | 3.7.1 - Message |
| | | | | | 2 | 3.7.2 - Message |
| | | | | | | that spans over |
| | | | | | | several lines |
8 | 1 | 1 | 1.8.1 - Message | | | | |
| | 2 | 1.8.2 - Message | | | | |
9 | 0 | | | | | | |
到目前为止,我能想到的最好的办法是在 TEST 下创建一个 sub-table for-each BLOCK。但这看起来很难看,因为当然 "Nr." 和 "Message" headers 不与 sub-table 的内容列对齐。
我已经阅读了一些关于 Muenchian 分组的文章(http://www.jenitennison.com/xslt/grouping/muenchian.html 和关于 Whosebug 的其他问题)并尝试了示例,但我无法为我的数据获取正确的键。
如果有人能帮我解决键和外部 for-each 循环,我想我可以处理剩下的事情。
提前致谢。
If somebody could help me with the keys and the outer for-each loop, I
think I can handle the rest.
恕我直言,外循环很简单,真正的问题在后面。以下是执行外循环的方法:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes" encoding="UTF-8" version="1.0"/>
<xsl:key name="test" match="TEST" use="NUMBER" />
<xsl:template match="/">
<table border="1">
<thead>
<tr>
<th colspan="2"/>
<th colspan="2">Header 1</th>
<th colspan="2">Header 2</th>
<th colspan="2">Header 3</th>
</tr>
<tr>
<th>Test</th>
<th>Flag</th>
<th>Nr.</th>
<th>Message</th>
<th>Nr.</th>
<th>Message</th>
<th>Nr.</th>
<th>Message</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="(root/Modes/Mode1/TEST | root/Modes/Mode2/TEST | root/Modes/Mode3/TEST)[count(. | key('test', NUMBER)[1]) = 1]">
<tr>
<td><xsl:value-of select="NUMBER"/></td>
<td><xsl:value-of select="FLAG"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
此时你将拥有:
现在真正的问题来了:如果您希望有一列为每条消息编号并使该编号与相邻的消息对齐,则必须为每条不是第一条消息的消息创建一个单独的行它的专栏。您将需要计算每列中的消息数,并使用三者中的最大值作为前两个单元格的行跨度值。
或者,您可以采取简单的方法并执行以下操作:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes" encoding="UTF-8" version="1.0"/>
<xsl:key name="test" match="TEST" use="NUMBER" />
<xsl:template match="/">
<table border="1">
<thead>
<tr>
<th width="5%">Test</th>
<th width="5%">Flag</th>
<th width="30%">Header 1<br/>Message</th>
<th width="30%">Header 2<br/>Message</th>
<th width="30%">Header 3<br/>Message</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="(root/Modes/Mode1/TEST | root/Modes/Mode2/TEST | root/Modes/Mode3/TEST)[count(. | key('test', NUMBER)[1]) = 1]">
<tr>
<td><xsl:value-of select="NUMBER"/></td>
<td><xsl:value-of select="FLAG"/></td>
<td>
<ol>
<xsl:for-each select="key('test', NUMBER)[parent::Mode1]/BLOCK">
<li>
<xsl:value-of select="CODE"/>
</li>
</xsl:for-each>
</ol>
</td>
<td>
<ol>
<xsl:for-each select="key('test', NUMBER)[parent::Mode2]/BLOCK">
<li>
<xsl:value-of select="CODE"/>
</li>
</xsl:for-each>
</ol>
</td>
<td>
<ol>
<xsl:for-each select="key('test', NUMBER)[parent::Mode3]/BLOCK">
<li>
<xsl:value-of select="CODE"/>
</li>
</xsl:for-each>
</ol>
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
生产:
可以使用 CSS 进一步按摩塑形。
我想创建一个组合 table,其中包含来自 xml 源中不同子节点的数据。
来源(大致)如下:请注意,我已经简化了示例。 "Modes" 节点在更大的 xml 文档中向下几层,"BLOCK" 节点包含的不仅仅是 "CODE" children。 数据是从三个不同的节点 Mode1、Mode2 和 Mode3 收集的。源文档中有更多 ModeX (X=1..10) 节点,但它们没有进入这个特定的 table.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="sample.xsl" type="text/xsl"?>
<root>
<!-- there are "a lot" more levels between root and Modes -->
<Modes>
<Mode1>
<KOMMENTAR>Header 1</KOMMENTAR>
<TEST>
<NUMBER>5</NUMBER>
<FLAG>0</FLAG>
</TEST>
<TEST>
<NUMBER>6</NUMBER>
<FLAG>0</FLAG>
</TEST>
<TEST>
<NUMBER>7</NUMBER>
<FLAG>1</FLAG>
<BLOCK>
<CODE>1.7.1 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>8</NUMBER>
<FLAG>1</FLAG>
<BLOCK>
<CODE>1.8.1 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>1.8.2 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>9</NUMBER>
<FLAG>0</FLAG>
<BLOCK>
<CODE>1.9.1 - Message</CODE>
</BLOCK>
</TEST>
</Mode1>
<Mode2>
<KOMMENTAR>Header 2</KOMMENTAR>
<TEST>
<NUMBER>5</NUMBER>
</TEST>
<TEST>
<NUMBER>6</NUMBER>
<BLOCK>
<CODE>2.6.1 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>2.6.2 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>2.6.2 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>7</NUMBER>
<BLOCK>
<CODE>2.7.1 - Message</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>8</NUMBER>
</TEST>
<TEST>
<NUMBER>9</NUMBER>
</TEST>
</Mode2>
<Mode3>
<KOMMENTAR>Header 3</KOMMENTAR>
<TEST>
<NUMBER>5</NUMBER>
</TEST>
<TEST>
<NUMBER>6</NUMBER>
</TEST>
<TEST>
<NUMBER>7</NUMBER>
<BLOCK>
<CODE>3.7.1 - Message</CODE>
</BLOCK>
<BLOCK>
<CODE>3.7.2 - Message that spans over several lines</CODE>
</BLOCK>
</TEST>
<TEST>
<NUMBER>8</NUMBER>
</TEST>
<TEST>
<NUMBER>9</NUMBER>
</TEST>
</Mode3>
<Mode9>
Contains some other data
</Mode9>
</Modes>
</root>
所需的输出是 table,如下所示(在 HTML 中):
| Header 1 | Header 2 | Header 3 | Test | Flag | Nr. | Message | Nr. | Message | Nr. | Message | 5 | 0 | | | | | | | 6 | 0 | | | 1 | 2.6.1 - Message | | | | | | | 2 | 2.6.2 - Message | | | | | | | 3 | 2.6.3 - Message | | | 7 | 1 | 1 | 1.7.1 - Message | 1 | 2.7.1 - Message | 1 | 3.7.1 - Message | | | | | | | 2 | 3.7.2 - Message | | | | | | | | that spans over | | | | | | | | several lines | 8 | 1 | 1 | 1.8.1 - Message | | | | | | | 2 | 1.8.2 - Message | | | | | 9 | 0 | | | | | | |
到目前为止,我能想到的最好的办法是在 TEST 下创建一个 sub-table for-each BLOCK。但这看起来很难看,因为当然 "Nr." 和 "Message" headers 不与 sub-table 的内容列对齐。
我已经阅读了一些关于 Muenchian 分组的文章(http://www.jenitennison.com/xslt/grouping/muenchian.html 和关于 Whosebug 的其他问题)并尝试了示例,但我无法为我的数据获取正确的键。
如果有人能帮我解决键和外部 for-each 循环,我想我可以处理剩下的事情。
提前致谢。
If somebody could help me with the keys and the outer for-each loop, I think I can handle the rest.
恕我直言,外循环很简单,真正的问题在后面。以下是执行外循环的方法:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes" encoding="UTF-8" version="1.0"/>
<xsl:key name="test" match="TEST" use="NUMBER" />
<xsl:template match="/">
<table border="1">
<thead>
<tr>
<th colspan="2"/>
<th colspan="2">Header 1</th>
<th colspan="2">Header 2</th>
<th colspan="2">Header 3</th>
</tr>
<tr>
<th>Test</th>
<th>Flag</th>
<th>Nr.</th>
<th>Message</th>
<th>Nr.</th>
<th>Message</th>
<th>Nr.</th>
<th>Message</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="(root/Modes/Mode1/TEST | root/Modes/Mode2/TEST | root/Modes/Mode3/TEST)[count(. | key('test', NUMBER)[1]) = 1]">
<tr>
<td><xsl:value-of select="NUMBER"/></td>
<td><xsl:value-of select="FLAG"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
此时你将拥有:
现在真正的问题来了:如果您希望有一列为每条消息编号并使该编号与相邻的消息对齐,则必须为每条不是第一条消息的消息创建一个单独的行它的专栏。您将需要计算每列中的消息数,并使用三者中的最大值作为前两个单元格的行跨度值。
或者,您可以采取简单的方法并执行以下操作:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" indent="yes" encoding="UTF-8" version="1.0"/>
<xsl:key name="test" match="TEST" use="NUMBER" />
<xsl:template match="/">
<table border="1">
<thead>
<tr>
<th width="5%">Test</th>
<th width="5%">Flag</th>
<th width="30%">Header 1<br/>Message</th>
<th width="30%">Header 2<br/>Message</th>
<th width="30%">Header 3<br/>Message</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="(root/Modes/Mode1/TEST | root/Modes/Mode2/TEST | root/Modes/Mode3/TEST)[count(. | key('test', NUMBER)[1]) = 1]">
<tr>
<td><xsl:value-of select="NUMBER"/></td>
<td><xsl:value-of select="FLAG"/></td>
<td>
<ol>
<xsl:for-each select="key('test', NUMBER)[parent::Mode1]/BLOCK">
<li>
<xsl:value-of select="CODE"/>
</li>
</xsl:for-each>
</ol>
</td>
<td>
<ol>
<xsl:for-each select="key('test', NUMBER)[parent::Mode2]/BLOCK">
<li>
<xsl:value-of select="CODE"/>
</li>
</xsl:for-each>
</ol>
</td>
<td>
<ol>
<xsl:for-each select="key('test', NUMBER)[parent::Mode3]/BLOCK">
<li>
<xsl:value-of select="CODE"/>
</li>
</xsl:for-each>
</ol>
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
生产:
可以使用 CSS 进一步按摩塑形。