我有一个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的新手,因此很难找到解决方案。任何帮助将不胜感激。
答案 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() < 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>
我建议你问一个关于着色的单独问题。确保我们事先了解确切知道的内容(例如已知总线类型列表?)以及所需输出是什么(将作为代码发布)。