有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java避免为空元素生成XML自关闭标记,并生成自定义的<XML>开始标记

我需要生成一个XML文件,其中包含一些数据,以便发送到我手上没有的第三方系统(由另一家公司制造,我无法修改或要求修改)

另一个系统不接受我生成的文档,因为它有一些空元素的自动关闭标记:<tag/>而不是<tag></tag>

我现在的代码就是这样的

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
StreamResult streamResult = new StreamResult(file);
transformer.transform(source, streamResult);

为了生成完整的结束标记,我尝试要求Transformer使用html输出方法:

transformer.setOutputProperty(OutputKeys.METHOD, "html");

来源:http://makble.com/the-self-closing-tag-problem-of-javaxxmltransform-package-dom-to-source

这适用于具有完整的结束标记,但我还有其他问题:

  • 未生成XML文档起始标记(如<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
  • 特殊字符是以HTML方式生成的(比如&eacute;而不是é

所以我发现我可以用StAXResult代替StreamResult这样:

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        XMLStreamWriter writer = XMLOutputFactory.newFactory().createXMLStreamWriter(new BufferedWriter(new FileWriter(nomFichier)));
        StAXResult streamResult = new StAXResult(writer);
        transformer.transform(source, streamResult);

这也适用于在空元素上有完整的结束标记,但我的XML文档开始标记不完整:

<?xml version="1.0"?>

如果我尝试使用转换器的输出属性来定义它,这将不起作用:

        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.VERSION, "1.0");
        transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
        transformer.setOutputProperty(OutputKeys.STANDALONE, "no");

由于使用了StAXResult,所有属性都被忽略

迈克尔·凯(https://stackoverflow.com/users/415448/michael-kay)在Processing xml file (Java)中明确指出了这一点:

The call Transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); has no effect unless the transformer is producing serialized output. In your case the transformer is not producing serialized output because you are sending the output to a StAXResult

我尝试将XMLStreamWriter配置为至少定义编码:

        XMLStreamWriter writer = XMLOutputFactory.newFactory().createXMLStreamWriter(new BufferedWriter(new FileWriter(nomFichier)));
        writer.writeStartDocument("ISO-8859-1", "1.0");
        StAXResult streamResult = new StAXResult(writer);
        transformer.transform(source, streamResult);

这将导致添加“正确”的起始XML标记,但我还有来自Transformer的默认标记:

<?xml version="1.0" encoding="ISO-8859-1"?><?xml version="1.0"?>

最后,我尝试删除Transformer默认标记:

        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

但正如前面所说的,这不起作用,因为变压器的输出属性被忽略了

关于如何实现这两个目标有什么想法吗

  • 有效的XML起始标记(<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
  • 正确的字符编码(é和非&eacute;
  • 元素为空时的完全结束标记(<tag></tag>而不是<tag/>

我看到的唯一方法是使用XMLStreamWriterStAXResult编写文档,然后处理生成的文件以对其进行解析,删除<?xml version="1.0"?>元素,并用硬编码的<?xml version="1.0" encoding="ISO-8859-1"?>字符串替换它,但我并不想仅仅因为它可能很大而解析生成的XML文件

我正在寻找一个更优雅的解决方案

提前感谢你的帮助


共 (2) 个答案

  1. # 1 楼答案

    如果要创建文件,为什么要使用StAXResult?正如您在回答中提到的,您正在将一个树结构转换为另一个树结构。XML永远不会序列化,因此不会考虑序列化设置

    您的主要问题似乎是希望避免使用自动关闭标记,但这毫无意义,因为自动关闭标记在语义上与一对打开/关闭标记相同。我认为唯一的解决方法是使用XSLT,在XSLT中,通过添加一些不会在中间产生任何输出的内容,欺骗处理器编写开始和结束标记。但这可能也取决于你的处理器。最后,您试图将XML发送到一个无法理解XML的系统,因此您将不得不求助于黑客

  2. # 2 楼答案

    如果希望避免使用XML自动关闭标记,可以使用

    @JsonProperty(value = "TEST")
    @JsonSerializer(nullsUsing = NullSerializer.class)
    private String test;
    

    NullSerializer:它将是一个从JsonSerializer扩展而来的类,并将返回null

    因此,如果“test”变量为null,则生成的XML消息如下所示:

    <TEST></TEST>
    

    而不是:

    <TEST/>