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

如何用JAXB解析嵌套XML?遇UnmarshalException错误求助

解决JAXB解析XML时的UnmarshalException异常

我有如下嵌套XML,希望解析出RevisionList元素下的history列表:

<vehicleHistoryList ml-update="aware" ml-stage="preload">
   <ExtractInfo date="2011-11-11T17:50:41.011-02:00" requestedRevision="4.0">
      <LoadTimes>
         <entry key="Vehicle History List DAO">1111</entry>
         <entry key="Test DAO">111</entry>
      </LoadTimes>
      <ComponentVersions>
         <entry key="Vehicle List Engine">1.44.1-190949</entry>
         <entry key="Vehicle List DAO">1.44.1-190949</entry>
         <entry key="WebService">1.44.1-190949</entry>
      </ComponentVersions>
      <debug dateTime="2022-11-28T17:50:41.011-05:00" enabled="false" />
   </ExtractInfo>
   <RevisionList>
      <history Acode="111111" RevCode="1227535.0" EffectiveDate="2022-07-25T00:00:00.000" LockedDate="2022-11-14T22:22:12.670-05:00" Latest_Change_Date="2022-11-11T23:11:46.400-05:00" Latest_Status_Change_Date="2022-11-11T18:03:15.553-05:00" />
      <history Acode="222222" RevCode="1192984.1" EffectiveDate="2022-06-14T00:00:00.000" LockedDate="2022-07-25T23:02:06.987-04:00" Latest_Change_Date="2022-11-11T23:11:46.417-05:00" Latest_Status_Change_Date="2022-06-15T07:05:42.470-04:00" Embargo_Date="2049-12-31T00:01:00-05:00" />
   </RevisionList>
</vehicleHistoryList>

执行vehicleHistoryList = (VehicleHistoryList) jaxbUnmarshaller.unmarshal(xmlSource);时,出现UnmarshalException: unexpected elements错误,以下是我编写的实体类:

VehicleHistoryList.java

@XmlRootElement(name="vehicleHistoryList")
@XmlAccessorType(XmlAccessType.FIELD)
public class VehicleHistoryList implements Serializable {
    private static final long serialVersionUID = 6906338837295291920L;

    @XmlElementWrapper(name="ExtractInfo")
    ExtractInfo extractInfo;

    @XmlElementWrapper(name = "RevisionList")
    @XmlElement(name="history")
    private List<History> history;

    public List<History> getHistory() {
        return history;
    }

    public void setHistory(List<History> history) {
        this.history = history;
    }
}

History.java

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class History implements Serializable {
    private static final long serialVersionUID = 542831991244445544L;

    @XmlAttribute(
            name = "Acode"
    )
    private String acode;

    @XmlAttribute(
            name = "RevCode"
    )
    private double revcode;

    @XmlJavaTypeAdapter(CustomDateTimeAdapter.class)
    @XmlAttribute(
            name = "EffectiveDate"
    )
    private Date effectiveDate;

    @XmlAttribute(
            name = "PriceLevel"
    )
    private Date priceLevel;

    @XmlAttribute(
            name = "LockedDate"
    )
    private Date lockedDate;

    @XmlAttribute(
            name = "Latest_Change_Date"
    )
    private Date latestChangeDate;

    @XmlAttribute(
            name = "Latest_Status_Change_Date"
    )
    private Date latestStatusChangeDate;

    public History() {
    }

    public String getAcode() {
        return acode;
    }

    public void setAcode(String acode) {
        this.acode = acode;
    }
}

错误原因及修正方案

1. ExtractInfo注解错误

@XmlElementWrapper用于包裹集合类型的元素,而ExtractInfo是单个节点,应该替换为@XmlElement注解。

2. 实体类与XML属性不匹配

  • History类中定义了XML不存在的PriceLevel属性,JAXB默认会校验未知属性,导致报错,需删除该属性。
  • XML中history节点包含Embargo_Date属性,但History类未定义,需添加对应属性并配置日期适配器。

修正后的代码

修正后的VehicleHistoryList.java
@XmlRootElement(name="vehicleHistoryList")
@XmlAccessorType(XmlAccessType.FIELD)
public class VehicleHistoryList implements Serializable {
    private static final long serialVersionUID = 6906338837295291920L;

    @XmlElement(name="ExtractInfo")
    private ExtractInfo extractInfo;

    @XmlElementWrapper(name = "RevisionList")
    @XmlElement(name="history")
    private List<History> history;

    public List<History> getHistory() {
        return history;
    }

    public void setHistory(List<History> history) {
        this.history = history;
    }

    public ExtractInfo getExtractInfo() {
        return extractInfo;
    }

    public void setExtractInfo(ExtractInfo extractInfo) {
        this.extractInfo = extractInfo;
    }
}
修正后的History.java
@XmlAccessorType(XmlAccessType.FIELD)
public class History implements Serializable {
    private static final long serialVersionUID = 542831991244445544L;

    @XmlAttribute(name = "Acode")
    private String acode;

    @XmlAttribute(name = "RevCode")
    private double revcode; // 建议改用String或BigDecimal避免浮点精度问题

    @XmlJavaTypeAdapter(CustomDateTimeAdapter.class)
    @XmlAttribute(name = "EffectiveDate")
    private Date effectiveDate;

    @XmlJavaTypeAdapter(CustomDateTimeAdapter.class)
    @XmlAttribute(name = "LockedDate")
    private Date lockedDate;

    @XmlJavaTypeAdapter(CustomDateTimeAdapter.class)
    @XmlAttribute(name = "Latest_Change_Date")
    private Date latestChangeDate;

    @XmlJavaTypeAdapter(CustomDateTimeAdapter.class)
    @XmlAttribute(name = "Latest_Status_Change_Date")
    private Date latestStatusChangeDate;

    @XmlJavaTypeAdapter(CustomDateTimeAdapter.class)
    @XmlAttribute(name = "Embargo_Date")
    private Date embargoDate;

    public History() {
    }

    public String getAcode() {
        return acode;
    }

    public void setAcode(String acode) {
        this.acode = acode;
    }

    public double getRevcode() {
        return revcode;
    }

    public void setRevcode(double revcode) {
        this.revcode = revcode;
    }

    public Date getEffectiveDate() {
        return effectiveDate;
    }

    public void setEffectiveDate(Date effectiveDate) {
        this.effectiveDate = effectiveDate;
    }

    public Date getLockedDate() {
        return lockedDate;
    }

    public void setLockedDate(Date lockedDate) {
        this.lockedDate = lockedDate;
    }

    public Date getLatestChangeDate() {
        return latestChangeDate;
    }

    public void setLatestChangeDate(Date latestChangeDate) {
        this.latestChangeDate = latestChangeDate;
    }

    public Date getLatestStatusChangeDate() {
        return latestStatusChangeDate;
    }

    public void setLatestStatusChangeDate(Date latestStatusChangeDate) {
        this.latestStatusChangeDate = latestStatusChangeDate;
    }

    public Date getEmbargoDate() {
        return embargoDate;
    }

    public void setEmbargoDate(Date embargoDate) {
        this.embargoDate = embargoDate;
    }
}

额外说明

如果不需要严格校验XML属性,可以通过配置JAXB忽略未知元素:

jaxbUnmarshaller.setEventHandler(new DefaultValidationEventHandler());

但更推荐让实体类结构与XML完全匹配,避免潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 03:40:34