避免为空元素生成 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,所有属性都将被忽略

Michael Kay(https://stackoverflow.com/users/415448/michael-kay)在处理xml文件(Java)中清楚地说了这一点:

除非变压器正在产生,否则调用Transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");不起作用 序列化输出。在您的情况下,变压器没有产生 序列化输出,因为您要将输出发送到 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 标签,但我也有来自转换器的默认标签:

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

最后,我重试删除了转换器默认标签:

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 文件,因为它可能非常大。

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

提前感谢您的帮助。

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

您的主要问题似乎是您想避免使用自关闭标签,但这毫无意义,因为自闭合标签在语义上与一对开始/结束标签相同。我认为唯一的解决方法是使用 XSLT,在其中,您可以通过添加一些不会在两者之间产生任何输出的内容来诱骗处理器编写开始和结束标记。但这大概也取决于您的处理器。最后,您正在尝试将XML发送到无法理解XML的系统,因此您将始终不得不诉诸黑客攻击。

如果要避免使用 XML 自闭合标记,可以使用

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

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

因此,如果"test"变量为空,则生成的XML消息将如下所示:

<TEST></TEST>

而不是:

<TEST/>

最新更新