LSSerializer не должен создавать ссылки на символы - PullRequest
0 голосов
/ 30 сентября 2019

Мое приложение использует 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...