如何用XSLT3.0模板匹配将JSON转换为HTML表格?
问题
我正在尝试使用XSLT3.0将JSON转换为HTML表格。JSON文档结构如下:
{ "ID":1234, "Title":"Garden Club", "Created":1677598782, "Modified":1677796144, "SystemChanged":"Greenhouse", "SystemChangedID":51007, "SystemsAffected":["Greenhouse", "Garden"], "SystemsAffectedID":[51007,89756], "IncidentType":"Maintenance", "Description":"Greenhouse fan motor will be replaced.", "StartDate":1677794400, "Feed":[{ "id":106799743, "commentBy":"Don Knotts", "dateCreated":1677796144, "dateUpdated":1677796144, "content":"Work has been completed successfully. Fan working as expected" }] }
我用以下XSLT将JSON转为XML:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions" xmlns:array="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xsl xs"> <xsl:variable name="reportjson" select="unparsed-text('/_resources/js/issue.json')"/> <xsl:variable name="reportxml" select="json-to-xml($reportjson, map { 'liberal': true() })"/> <xsl:template name="page-content"> <xsl:copy-of select="$reportxml"/> </xsl:template> </xsl:stylesheet>
转换后的XML输出:
<array><map> <number key="ID">1234</number> <string key="Title">Garden Club</string> <number key="Created">1677598782</number> <number key="Modified">1677796144</number> <string key="SystemChanged">Greenhouse</string> <number key="SystemChangedID">51007</number> <array key="SystemsAffected"> <string>Greenhouse</string> <string>Garden</string> </array> <array key="SystemsAffectedID"> <number>51007</number> <number>89756</number> </array> <string key="IncidentType">Maintenance</string> <string key="Description">Greenhouse fan motor will be replaced.</string> <number key="StartDate">1677794400</number> <array key="Feed"><map> <number key="id">106799743</number> <string key="commentBy">Don Knotts</string> <number key="dateCreated">1677796144</number> <number key="dateUpdated">1677796144</number> <string key="content">Work has been completed successfully. Fan working as expected</string> </map> </array> </map> </array>
我尝试用以下模板匹配转成HTML表格,但无法选中任何元素:
<xsl:template match="array"><table><xsl:apply-templates/></table></xsl:template> <xsl:template match="map"><tr><xsl:apply-templates/></tr></xsl:template> <xsl:template match="number|string"><td><xsl:apply-templates select="*/text()"/></td></xsl:template>
此前我用xsl:for-each实现过类似功能,示例代码:
<xsl:for-each select="$reportxml/array"> <table> <xsl:for-each select="map"> <tr>...</tr> </xsl:for-each> </table> </xsl:for-each>
请问如何通过模板匹配实现上述XML到HTML表格的转换?
解决方案
问题根源
- 原
page-content模板使用<xsl:copy-of>直接复制节点树,不会触发任何模板匹配逻辑,必须改用<xsl:apply-templates>来启动模板处理流程。 json-to-xml生成的所有元素(array、map、number、string等)都属于http://www.w3.org/2005/xpath-functions命名空间,模板匹配时必须指定对应的命名空间前缀(你的样式表中已定义map前缀指向该命名空间)。
修改后的完整XSLT代码
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xsl xs map"> <xsl:variable name="reportjson" select="unparsed-text('/_resources/js/issue.json')"/> <xsl:variable name="reportxml" select="json-to-xml($reportjson, map { 'liberal': true() })"/> <xsl:template name="page-content"> <!-- 改用apply-templates触发模板匹配 --> <xsl:apply-templates select="$reportxml"/> </xsl:template> <!-- 匹配根array,生成主表格 --> <xsl:template match="map:array"> <table border="1"> <xsl:apply-templates/> </table> </xsl:template> <!-- 匹配顶层map,生成表格行,每个子元素对应一个单元格 --> <xsl:template match="map:map"> <xsl:for-each select="*"> <tr> <!-- 输出key作为表头 --> <th><xsl:value-of select="@key"/></th> <!-- 应用模板处理当前节点的内容 --> <td><xsl:apply-templates select="."/></td> </tr> </xsl:for-each> </xsl:template> <!-- 匹配普通number/string节点,直接输出文本 --> <xsl:template match="map:number|map:string"> <xsl:value-of select="text()"/> </xsl:template> <!-- 匹配数组节点,将数组内元素用逗号分隔合并输出 --> <xsl:template match="map:array"> <xsl:value-of select="*/text()" separator=", "/> <!-- 处理Feed数组内的map,生成嵌套表格 --> <xsl:if test="@key='Feed'"> <table border="1" style="margin-top:8px;"> <xsl:apply-templates select="map:map"/> </table> </xsl:if> </xsl:template> <!-- 匹配Feed内的子map,生成评论详情行 --> <xsl:template match="map:map[parent::map:array[@key='Feed']]"> <tr> <th>Comment By</th> <td><xsl:value-of select="map:string[@key='commentBy']"/></td> </tr> <tr> <th>Content</th> <td><xsl:value-of select="map:string[@key='content']"/></td> </tr> <tr> <th>Created</th> <td><xsl:value-of select="format-dateTime(xs:dateTime('1970-01-01T00:00:00') + xs:dayTimeDuration(concat('PT', map:number[@key='dateCreated'], 'S')), '[M01]/[D01]/[Y0001] [H01]:[m01]')"/></td> </tr> </xsl:template> </xsl:stylesheet>
代码说明
- 替换
<xsl:copy-of>为<xsl:apply-templates select="$reportxml"/>,启动模板匹配流程。 - 所有模板匹配都使用
map:前缀,确保能正确匹配到命名空间下的元素。 - 顶层map采用
for-each遍历子元素,生成th(表头)和td(内容)的行结构,更符合表格展示逻辑。 - 针对数组类型的节点(如
SystemsAffected),用separator=", "合并数组元素;针对Feed数组,额外生成嵌套表格展示评论详情。 - 对时间戳进行了格式化转换,将Unix时间戳转为可读的日期时间格式。
内容的提问来源于stack exchange,提问作者Bryan C.
相关产品推荐
相关产品推荐

