如何使用Jackson XmlMapper控制编码?

时间:2018-10-12 11:01:44

标签: xml jackson jackson-dataformat-xml

我找不到将序列化XML的编码从默认的UTF-8更改为ISO-8859-1的(很明显的)方法。我读了Usage Guide,这使我认为必须将XMLOutputFactoryXmlFactory结合使用才能实现此目的,但是我看不到将任何这些工厂配置为默认情况下使用其他编码,只有createXMLEventWriter可以传递编码。

我知道如何使用ToXmlGenerator.Feature.WRITE_XML_DECLARATION来生成XML声明。所以我需要的是这样的声明:

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

当然,内容也应该用ISO-8859-1编码。

2 个答案:

答案 0 :(得分:1)

ToXmlGenerator source code中,您会发现UTF-8是硬编码的:

if (Feature.WRITE_XML_1_1.enabledIn(_formatFeatures)) {
    _xmlWriter.writeStartDocument("UTF-8", "1.1");
} else if (Feature.WRITE_XML_DECLARATION.enabledIn(_formatFeatures)) {
    _xmlWriter.writeStartDocument("UTF-8", "1.0");
} else {
    return;
}

一旦ToXmlGeneratorfinal,可能就没有简单的处理方法。我已经在issue项目中提交了jackson-dataformat-xml


如果坚持使用JAXB,则可以使用Marshaller.JAXB_ENCODING控制encoding属性的值:

Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "ISO-8859-1");
marshaller.marshal(foo, System.out);

请参阅此answer

答案 1 :(得分:1)

我发现的解决方案是将Writer的自定义Jackson api与所需的编码一起使用,并自行打印xml声明。

您必须使用Writer包装器,因为Jackson使用反射(我认为确实如此)来找出您使用的是哪种类型的书写器以及其编码是什么,并依赖于反射(是否不是UTF-8)执行XML实体编码超过127个字符。如果您对XML实体编码感到满意,则可以跳过包装器。

如果您使用杰克逊的

mapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);

您会冒着根据本地环境创建无效XML的风险。杰克逊将始终在xml声明中打印UTF-8,如果您提供具有非utf-8编码的流(并且某些编写器构造函数不允许您指定编码并使用平台默认值-平台之间可能会有所不同),则可以用不同于xml声明标头的方式编码的文档正文会让您相信。

String fileName = "/tmp/file.xml";
String encoding = "ISO-8859-1";
Writer output = new OutputStreamWriter(new FileOutputStream(fileName), encoding);

output.write("<?xml version=\"1.0\" encoding=\"" + encoding + "\" ?>\n");
mapper.writer().writeValue(new Writer(output) {
    @Override
    public void write(char[] var1, int var2, int var3) throws IOException {
        output.write(var1, var2, var3);
    }

    @Override
    public void flush() throws IOException {
        output.flush();
    }

    @Override
    public void close() throws IOException {
        output.close();
    }

}, value);