XSLT:从不同节点创建组合表

时间:2015-03-26 09:04:03

标签: xml xslt xpath

我想创建一个组合表,其中包含来自xml源中不同子节点的数据。

源(大致)如下:请注意,我已经简化了示例。 "模式"在更大的xml文档和" BLOCK"中,节点是几个级别。节点不仅包含" CODE"儿童。 从三个不同的节点Mode1,Mode2和Mode3收集数据。源文档中有更多的ModeX(X = 1..10)节点,但它们不会进入此特定表。

<?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>

所需的输出是如下表格(以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下面的每个BLOCK创建一个子表。但这看起来很丑陋,因为当然是&#34; Nr。&#34;和&#34;消息&#34;标头不与子表的内容列对齐。

我已经阅读了一些关于Muenchian分组的文章(http://www.jenitennison.com/xslt/grouping/muenchian.html以及有关stackoverflow的其他问题)并尝试了这些示例,但我无法获得适合我数据的密钥。

如果有人可以帮助我使用键和外部for-each循环,我想我可以处理其余部分。

提前致谢。

1 个答案:

答案 0 :(得分:0)

  

如果有人可以帮助我使用键和外部for-each循环,我   我想我可以处理剩下的事了。

恕我直言,外环很容易,真正的问题出现了。以下是外循环的方法:

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>

此时您将拥有:

enter image description here

现在出现了一个真正的问题:如果您想要一个为每条消息编号的列并使该号码与相邻消息对齐,则必须为每个消息创建一个单独的行,而不是列中的第一个消息。您需要计算每列中的消息数,并使用这三个中的最大值作为前两个单元格的rowspan值。

或者,您可以采取简单的方法,并执行以下操作:

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>

生产: enter image description here

可以使用CSS进一步按摩成形。