使用Java构造XML字符串
概述
项目需要构造如下的XML字符串(如果需要xml头部的声明,可自行去除代码的配置即可)
<xml>
<ToUserName><![CDATA[ToUserName]]></ToUserName>
<FromUserName><![CDATA[FromUserName]]></FromUserName>
<CreateTime>CreateTime</CreateTime>
<MsgType><![CDATA[MsgType]]></MsgType>
<TemplateCard>
<CardType><![CDATA[CardType]]></CardType>
<MainTitle>
<Title><![CDATA[MainTitle]]></Title>
</MainTitle>
<SubTitleText><![CDATA[SubTitleText]]></SubTitleText>
<ButtonList>
<Text><![CDATA[button_1]]></Text>
<Style>1</Style>
<Key><![CDATA[button_key_1]]></Key>
</ButtonList>
<ReplaceText><![CDATA[已提交]]></ReplaceText>
</TemplateCard>
</xml>
实现方式
使用如下工具类可以自行构建想要的XML字符串。需要引入lombok依赖(懒得写get和set方法了)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
package com.jusdaglobal.aichat.util;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@Slf4j
public class XmlBuilderUtils {
/**
* 构造XML字符串
* @param rootElementName 根元素名
* @param nodeList 节点列表
* @return 构造的XML字符串
*/
public static String build(String rootElementName, List<Node> nodeList) {
// 创建DocumentBuilderFactory和DocumentBuilder对象
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
try {
dBuilder = dbFactory.newDocumentBuilder();
// 创建新的Document对象和根元素
Document doc = dBuilder.newDocument();
Element rootElement = doc.createElement(rootElementName);
doc.appendChild(rootElement);
// 添加子节点和属性到根元素
for (Node node : nodeList) {
Element element = doc.createElement(node.getName());
if (node.isNeedCdata) {
//判断结点是否需要 CDATA 片段
//CDATA 片段:在 XML 中,CDATA 可以直接包含未经转义的文本。比如 < 和 &,只要位于 CDATA 片段中,它们就不需要被转义,保持原样就可以了
element.appendChild(doc.createCDATASection(node.getValue()));
} else if (StringUtils.hasText(node.getValue())){
element.setTextContent(node.getValue());
}
if (Objects.nonNull(node.getAttributeList())) {
//设置结点的属性值
for (Attribute attribute : node.getAttributeList()) {
element.setAttribute(attribute.getName(), attribute.getValue());
}
} else if (Objects.nonNull(node.getChildrenList())) {
//如果该结点有子节点,则添加子节点的值
for (Node child : node.getChildrenList()) {
Element childElement = getChildrenNode(child,doc);
//判断是否还有子节点
if (!CollectionUtils.isEmpty(child.getChildrenList())) {
for (Node childrenNode : child.getChildrenList()) {
Element childrenElement = getChildrenNode(childrenNode,doc);
childElement.appendChild(childrenElement);
}
}
//添加子节点
element.appendChild(childElement);
}
}
//将结点添加到根结点下
rootElement.appendChild(element);
}
Transformer transformer = TransformerFactory.newInstance().newTransformer();
//去除XML头部声明(<?xml version="1.0" encoding="UTF-8" standalone="no"?>)
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
//启用缩进
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//指定了缩进量,可以将 "2" 替换成其他值,如 "4" 或 "tab" 等
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
// 设置字符编码
transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
// 将新的Document对象转换为字符串输出
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
return writer.toString().trim();
} catch (Exception e) {
log.error("构造XML异常{}",e.getMessage());
}
return "";
}
/**
* 构造子节点
*/
private static Element getChildrenNode(Node child, Document doc){
Element childElement = doc.createElement(child.getName());
if (child.isNeedCdata) {
childElement.appendChild(doc.createCDATASection(child.getValue()));
} else if (StringUtils.hasText(child.getValue())){
childElement.setTextContent(child.getValue());
}
//设置子结点的属性值
if (Objects.nonNull(child.getAttributeList())) {
for (Attribute attribute : child.getAttributeList()) {
childElement.setAttribute(attribute.getName(), attribute.getValue());
}
}
return childElement;
}
/**
* 节点类
*/
@Data
@AllArgsConstructor
public static class Node {
/**结点名称*/
private final String name;
/**结点值*/
private final String value;
/**结点属性*/
private final List<Attribute> attributeList;
/**结点的子节点*/
private final List<Node> childrenList;
/**结点是否需要 CDATA 片段*/
private boolean isNeedCdata;
}
/**
* 属性类
*/
@Data
@AllArgsConstructor
public static class Attribute {
/**属性名称*/
private final String name;
/**属性值*/
private final String value;
}
}
测试代码
public static void main(String[] args) throws Exception {
List<Node> nodeList = new ArrayList<>();
nodeList.add(new Node("ToUserName", "ToUserName", null,null,true));
nodeList.add(new Node("FromUserName", "FromUserName", null,null,true));
nodeList.add(new Node("CreateTime", "CreateTime", null,null,false));
nodeList.add(new Node("MsgType", "MsgType", null,null,true));
List<Node> childNodes = new ArrayList<>();
childNodes.add(new Node("CardType","CardType",null,null,true));
childNodes.add(new Node("MainTitle",null,null,List.of(new Node("Title","MainTitle",null,null,true)),false));
childNodes.add(new Node("SubTitleText","SubTitleText",null,null,true));
List<Node> button_1 = new ArrayList<>();
button_1.add(new Node("Text","button_1",null,null,true));
button_1.add(new Node("Style","1",null,null,false));
button_1.add(new Node("Key","button_key_1",null,null,true));
childNodes.add(new Node("ButtonList",null,null,button_1,false));
childNodes.add(new Node("ReplaceText","已提交",null,null,true));
nodeList.add(new Node("TemplateCard", null, null,childNodes,false));
System.out.println(build("xml", nodeList));
}