问题:下述代码在本地和测试运行输出的XML类型的字符串内容有区别,目前感觉是 document转成字符串的时候有什没有设置,或者缺少方法没有调用。
// 调用代码
XmlStringConverter xmlStringConverter = new XmlStringConverter();
Document document = xmlStringConverter.toXmlSerial(requestBody);
String xmlData = xmlStringConverter.getXMLStringByDocument(document);
//实体类 FOX是根元素 name 是当前变量要生成的标签名称。parentName 是父标签名称 index为0的代表设置子元素,
@XmlElementLocation(name = "SIGNONMSGSRQV1",parentName = "FOX",index = 0 )
private String signonmsgsrqv1;
@XmlElementLocation(name = "SONRQ",parentName = "SIGNONMSGSRQV1",index = 0 )
private String sonrq;
/**
* 客户端日期时间,YYYY-MM-DD_HH:MM:SS 必输
*/
@XmlElementLocation(name = "DTCLIENT",parentName = "SONRQ",index =1 )
private String dtClient;
/**
* 企业网银客户号,10位数字 必输
*/
@XmlElementLocation(name = "CID",parentName = "SONRQ",index = 2)
private String cid;
package com.zc.ms.api.xingye;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.Objects;
/**
* @Author TuYinHu
* @Date 2023/10/25 11:06
* @description: XML对象和String对象相互转换
* @Title: XmlStringConverter
*/
@Slf4j
public class XmlStringConverter {
/**
* 序列化javabean对象
*
* @param requestBody
* @param <T>
* @return
*/
public <T> Document toXmlSerial(T requestBody) {
try {
// 创建文档对象
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
document.setXmlStandalone(true);
// 创建根元素<FOX>
Element foxElement = document.createElement("FOX");
document.appendChild(foxElement);
// 使用反射获取Java对象的属性名称和值,并将它们转换为XML子元素
generateXml(requestBody, document, foxElement);
return document;
} catch (ParserConfigurationException | IllegalAccessException | IllegalArgumentException e) {
log.error("请求内容XML拼接转换异常{}", e);
throw new RuntimeException("请求内容XML拼接转换异常");
}
}
public <T> void generateXml(T entity, Document document, Element rootElement) throws IllegalAccessException {
Field[] childFields = entity.getClass().getDeclaredFields();
for (Field field : childFields) {
field.setAccessible(true);
//实体类注解
XmlElementLocation xmlElement = field.getAnnotation(XmlElementLocation.class);
if (Objects.equals("FOX", xmlElement.parentName())) {
Element element = document.createElement(xmlElement.name());
rootElement.appendChild(element);
} else {
// 获取父级元素
Element parent = getParentElementByName(rootElement, xmlElement.parentName());
if (parent == null) {
//父元素不存在,创建父元素,将自己添加到父元素,并将父元素添加到根元素
parent = document.createElement(xmlElement.parentName());
rootElement.appendChild(parent);
}
//检查子元素是否生成过自己
Element element = getParentElementByName(rootElement, xmlElement.name());
if(element == null){
element = document.createElement(xmlElement.name());
}
Object fieldValue = field.get(entity);
if (fieldValue != null) {
if (xmlElement.index() != 0) {
element.setTextContent(fieldValue.toString());
element.appendChild(document.createTextNode(""));
}
}
parent.appendChild(element);
}
}
}
/**
* rootElement
*
* @param name
* @return
*/
private Element getParentElementByName(Element rootElement, String name) {
NodeList nodeList = rootElement.getElementsByTagName(name);
if (nodeList.getLength() > 0) {
return (Element) nodeList.item(0);
} else {
return null;
}
}
/**
* 将文档对象转换为XML字符串
*
* @param document
* @return
* @throws TransformerException
*/
public String getXMLStringByDocument(Document document) {
try {
// 将文档对象转换为XML字符串
Transformer transformer = TransformerFactory.newInstance().newTransformer();
//会包含 XML 声明(例如 <?xml version="1.0" encoding="UTF-8"?>)
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");
//使用标准的 XML 方法生成 XML 字符串
transformer.setOutputProperty(OutputKeys.METHOD,"xml");
// 版本
transformer.setOutputProperty(OutputKeys.VERSION,"1.0");
//设置输出的编码
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//行缩进排版
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}line-separator", "\n");
DOMSource source = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
log.info("writer=={}==",writer.toString());
// 获取转换后的字符串
String xmlString = writer.toString();
//观察两种的输出,发现没有区别
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
StreamResult result2 = new StreamResult(byteArrayOutputStream);
transformer.transform(source, result2);
log.info("byteArrayOutputStream=={}==",byteArrayOutputStream.toString());
return xmlString;
} catch (TransformerException e) {
log.error("文档对象转换为XML字符串异常{}", e.getMessage());
throw new RuntimeException("文档对象转换为XML字符串异常");
}
}
}
windows idea log输出:
17:37:47.275 nacos [http-nio-30013-exec-1] INFO c.z.ms.api.xingye.XmlStringConverter - writer==<?xml version="1.0" encoding="UTF-8"?><FOX>
<SIGNONMSGSRQV1>
<SONRQ>
<DTCLIENT>2023-11-15 14:00:56</DTCLIENT>
<CID>123</CID>
<USERID>user</USERID>
<USERPASS>123</USERPASS>
<GENUSERKEY>N</GENUSERKEY>
<LANGUAGE>ZH_CN</LANGUAGE>
<APPID>XYFIB</APPID>
<APPVER>1000</APPVER>
</SONRQ>
</SIGNONMSGSRQV1>
<SECURITIES_MSGSRQV1>
```省略 都正常
</SECURITIES_MSGSRQV1>
</FOX>
==
17:37:47.276 nacos [http-nio-30013-exec-1] INFO c.z.ms.api.xingye.XmlStringConverter - byteArrayOutputStream 同上
线上 linux 输出
17:39:13.277 nacos [http-nio-30013-exec-6] INFO c.z.ms.api.xingye.XmlStringConverter - writer==<?xml version="1.0" encoding="UTF-8"?>
<SIGNONMSGSRQV1>
<SONRQ>
<DTCLIENT>2023-11-15 14:00:56
<CID>123
<USERID>user
<USERPASS>123
<GENUSERKEY>N
<LANGUAGE>ZH_CN
<APPID>XYFIB
<APPVER>1000
</SONRQ>
二者区别 linux 缺少头,有数值的参数缺少结尾标签
在设置下面的缩进后才有标签头,之前线上的日志只有一个+数值,没有标签。
//行缩进排版
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
linux日志如下
09:28:03.257 nacos [http-nio-30013-exec-2] INFO c.z.ms.api.xingye.XmlStringConverter - writer
==<?xml version="1.0" encoding="UTF-8"?>2023-11-15 14:00:56user yqtes 123 NZH_CNXYFIB10001700530083562test1170101001007338661111111批量开户10010000000.00.02016-10-253D002016-10-250000==
然后我在generateXml方法中显示添加一个空节点,解析器在处理这些元素时,就会认为它们不是空的。没效果。
element.appendChild(document.createTextNode(""));
目前给出的方案如下,目前都是无效:
element.setTextContent(fieldValue.toString() + "");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}line-separator", System.getProperty("line.separator"));
//这个调整和注释相同,都会导致输出只有字符串没有标签
transformer.setOutputProperty(OutputKeys.INDENT, "2");