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

