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

JSON转Java POJO遇GSON解析异常,求XSD xs:choice场景解决方案

解决GSON解析XML转JSON时的xs:choice与数组匹配问题

看起来你遇到的问题主要来自两个核心点:XML转JSON时单个元素被转为对象而非数组,以及xs:choice结构在POJO中的映射处理。我来一步步帮你梳理解决方案:

1. 先解决核心报错:MOVIMIENTO的数组/对象不匹配

你的错误Expected BEGIN_ARRAY but was BEGIN_OBJECT说明GSON期望MOVIMIENTO是数组,但实际JSON里它是单个对象。这是因为org.json的XML.toJSONObject默认逻辑:当XML中某个元素只有一个实例时,会转成JSON对象;多个实例才会转成数组。而你的XSD里MOVIMIENTO的maxOccurs="31",但minOccurs默认是1,所以当只有一条MOVIMIENTO数据时,转JSON就会变成对象,和POJO里定义的MOVIMIENTO[]类型不匹配。

修复方法:强制XML转JSON时保留数组结构

修改XML转JSON的代码,使用XMLParserConfiguration来强制让指定元素(或所有重复元素)始终以数组形式输出:

import org.json.XML;
import org.json.XMLParserConfiguration;

// 创建配置,开启"始终保留数组"模式
XMLParserConfiguration config = new XMLParserConfiguration();
config.setKeepArrays(true);

// 用配置好的规则转XML为JSON
JSONObject xmlJSONObj = XML.toJSONObject(xmlString, config);

这样不管MOVIMIENTO有1个还是31个,转出来的JSON里它都会是数组,GSON解析MOVIMIENTO[]就不会报错了。

2. 处理xs:choice的POJO映射

对于RESIDENCIA的二选一字段(ID_PAIS/ID_PROVINCIA_ISLA),你手动添加两个字段的做法是没问题的。GSON的默认行为会自动忽略JSON中不存在的字段,也就是说:

  • 当JSON里有ID_PROVINCIA_ISLA时,POJO的ID_PAIS会是null
  • 当JSON里有ID_PAIS时,POJO的ID_PROVINCIA_ISLA会是null

完全符合xs:choice的业务逻辑,后续你只需要在代码里判断哪个字段不为null即可。

如果想要更严谨的约束(确保只有一个ID字段被赋值),也可以自定义GSON反序列化器:

public class ResidenciaDeserializer implements JsonDeserializer<RESIDENCIA> {
    @Override
    public RESIDENCIA deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        RESIDENCIA residencia = new RESIDENCIA();
        JsonObject obj = json.getAsJsonObject();
        
        // 解析MOVIMIENTO数组
        residencia.MOVIMIENTO = context.deserialize(obj.get("MOVIMIENTO"), MOVIMIENTO[].class);
        
        // 处理二选一的ID字段
        if (obj.has("ID_PAIS")) {
            residencia.ID_PAIS = obj.get("ID_PAIS").getAsString();
        } else if (obj.has("ID_PROVINCIA_ISLA")) {
            residencia.ID_PROVINCIA_ISLA = obj.get("ID_PROVINCIA_ISLA").getAsString();
        }
        
        return residencia;
    }
}

然后注册这个反序列化器到GSON:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(RESIDENCIA.class, new ResidenciaDeserializer())
    .create();

3. 可选优化:跳过JSON中转,直接用JAXB解析XML

既然你有XSD文件,其实可以绕开XML转JSON的步骤,直接用JAXB生成POJO并解析XML,这样原生支持xs:choice结构,更准确也更高效。

步骤:

  1. 用JAXB的xjc工具根据XSD生成POJO类
  2. 直接用JAXBContext解析XML:
JAXBContext jaxbContext = JAXBContext.newInstance(ENCUESTA.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
ENCUESTA encuesta = (ENCUESTA) unmarshaller.unmarshal(new StringReader(xmlString));

JAXB生成的RESIDENCIA类会自动处理xs:choice,比如生成一个Object类型的字段或者带注解的二选一属性,完全符合XSD的约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:28:37