JAXB读取嵌套元素列表返回null问题排查与解决
JAXB读取XML嵌套元素列表返回null的排查与解决
问题场景
我要解析一段医药产品信息的XML,结构如下:
<produktyLecznicze stanNaDzien="2023-05-26" xmlns="http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0"> <produktLeczniczy nazwaProduktu="Zoledronic acid Fresenius Kabi" rodzajPreparatu="ludzki" nazwaPowszechnieStosowana="Acidum zoledronicum" moc="4 mg/5 ml" postac="Koncentrat do sporządzania roztworu do infuzji" podmiotOdpowiedzialny="Fresenius Kabi Polska Sp. z o.o." typProcedury="DCP" numerPozwolenia="20708" waznoscPozwolenia="Bezterminowy" kodATC="M05BA08" id="100000014"> <opakowania> <opakowanie wielkosc="1" jednostkaWielkosci="fiol. 5 ml " kodEAN="05909991023652" kategoriaDostepnosci="Rpz" skasowane="NIE" numerEu="" dystrybutorRownolegly="" id="2"/> <opakowanie wielkosc="4" jednostkaWielkosci="fiol. 5 ml " kodEAN="05909991023669" kategoriaDostepnosci="Rpz" skasowane="NIE" numerEu="" dystrybutorRownolegly="" id="3"/> <opakowanie wielkosc="10" jednostkaWielkosci="fiol. 5 ml " kodEAN="05909991023676" kategoriaDostepnosci="Rpz" skasowane="NIE" numerEu="" dystrybutorRownolegly="" id="4"/> </opakowania> <substancjeCzynne> <substancjaCzynna>Acidum zoledronicum</substancjaCzynna> </substancjeCzynne> </produktLeczniczy> ... </produktyLecznicze>
用JAXB解析时,根元素produktyLecznicze的stanNaDzien属性能正常读取,但嵌套的produktLeczniczy元素列表一直返回null;同时现有的ProduktLeczniczy类也未处理内部的opakowania和substancjeCzynne子元素。
现有代码
ProduktyLecznicze类
@Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "produktyLecznicze", namespace="http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0") public class ProduktyLecznicze { @XmlAttribute(name = "stanNaDzien") private String stanNaDzien; @XmlElement(name = "produktLeczniczy") private List<ProduktLeczniczy> produktyLecznicze; }
ProduktLeczniczy类
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @ToString @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "produktLeczniczy", namespace = "http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0") public class ProduktLeczniczy { @XmlAttribute(name ="nazwaProduktu") private String nazwaProduktu; @XmlAttribute(name ="rodzajPreparatu") private String rodzajPreparatu; @XmlAttribute(name ="nazwaPowszechnieStosowana") private String nazwaPowszechnieStosowana; @XmlAttribute(name ="moc") private String moc; @XmlAttribute(name ="postac") private String postac; @XmlAttribute(name ="podmiotOdpowiedzialny") private String podmiotOdpowiedzialny; @XmlAttribute(name ="typProcedury") private String typProcedury; @XmlAttribute(name ="numerPozwolenia") private String numerPozwolenia; @XmlAttribute(name ="waznoscPozwolenia") private String waznoscPozwolenia; @XmlAttribute(name ="kodATC") private String kodATC; @XmlAttribute(name ="id") private int id; }
问题原因
- 命名空间未匹配:XML中所有元素都属于指定命名空间,但
ProduktyLecznicze类的@XmlElement未指定namespace,JAXB无法识别对应命名空间下的produktLeczniczy元素。 - 缺少子元素映射:
ProduktLeczniczy类未定义opakowania和substancjeCzynne的对应字段,无法解析这部分嵌套内容。 - 列表未初始化:若列表字段未提前创建实例,JAXB不会自动初始化,导致返回null。
解决步骤
1. 统一处理命名空间(推荐方案)
在Java类所在包下创建package-info.java,统一指定命名空间和元素格式,避免每个元素重复配置:
@XmlSchema( namespace = "http://rejestrymedyczne.ezdrowie.gov.pl/rpl/eksport-danych-v1.0", elementFormDefault = XmlNsForm.QUALIFIED ) package 你的包路径; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema;
配置后,所有JAXB类的元素会默认使用该命名空间,无需在@XmlRootElement或@XmlElement中重复声明。
2. 修正ProduktyLecznicze类
提前初始化列表字段,确保JAXB能正常注入数据:
@Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "produktyLecznicze") public class ProduktyLecznicze { @XmlAttribute(name = "stanNaDzien") private String stanNaDzien; @XmlElement(name = "produktLeczniczy") // 提前初始化列表,避免返回null private List<ProduktLeczniczy> produktyLecznicze = new ArrayList<>(); }
3. 补充嵌套元素对应的类并完善ProduktLeczniczy
创建Opakowania类
对应XML中的<opakowania>元素:
@Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor @XmlAccessorType(XmlAccessType.FIELD) public class Opakowania { @XmlElement(name = "opakowanie") private List<Opakowanie> opakowaniaList = new ArrayList<>(); }
创建Opakowanie类
对应XML中的<opakowanie>元素:
@Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor @XmlAccessorType(XmlAccessType.FIELD) public class Opakowanie { @XmlAttribute(name = "wielkosc") private int wielkosc; @XmlAttribute(name = "jednostkaWielkosci") private String jednostkaWielkosci; @XmlAttribute(name = "kodEAN") private String kodEAN; @XmlAttribute(name = "kategoriaDostepnosci") private String kategoriaDostepnosci; @XmlAttribute(name = "skasowane") private String skasowane; @XmlAttribute(name = "numerEu") private String numerEu; @XmlAttribute(name = "dystrybutorRownolegly") private String dystrybutorRownolegly; @XmlAttribute(name = "id") private int id; }
创建SubstancjeCzynne类
对应XML中的<substancjeCzynne>元素:
@Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor @XmlAccessorType(XmlAccessType.FIELD) public class SubstancjeCzynne { @XmlElement(name = "substancjaCzynna") private String substancjaCzynna; }
完善ProduktLeczniczy类
添加嵌套元素的字段:
@Getter @Setter @AllArgsConstructor @NoArgsConstructor @ToString @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "produktLeczniczy") public class ProduktLeczniczy { @XmlAttribute(name ="nazwaProduktu") private String nazwaProduktu; @XmlAttribute(name ="rodzajPreparatu") private String rodzajPreparatu; @XmlAttribute(name ="nazwaPowszechnieStosowana") private String nazwaPowszechnieStosowana; @XmlAttribute(name ="moc") private String moc; @XmlAttribute(name ="postac") private String postac; @XmlAttribute(name ="podmiotOdpowiedzialny") private String podmiotOdpowiedzialny; @XmlAttribute(name ="typProcedury") private String typProcedury; @XmlAttribute(name ="numerPozwolenia") private String numerPozwolenia; @XmlAttribute(name ="waznoscPozwolenia") private String waznoscPozwolenia; @XmlAttribute(name ="kodATC") private String kodATC; @XmlAttribute(name ="id") private int id; @XmlElement(name = "opakowania") private Opakowania opakowania; @XmlElement(name = "substancjeCzynne") private SubstancjeCzynne substancjeCzynne; }
4. 解析验证示例
public class JAXBParserDemo { public static void main(String[] args) { try { JAXBContext jaxbContext = JAXBContext.newInstance(ProduktyLecznicze.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); // 替换为你的XML文件路径 ProduktyLecznicze produkty = (ProduktyLecznicze) unmarshaller.unmarshal(new File("produkty.xml")); System.out.println("数据日期:" + produkty.getStanNaDzien()); System.out.println("产品数量:" + produkty.getProduktyLecznicze().size()); ProduktLeczniczy firstProdukt = produkty.getProduktyLecznicze().get(0); System.out.println("第一个产品名:" + firstProdukt.getNazwaProduktu()); System.out.println("该产品包装数量:" + firstProdukt.getOpakowania().getOpakowaniaList().size()); } catch (JAXBException e) { e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者wazzupek01
相关产品推荐
相关产品推荐

