使用XSL的XML到HTML表

时间:2014-10-26 11:58:29

标签: xslt html-table

我有一个XML文件,我从我的数据库导出,结构如下, '

<output>
    <row>
        <Month>October</Month>
        <Location>kansas</Location>
        <bus_name>bus1</bus_name>
        <bus_type>volvo</bus_type>
        <bus_colour>red</bus_colour>
        <bus_count>10</bus_count>
    </row>
    <row>
        <Month>October</Month>
        <Location>kansas</Location>
        <bus_name>bus1</bus_name>
        <bus_type>Volvo</bus_type>
        <bus_colour>green</bus_colour>
        <bus_count>11</bus_count>
    </row>
        <Month>October</Month>
        <Location>kansas</Location>
        <bus_name>bus1</bus_name>
        <bus_type>Merc</bus_type>
        <bus_colour>blue</bus_colour>
        <bus_count>5</bus_count>
    </row>
So on...
</output>

我需要将表格看作下面附带的图像。 XSL和XML文件将定期刷新。单元格的颜色类似于总线类型。

我是XSL的新手,因此很难找到解决方案。任何帮助将不胜感激。

Table Output

2 个答案:

答案 0 :(得分:1)

就像一个不同的方法,也处理相同bus_types的颜色 Demo

<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<table>
    <tr>
        <td colspan="9">ACME BUS SERVICE</td>
    </tr>
    <tr>
        <td colspan="9">
            Month: <xsl:value-of select="//Month"/>
        </td>
    </tr>
    <tr>
        <td>Season</td>
        <td>Location</td>
        <td>Bus Name</td>
        <td colspan="2">RED</td>
        <td colspan="2">GREEN</td>
        <td colspan="2">BLUE</td>
    </tr>
    <tr>
        <td></td>
        <td></td>
        <td></td>
        <td>Bus Type</td>
        <td>Bus Count</td>
        <td>Bus Type</td>
        <td>Bus Count</td>
        <td>Bus Type</td>
        <td>Bus Count</td>
    </tr>
    <xsl:for-each select="//row[Location[not(preceding::Location/. = .)]]" >
        <xsl:variable name="currentLocation" select="./Location"/>
        <tr>
            <xsl:attribute name="class">
              <xsl:value-of select="$currentLocation"/>
             </xsl:attribute>
            <td>
                <xsl:if test="position()=1">Winter</xsl:if>
            </td>
            <td>
                <xsl:value-of select="$currentLocation"/>
            </td>
            <td>
                <xsl:value-of select="./bus_name"/>
            </td>
            <td>
                <xsl:if test="count(//row[Location= $currentLocation]
                                         [bus_type = //row[Location= $currentLocation]
                                         [bus_colour = 'red']/bus_type]) > 1">
                    <xsl:attribute name="class">color</xsl:attribute>
                </xsl:if>
                <xsl:value-of select="//row[Location= $currentLocation]
                                           [bus_colour = 'red']/bus_type"/>
            </td>
            <td>
                <xsl:value-of select="//row[Location= $currentLocation]
                                           [bus_colour = 'red']/bus_count"/>
            </td>
            <td>
                <xsl:if test="count(//row[Location= $currentLocation]
                                         [bus_type = //row[Location=$currentLocation]  
                                         [bus_colour = 'green']/bus_type]) > 1">
                    <xsl:attribute name="class">color</xsl:attribute>
                </xsl:if>
                <xsl:value-of select="//row[Location= $currentLocation]
                                           [bus_colour = 'green']/bus_type"/>
            </td>
            <td>
                <xsl:value-of select="//row[Location= $currentLocation]
                                           [bus_colour = 'green']/bus_count"/>
            </td>
            <td>
                <xsl:if test="count(//row[Location= $currentLocation]
                                         [bus_type = //row[Location=$currentLocation]  
                                         [bus_colour = 'blue']/bus_type]) > 1">
                    <xsl:attribute name="class">color</xsl:attribute>
                </xsl:if>
                <xsl:value-of select="//row[Location= $currentLocation]
                                           [bus_colour = 'blue']/bus_type"/>
            </td>
            <td>
                <xsl:value-of select="//row[Location= $currentLocation]
                                           [bus_colour = 'blue']/bus_count"/>
            </td>
        </tr>
    </xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

