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

如何使用XSLT实现JSON转JSON?解决Saxon HE相关报错

JSON转JSON的XSLT转换问题及解决方案

需求说明

使用XSLT技术将输入JSON转换为指定结构的JSON。

输入JSON

{
  "members": [
    {
      "name": "Molecule Man1",
      "age": 29,
      "secretIdentity": "Dan Jukes"
    },
    {
      "name": "Molecule Man2",
      "age": 30,
      "secretIdentity": "Martin"
    }
  ]
}

期望输出JSON

{
   "resourceType": "Test",
   "type": {
      "name": "Member"
   },
   "displayName": "Molecule Man",
   "attributes": {
      "test": [
         {
            "value": "29"
         }
      ],
      "testing": [
         {
            "value": "Dan Jukes"
         }
      ]
   }
}

遇到的错误

  • SERE0023 JSON序列化:无法处理长度为2的序列
  • 尝试使用<saxon::array>时提示“saxon:array未被识别为Saxon指令,Saxon扩展需要Saxon-PE或更高版本”

现有代码

Java代码

package com.practice;

import net.sf.saxon.s9api.*;
import javax.xml.transform.stream.StreamSource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class JsonToXsltToJson {
    public static void main(String[] args) throws FileNotFoundException, SaxonApiException {
        Processor processor = new Processor(false);
        TransformJson(processor);
    }

    static void TransformJson(Processor processor) throws FileNotFoundException, SaxonApiException {
        JsonBuilder jsonBuilder = processor.newJsonBuilder();
        XdmValue input = jsonBuilder.parseJson(new InputStreamReader(new FileInputStream("input.json"), StandardCharsets.UTF_8));
        XsltCompiler xsltCompiler = processor.newXsltCompiler();
        XsltExecutable xsltExecutable = xsltCompiler.compile(new StreamSource(new File("jsonTransform.xsl")));
        Xslt30Transformer xslt30Transformer = xsltExecutable.load30();
        xslt30Transformer.applyTemplates(input, xslt30Transformer.newSerializer(System.out));
    }
}

原XSLT代码

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="3.0"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:map="http://www.w3.org/2005/xpath-functions/map"
                xmlns:mf="http://example.com/mf" 
                exclude-result-prefixes="#all">

    <xsl:param name="nodes" as="map(*)*"/>

    <xsl:template name="init">
        <xsl:apply-templates select="($nodes)"/>
    </xsl:template>

    <xsl:template  match=".">
        <xsl:map>
            <xsl:map-entry key="'resourceType'" select="'Test'"/>
            <xsl:map-entry key="'type'">
            <xsl:map-entry key="'name'" select="'Member'"/>
            </xsl:map-entry>
            <xsl:map-entry key="'displayName'" select= "?members?1?name"/>
            <xsl:map-entry key="'attributes'">
            <xsl:map-entry key="'age'">
            <xsl:map-entry key="'value'" select="?members?1?age"/>
            </xsl:map-entry>
                <xsl:map-entry key="'secretIdentity'">
                    <xsl:map-entry key="'value'" select="?members?1?secretIdentity"/>
                </xsl:map-entry>
            </xsl:map-entry>
        </xsl:map>
    </xsl:template>
    <xsl:output method="json" indent="yes"/>
</xsl:stylesheet>

解决方案

错误原因分析

  1. SERE0023错误:原XSLT中定义的nodes参数未被正确传入值,模板匹配逻辑导致输出多节点序列,而JSON序列化要求输出单个map或数组。
  2. saxon:array不支持:saxon:array是Saxon-PE及以上版本的扩展指令,Saxon HE不兼容,需改用XSLT 3.0标准数组构造语法。

修改后的XSLT代码

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="3.0"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                exclude-result-prefixes="#all">

    <!-- 输出JSON格式并开启缩进 -->
    <xsl:output method="json" indent="yes"/>
    <!-- 指定初始模板为main,避免匹配逻辑歧义 -->
    <xsl:initial-template name="main"/>

    <xsl:template name="main">
        <!-- 获取第一个成员数据 -->
        <xsl:variable name="first-member" select="?members?1"/>
        <!-- 构造目标JSON对应的map结构 -->
        <xsl:map>
            <xsl:map-entry key="'resourceType'" select="'Test'"/>
            <!-- 嵌套map构造type字段 -->
            <xsl:map-entry key="'type'" select="map { 'name': 'Member' }"/>
            <xsl:map-entry key="'displayName'" select="'Molecule Man'"/>
            <xsl:map-entry key="'attributes'">
                <xsl:map>
                    <!-- 使用标准数组构造语法array{},将value包装为数组元素 -->
                    <xsl:map-entry key="'test'" select="array{ map { 'value': string($first-member?age) } }"/>
                    <xsl:map-entry key="'testing'" select="array{ map { 'value': $first-member?secretIdentity } }"/>
                </xsl:map>
            </xsl:map-entry>
        </xsl:map>
    </xsl:template>

</xsl:stylesheet>

修改后的Java代码

调整调用逻辑,触发指定初始模板,避免原applyTemplates的匹配问题:

package com.practice;

import net.sf.saxon.s9api.*;
import javax.xml.transform.stream.StreamSource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class JsonToXsltToJson {
    public static void main(String[] args) throws FileNotFoundException, SaxonApiException {
        Processor processor = new Processor(false);
        TransformJson(processor);
    }

    static void TransformJson(Processor processor) throws FileNotFoundException, SaxonApiException {
        JsonBuilder jsonBuilder = processor.newJsonBuilder();
        // 解析输入JSON为根map节点
        XdmNode input = jsonBuilder.parseJson(new InputStreamReader(new FileInputStream("input.json"), StandardCharsets.UTF_8)).itemAt(0).asNode();
        XsltCompiler xsltCompiler = processor.newXsltCompiler();
        XsltExecutable xsltExecutable = xsltCompiler.compile(new StreamSource(new File("jsonTransform.xsl")));
        Xslt30Transformer xslt30Transformer = xsltExecutable.load30();
        // 设置初始模板的上下文节点为输入JSON根节点
        xslt30Transformer.setInitialContextNode(input);
        // 调用初始模板main生成输出
        xslt30Transformer.callTemplate(new QName("main"), xslt30Transformer.newSerializer(System.out));
    }
}

关键修改点

  1. XSLT方面:
    • 移除未使用的nodes参数,改用xsl:initial-template指定入口模板,确保输出单个map结构,解决序列长度错误。
    • 使用XSLT 3.0标准的array{...}语法构造数组,替代非标准的saxon:array,兼容Saxon HE。
    • 对齐期望输出的字段名(如test、testing),调整嵌套map结构。
  2. Java方面:
    • 将解析后的XdmValue转为XdmNode,作为初始模板的上下文节点。
    • 使用callTemplate触发指定初始模板,避免applyTemplates的匹配歧义。

内容的提问来源于stack exchange,提问作者Ram Prasad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 10:57:46