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

如何将Java对象列表编组/解组为无根元素的XML?

问题场景

我有一个结构如下的Employee类Java对象列表:

@XmlRootElement(name = "employee")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employee 
{
  private Integer id;
  private String firstName;
  private String lastName;
  private double income;
   
  //Getters and Setters
}

我希望将其转换为不含根元素的XML文件,预期输出如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<employee>
    <id>1</id>
    <firstName>Lokesh</firstName>
    <lastName>Gupta</lastName>
    <income>100.0</income>
</employee>
<employee>
    <id>2</id>
    <firstName>John</firstName>
    <lastName>Mclane</lastName>
    <income>200.0</income>
</employee>

尝试直接编组列表未成功,用包装类编组会自动添加根元素(包装类代码及输出如下):

@XmlRootElement(name = "employees")
@XmlAccessorType (XmlAccessType.FIELD)
public class Employees 
{
  @XmlElement(name = "employee")
  private List<Employee> employees = null;
}

输出的XML会包含<employees>根节点:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<employees>
    <employee>
        <id>1</id>
        <firstName>Lokesh</firstName>
        <lastName>Gupta</lastName>
        <income>100.0</income>
    </employee>
    <employee>
        <id>2</id>
        <firstName>John</firstName>
        <lastName>Mclane</lastName>
        <income>200.0</income>
    </employee>
</employees>

想问:能不能通过JAXB或其他Java转XML库实现需求?同时能否将这种无根元素的XML反向解组为Java POJO?


解决方案

一、使用JAXB实现无根元素编组

JAXB默认要求文档有单一根元素,但可以通过逐个编组列表中的每个对象生成无根节点的XML:

编组代码示例

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.io.FileWriter;
import java.util.List;

public class JaxbMarshaller {
    public static void marshalEmployees(List<Employee> employees, String filePath) throws Exception {
        JAXBContext context = JAXBContext.newInstance(Employee.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.setProperty(Marshaller.JAXB_STANDALONE, true);

        try (FileWriter writer = new FileWriter(filePath)) {
            // 手动写入XML声明
            writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n");
            
            // 逐个编组每个Employee对象
            for (Employee emp : employees) {
                marshaller.marshal(emp, writer);
                writer.write("\n"); // 换行分隔节点,提升可读性
            }
        }
    }
}

二、反向解组无根元素XML

无根元素的XML不符合标准XML文档结构(要求有且仅有一个根节点),直接用JAXB解组会报错,可通过以下两种方式处理:

1. 手动读取XML节点逐个解组

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class JaxbUnmarshaller {
    public static List<Employee> unmarshalEmployees(String filePath) throws Exception {
        List<Employee> employees = new ArrayList<>();
        JAXBContext context = JAXBContext.newInstance(Employee.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(new File(filePath));
        
        // 提取所有employee节点并逐个解组
        NodeList nodeList = doc.getElementsByTagName("employee");
        for (int i = 0; i < nodeList.getLength(); i++) {
            Element element = (Element) nodeList.item(i);
            Employee emp = (Employee) unmarshaller.unmarshal(element);
            employees.add(emp);
        }
        return employees;
    }
}

2. 借助StAX流读取解组

用StAX遍历XML事件,遇到employee节点时执行解组:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

public class StaxUnmarshaller {
    public static List<Employee> unmarshalEmployees(String filePath) throws Exception {
        List<Employee> employees = new ArrayList<>();
        JAXBContext context = JAXBContext.newInstance(Employee.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();

        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream(filePath));

        // 遍历XML事件,解组每个employee节点
        while (reader.hasNext()) {
            if (reader.isStartElement() && "employee".equals(reader.getLocalName())) {
                Employee emp = unmarshaller.unmarshal(reader, Employee.class).getValue();
                employees.add(emp);
            }
            reader.next();
        }
        reader.close();
        return employees;
    }
}

三、使用Jackson XML库实现(更简洁)

Jackson XML库对无根元素的支持更友好,无需手动处理节点:

1. 添加Maven依赖

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.15.2</version>
</dependency>

2. 修改Employee类注解

给Employee类添加Jackson XML的根节点注解(可保留原JAXB注解):

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

@JacksonXmlRootElement(localName = "employee")
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
    // 字段、Getters和Setters不变
}

3. 编组代码

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.util.List;

public class JacksonMarshaller {
    public static void marshalEmployees(List<Employee> employees, String filePath) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
        xmlMapper.writeValue(new File(filePath), employees);
    }
}

4. 解组代码

import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.util.List;

public class JacksonUnmarshaller {
    public static List<Employee> unmarshalEmployees(String filePath) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        return xmlMapper.readValue(new File(filePath), new com.fasterxml.jackson.core.type.TypeReference<List<Employee>>(){});
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 09:13:25