如何用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
相关产品推荐
相关产品推荐

