You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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表格的转换?


解决方案

问题根源

  1. 原page-content模板使用<xsl:copy-of>直接复制节点树,不会触发任何模板匹配逻辑,必须改用<xsl:apply-templates>来启动模板处理流程。
  2. 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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 11:17:03