Мое приложение использует Java 8 и обрабатывает файлы XML. Внутри файлы хранятся в формате org.w3c.dom.Document
. Это делает довольно трудным переключение на библиотеку, которая использует другие классы XML. Большинство входных файлов кодируются в UTF-8, и в большинстве из них также есть несколько широких символов (например, эмодзи). Во входных файлах эти широкие символы отображаются как есть. Снова используя пример с эмодзи, я могу открыть свой входной XML-файл и увидеть там смайлики. Это поведение, которое я хочу. Разбор файлов в Document
через DocumentBuilder
также работает нормально. Я проверил getTextContent
для узла с такими символами, что они все еще появляются в этой форме.
Однако сериализация этого Document
обратно в массив байтов и более поздние файлы не работает должным образом. Широкие символы заменяются ссылками на символы. Эти ссылки на самом деле недопустимы (см. Сериализация дополнительных символов Юникода в документы XML с Java ). Но это не проблема, с которой я сталкиваюсь. Кроме того, есть еще один вопрос о SO, который я не могу найти в данный момент, который касался сериализатора, записывающего неверную кодировку в преамбулу. Это также не влияет на меня. Что я действительно хочу, так это то, что широкие символы не заменяются ссылками на символы, просто хранятся как байты UTF-8. Javadoc для LSSerializer
говорит:
В символьных данных документа (вне разметки) любые символы, которые не могут быть представлены непосредственно, заменяются ссылками на символы.
Пожалуйста, исправьте меня, если я ошибаюсь, но эти символы должны быть непосредственно представлены в кодировке UTF-8. Это код, который я использую:
public void serializeXml(Document doc, OutputStream os) {
DOMImplementationRegistry reg = DOMImplementationRegistry.newInstance();
DOMImplementationLS impl = (DOMImplementationLS) reg.getDOMImplementation("LS");
LSSerializer ser = impl.createLSSerializer();
LSOutput out = impl.createLSOutput();
out.setEncoding(doc.getXmlEncoding() /* "UTF-16" */);
out.setNewLine("\n");
out.setByteStream(os);
ser.write(doc, out);
}
И это версия с Transformer
, которая, к сожалению, ведет себя так же.
public void serializeXml(Document doc, OutputStream os) {
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.METHOD, "xml");
t.setOutputProperty(OutputKeys.ENCODING, doc.getXmlEncoding() /* "UTF-16" */);
t.transform(new DOMSource(doc), new StreamResult(os));
}
Установка выходной кодировки на UTF-16
Обходной путь. В этой кодировке символы отображаются так, как я хочу. Тем не менее, поскольку приложение довольно часто перетасовывает данные, в том числе и по сети, я бы очень предпочел использовать UTF-8, когда это имеет смысл (от широких символов до нуля), и использовать UTF-16, когда входной файл вуже закодированы как таковые, чтобы сохранить несколько байтов. Есть ли известное решение для достижения этой цели?
PS: В другом проекте я могу использовать JAXB. Распределение одинаковых документов отлично работает даже с UTF-8.
Редактировать: Запись файла довольно проста и не является преступником. Один пример будет выглядеть так:
Files.write(Paths.get(filename), os.toByteArray());
, где os
- это OutputStream
, записанный в приведенном выше коде.
Этот пример должен производить описанное поведение.
<Attributes>
<Map>
<entry key="name" value="?test?"/>
</Map>
</Attributes>