对于每个位置,该位置都设置为<tr>的类名,例如<tr class="kansas">。每个在某个位置使用多次的总线类型的td都会获得class =&#34; color&#34;。因此,要显示具有不同颜色的表格,您只需添加CSS,例如.kansas .color { background-color: blue; }。如果你想根据bus_type显示相同的颜色,只需调整类名&#34;颜色&#34;在xslt中当前的bus_type。

注意:在链接示例中,我只为德克萨斯州添加了一行,以显示XSLT显示多个位置,仅设置第一个季节,并且如果没有提供所有颜色,也可以使用一个位置。并且输出不是有效的HTML(没有提供html-,head-,body-tags等)。正如您所说,您希望获得HTML输出,您可能已经有一个XSLT生成有效的HTML,您可以在其中调整/包含表格所需的部分。

更新注释中的问题:将<tr>的类名设置为bus_type的名称(如果在某个位置使用了bus_type多次)而不是位置:

在上面的XSLT中更改此内容:

<tr>
<xsl:attribute name="class">
   <xsl:value-of select="$currentLocation"/>
</xsl:attribute>

<tr>
<xsl:if test="count(//row[Location=$currentLocation]) >  
              count(//row[Location=$currentLocation]/
                      bus_type[not(. = preceding::bus_type)])">  
    <xsl:attribute name="class">
       <xsl:value-of select="//row[Location=$currentLocation]/
                               bus_type[ . = preceding::bus_type]"/>
    </xsl:attribute>
</xsl:if>

为此更新了Demo 2

附加说明和问题:OP XML的一个调整是改变小写&#34; volvo&#34;到&#34;沃尔沃&#34;。如果来自DB的原始导出确实混合了大写和小写名称,则可以在XSLT中处理这个以小写所有bus_names(以获取唯一值)并将<td>中值的大写字母大写。最好知道你是否使用XSLT 2.0或XSLT 1.0,因为XSLT 2.0提供了简化某些任务的功能 - 例如2.0提供lower-case()函数,其中在1.0中使用translate()可以实现相同的功能 - 作为对此的参考,正如您提到的XSL新手:How can I convert a string to upper- or lower-case with XSLT?
进一步的问题是 - 因为XML示例只是数据库导出的一部分 - 如果每个位置只有一行,或者可能存在各种行,例如堪萨斯巴士1,堪萨斯巴士2等。

对于评论中的第二个问题,

更新2 :我可以添加(几乎)逐行说明,并在完成后删除评论。我认为没有必要覆盖HTML部分,只包括XSLT。与此同时,如您所说,您对XSLT不熟悉,可能以下内容可能有用:
对于<xsl:template match="/"> - https://stackoverflow.com/questions/3127108/xsl-xsltemplate-match
对于XPath轴 - http://www.xmlplease.com/axis
对于一些基础知识,例如 - In what order do templates in an XSLT document execute, and do they match on the source XML or the buffered output?

请注意,在SO处应避免使用扩展注释 - 当帖子下方的评论过多时,将显示一条建议移至聊天的自动消息。因为你需要20的聊天声誉(https://stackoverflow.com/help/privileges),所以目前还不可能。

答案 1 :(得分:0)

  

前三个节点必须与第一行映射

现在 是一个具体的问题。假设您的输入被安排为每组3个连续的<row>元素映射到单个表行(内部组位置与列位置匹配),请尝试这样:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/output">
    <table border="1">
        <tr>
            <!-- build your header here -->
        </tr>
        <xsl:for-each select="row[position() mod 3 = 1]" >
            <tr>
                <td><xsl:value-of select="Location"/></td>
                <td><xsl:value-of select="bus_name"/></td>
                <xsl:for-each select=". | following-sibling::row[position() &lt; 3]">
                    <td><xsl:value-of select="bus_type"/></td>
                    <td><xsl:value-of select="bus_colour"/></td>
                    <td><xsl:value-of select="bus_count"/></td>
                </xsl:for-each>
            </tr>
        </xsl:for-each>
    </table>
</xsl:template>

</xsl:stylesheet>

我建议你问一个关于着色的单独问题。确保我们事先了解确切知道的内容(例如已知总线类型列表?)以及所需输出是什么(将作为代码发布)。