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

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;
}

问题原因

  1. 命名空间未匹配:XML中所有元素都属于指定命名空间,但ProduktyLecznicze类的@XmlElement未指定namespace,JAXB无法识别对应命名空间下的produktLeczniczy元素。
  2. 缺少子元素映射:ProduktLeczniczy类未定义opakowania和substancjeCzynne的对应字段,无法解析这部分嵌套内容。
  3. 列表未初始化:若列表字段未提前创建实例,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 03:12:07