如何使用 Jackson XmlMapper 控制编码?
How to control encoding with Jackson XmlMapper?
我找不到一种(明显的)方法来将序列化 XML 的编码从默认的 UTF-8
更改为 ISO-8859-1
。我读了 Usage Guide,这让我认为必须有一种方法使用 XMLOutputFactory
和 XmlFactory
来实现这一点,但我看不到配置任何这些工厂的方法默认使用另一种编码,只有 createXMLEventWriter
可以传入编码。
我知道如何使用 ToXmlGenerator.Feature.WRITE_XML_DECLARATION
生成 XML 声明。所以我需要的是这样的声明:
<?xml version='1.0' encoding='ISO-8859-1'?>
当然,内容也应该用 ISO-8859-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;
}
曾经 ToXmlGenerator
is final
there might not be an easy way to handle it. I've submitted an issue in the 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。
我找到的解决方案是使用自定义 Jackson api 和 Writer 以及您想要的编码,然后自己打印 xml 声明。
你必须使用 Writer 包装器,因为 Jackson 使用反射(我认为它确实如此)来找出你使用的是哪种类型的 writer 以及它的编码是什么,并根据它(是否不是 UTF-8)执行 XML 超过 127 个字符的实体编码。如果您对 XML 实体编码感到满意,则可以跳过包装器。
如果你使用 Jackson 的
mapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
您 运行 有创建无效 XML 的风险,具体取决于您的本地环境。 Jackson 将始终在 xml 声明中打印 UTF-8,如果您提供非 utf-8 编码的流(并且某些编写器构造函数不允许您指定编码并使用平台默认值 - 这可能会在平台之间发生变化),您可以获得文档的 body 编码方式不同于 xml 声明 header 让您相信。
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);
我找不到一种(明显的)方法来将序列化 XML 的编码从默认的 UTF-8
更改为 ISO-8859-1
。我读了 Usage Guide,这让我认为必须有一种方法使用 XMLOutputFactory
和 XmlFactory
来实现这一点,但我看不到配置任何这些工厂的方法默认使用另一种编码,只有 createXMLEventWriter
可以传入编码。
我知道如何使用 ToXmlGenerator.Feature.WRITE_XML_DECLARATION
生成 XML 声明。所以我需要的是这样的声明:
<?xml version='1.0' encoding='ISO-8859-1'?>
当然,内容也应该用 ISO-8859-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;
}
曾经 ToXmlGenerator
is final
there might not be an easy way to handle it. I've submitted an issue in the 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。
我找到的解决方案是使用自定义 Jackson api 和 Writer 以及您想要的编码,然后自己打印 xml 声明。
你必须使用 Writer 包装器,因为 Jackson 使用反射(我认为它确实如此)来找出你使用的是哪种类型的 writer 以及它的编码是什么,并根据它(是否不是 UTF-8)执行 XML 超过 127 个字符的实体编码。如果您对 XML 实体编码感到满意,则可以跳过包装器。
如果你使用 Jackson 的
mapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
您 运行 有创建无效 XML 的风险,具体取决于您的本地环境。 Jackson 将始终在 xml 声明中打印 UTF-8,如果您提供非 utf-8 编码的流(并且某些编写器构造函数不允许您指定编码并使用平台默认值 - 这可能会在平台之间发生变化),您可以获得文档的 body 编码方式不同于 xml 声明 header 让您相信。
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);