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

SpringBoot中如何实现List元素的@XmlElement名称递增?

动态生成XML元素名称的解决方案

问题说明

需要生成如下格式的XML,其中每个MRA_BALANCE_SHEET节点下的元素前缀R0030按10递增(如R0030→R0040),每个节点包含RxxxxC0030和RxxxxC0040两个子元素:

<Entity>
<MRA_BALANCE_SHEET>
       <R0030C0030>value</R0030C0030>
       <R0030C0040>value</R0030C0040>
</MRA_BALANCE_SHEET>
<MRA_BALANCE_SHEET>
       <R0040C0030>value</R0040C0030>
       <R0040C0040>value</R0040C0040>
</MRA_BALANCE_SHEET>
</Entity>

原代码使用XmlAdapter<String, String>仅修改了属性值,导致输出的元素名称仍是原属性名(如<PHP>),不符合预期。

错误原因

原适配器仅替换了元素的文本内容,而非修改元素本身的名称。JAXB默认会根据实体类的属性名生成XML元素名称,单纯修改值无法改变标签名。

解决方法

通过自定义XmlAdapter结合DOM操作,动态构建所需的XML元素结构:

1. 封装子节点实体类

创建BalanceSheetItem类,对应每个MRA_BALANCE_SHEET下的两个子元素值:

public class BalanceSheetItem {
    private String c0030Value;
    private String c0040Value;

    // Getter和Setter
    public String getC0030Value() {
        return c0030Value;
    }

    public void setC0030Value(String c0030Value) {
        this.c0030Value = c0030Value;
    }

    public String getC0040Value() {
        return c0040Value;
    }

    public void setC0040Value(String c0040Value) {
        this.c0040Value = c0040Value;
    }
}

2. 编写自定义XmlAdapter

实现XmlAdapter,将BalanceSheetItem转换为包含动态命名子元素的MRA_BALANCE_SHEET元素:

import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class BalanceSheetAdapter extends XmlAdapter<Object, BalanceSheetItem> {
    // 计数器,按10递增,单线程环境使用静态变量,多线程建议用AtomicInteger
    private static int counter = 30;

    @Override
    public BalanceSheetItem unmarshal(Object v) throws Exception {
        // 反序列化逻辑(根据需求实现)
        Element mraSheet = (Element) v;
        BalanceSheetItem item = new BalanceSheetItem();
        // 遍历子节点获取值
        for (int i = 0; i < mraSheet.getChildNodes().getLength(); i++) {
            Node node = mraSheet.getChildNodes().item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                String nodeName = node.getNodeName();
                if (nodeName.endsWith("C0030")) {
                    item.setC0030Value(node.getTextContent());
                } else if (nodeName.endsWith("C0040")) {
                    item.setC0040Value(node.getTextContent());
                }
            }
        }
        return item;
    }

    @Override
    public Object marshal(BalanceSheetItem item) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.newDocument();

        // 生成动态前缀(如R0030、R0040)
        String prefix = "R" + String.format("%04d", counter);
        counter += 10;

        // 创建C0030子元素
        Element c0030 = doc.createElement(prefix + "C0030");
        c0030.setTextContent(item.getC0030Value());
        // 创建C0040子元素
        Element c0040 = doc.createElement(prefix + "C0040");
        c0040.setTextContent(item.getC0040Value());

        // 创建MRA_BALANCE_SHEET父元素并添加子节点
        Element mraSheet = doc.createElement("MRA_BALANCE_SHEET");
        mraSheet.appendChild(c0030);
        mraSheet.appendChild(c0040);

        return mraSheet;
    }
}

3. 调整根实体类

在Entity类中使用@XmlAnyElement和@XmlJavaTypeAdapter注解,指定使用自定义适配器处理列表:

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.List;

@XmlRootElement(name = "Entity")
public class Entity {
    private List<BalanceSheetItem> mraBalanceSheets;

    @XmlAnyElement
    @XmlJavaTypeAdapter(BalanceSheetAdapter.class)
    public List<BalanceSheetItem> getMraBalanceSheets() {
        return mraBalanceSheets;
    }

    public void setMraBalanceSheets(List<BalanceSheetItem> mraBalanceSheets) {
        this.mraBalanceSheets = mraBalanceSheets;
    }
}

4. 测试生成XML

使用JAXB生成XML的示例代码:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import java.util.ArrayList;
import java.util.List;

public class XmlGenerator {
    public static void main(String[] args) throws Exception {
        JAXBContext context = JAXBContext.newInstance(Entity.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        // 构建测试数据
        Entity entity = new Entity();
        List<BalanceSheetItem> items = new ArrayList<>();

        BalanceSheetItem item1 = new BalanceSheetItem();
        item1.setC0030Value("value1");
        item1.setC0040Value("value2");
        items.add(item1);

        BalanceSheetItem item2 = new BalanceSheetItem();
        item2.setC0030Value("value3");
        item2.setC0040Value("value4");
        items.add(item2);

        entity.setMraBalanceSheets(items);

        // 输出XML
        marshaller.marshal(entity, System.out);
    }
}

注意事项

  • 静态计数器counter在多线程环境下存在线程安全问题,建议替换为AtomicInteger保证线程安全。
  • 反序列化逻辑可根据实际需求调整,若不需要反序列化可简化unmarshal方法。

内容的提问来源于stack exchange,提问作者Elmer Castelo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:25:08