Gambler_Tu 2023-11-20 17:50 采纳率: 50%
浏览 17
已结题

document转字符串时缺少一半的标签

问题:下述代码在本地和测试运行输出的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");
  • 写回答

12条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2023-11-20 17:50
    关注

    引自强大而免费的微信小程序:皆我百晓生

    问题可能出在以下代码段中:

    if (fieldValue != null) {
        if (xmlElement.index() != 0) {
            element.setTextContent(fieldValue.toString());
            element.appendChild(document.createTextNode(""));
        }
    }
    

    在这里,如果字段的值不为null,将字段的值设置为元素的文本内容,然后添加一个空的文本节点。然而,并没有为字段的值添加结束标签。这可能导致部分标签没有完全闭合。

    你可以尝试修改上述代码段,使用element.setTextContent(fieldValue.toString() + "")来为字段的值添加结束标签。这样可以确保所有的标签都完整闭合。

    修改后的代码如下:

    if (fieldValue != null) {
        if (xmlElement.index() != 0) {
            element.setTextContent(fieldValue.toString() + "");
        }
    }
    

    然后重新运行代码,观察输出的XML字符串是否完整。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 11月22日
  • 修改了问题 11月21日
  • 修改了问题 11月21日
  • 创建了问题 11月20日