трансформатор.setOutputProperty(OutputKeys.Кодировка, "UTF-8") не работает
у меня есть следующий метод для записи XMLDom в поток:
public void writeToOutputStream(Document fDoc, OutputStream out) throws Exception {
fDoc.setXmlStandalone(true);
DOMSource docSource = new DOMSource(fDoc);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.transform(docSource, new StreamResult(out));
}
я тестирую некоторые другие функции XML, и это только метод, который я использую для записи в файл. Моя тестовая программа генерирует 33 тестовых случая, в которых файлы записываются. 28 из них имеют следующий заголовок:
<?xml version="1.0" encoding="UTF-8"?>...
но по какой-то причине 1 из тестовых случаев теперь производит:
<?xml version="1.0" encoding="ISO-8859-1"?>...
и еще четыре производят:
<?xml version="1.0" encoding="Windows-1252"?>...
как вы можете ясно видеть, я установка выходного ключа кодирования в UTF-8. Эти тесты использовались для работы на более ранней версии Java. Я не запускал тесты некоторое время(более года), но сегодня работает на "Java (TM) SE Runtime Environment (build 1.6.0_22-b04)", я получаю это забавное поведение.
Я проверил, что документы, вызывающие проблему, были прочитаны из файлов, которые первоначально имели эту кодировку. Похоже, что новые версии библиотек пытаются сохранить кодировку исходного файла, был прочитан. Но это не то, чего я хочу ... Я действительно хочу, чтобы выход был в UTF-8.
кто-нибудь знает о каком-либо другом факторе, который может заставить трансформатор игнорировать настройку кодировки UTF-8? Есть ли что-то еще, что должно быть установлено в документе, чтобы сказать, чтобы забыть кодировку файла, который был первоначально прочитан?
обновление:
Я проверил тот же проект на другой машине, построил и провел там тесты. На этой машине все тесты проходят! Все файлы имеют "UTF-8" в заголовке. Эта машина имеет" Java(TM) SE Runtime Environment (build 1.6.0_29-b11) " обе машины работают под управлением Windows 7. На новой машине, которая работает правильно, jdk1.5.0_11 используется для создания сборки, но на старой машине jdk1.6.0_26 используется для создания сборки. Библиотеки, используемые для обеих сборок, абсолютно одинаковы. Может ли это быть несовместимость JDK 1.6 с 1.5 во время сборки?
обновление:
после 4,5 лет, Java библиотека все еще сломана, но из-за предложения Vyrx ниже, у меня, наконец, есть правильное решение!
public void writeToOutputStream(Document fDoc, OutputStream out) throws Exception {
fDoc.setXmlStandalone(true);
DOMSource docSource = new DOMSource(fDoc);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
out.write("<?xml version="1.0" encoding="UTF-8"?>".getBytes("UTF-8"));
transformer.transform(docSource, new StreamResult(out));
}
решение состоит в том, чтобы отключить запись заголовка и написать правильный заголовок непосредственно перед сериализацией XML в выходной steam. Хромает, но дает правильные результаты. Тесты, сломанные более 4 лет назад, теперь снова работают!
7 ответов
У меня была такая же проблема на Android при сериализации символов emoji. При использовании кодировки UTF-8 в трансформаторе выходными были HTML-символьные сущности (суррогатные пары UTF-16), которые впоследствии нарушали другие Парсеры, считывающие данные.
вот как я закончил его решение:
StringWriter sw = new StringWriter();
sw.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
Transformer t = TransformerFactory.newInstance().newTransformer();
// this will work because we are creating a Java string, not writing to an output
t.setOutputProperty(OutputKeys.ENCODING, "UTF-16");
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.transform(new DOMSource(elementNode), new StreamResult(sw));
return IOUtils.toInputStream(sw.toString(), Charset.forName("UTF-8"));
чтобы ответить на вопрос, следующий код работает для меня. Это может принять кодировку входного сигнала и преобразовать данные в кодировку выхода.
ByteArrayInputStream inStreamXMLElement = new ByteArrayInputStream(strXMLElement.getBytes(input_encoding));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document docRepeat = db.parse(new InputSource(new InputStreamReader(inStreamXMLElement, input_encoding)));
Node elementNode = docRepeat.getElementsByTagName(strRepeat).item(0);
TransformerFactory tFactory = null;
Transformer transformer = null;
DOMSource domSourceRepeat = new DOMSource(elementNode);
tFactory = TransformerFactory.newInstance();
transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, output_encoding);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
StreamResult sr = new StreamResult(new OutputStreamWriter(bos, output_encoding));
transformer.transform(domSourceRepeat, sr);
byte[] outputBytes = bos.toByteArray();
strRepeatString = new String(outputBytes, output_encoding);
Я потратил значительное количество времени на отладку этой проблемы, потому что она хорошо работала на моей машине (Ubuntu 14 + Java 1.8.0_45), но не работала должным образом в производстве (Alpine Linux + Java 1.7).
вопреки моим ожиданиям, следующий из вышеупомянутого ответа не помог.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
StreamResult sr = new StreamResult(new OutputStreamWriter(bos, "UTF-8"));
но этот работал, как ожидалось
val out = new StringWriter()
val result = new StreamResult(out)
о чем?:
public static String documentToString(Document doc) throws Exception{ return(documentToString(doc,"UTF-8")); }//
public static String documentToString(Document doc, String encoding) throws Exception{
TransformerFactory transformerFactory =TransformerFactory.newInstance();
Transformer transformer = null;
if ( "".equals(validateNullString(encoding) ) ) encoding = "UTF-8";
try{
transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes") ;
transformer.setOutputProperty(OutputKeys.ENCODING, encoding) ;
}catch (javax.xml.transform.TransformerConfigurationException error){
return null;
}
Source source = new DOMSource(doc);
StringWriter writer = new StringWriter();
Result result = new StreamResult(writer);
try{
transformer.transform(source,result);
}catch (javax.xml.transform.TransformerException error){
return null;
}
return writer.toString();
}//documentToString
Я мог бы обойти проблему, обернув объект документа, переданный конструктору DOMSource. Метод getXmlEncoding моей оболочки всегда возвращает null, все остальные методы делегируются объекту обернутого документа.
Я делаю дикий выстрел здесь, но вы упоминаете, что читаете файлы для данных тестов. Можете ли вы убедиться, что Вы читаете файлы, используя правильную кодировку, чтобы при записи в OutputStream у вас уже были данные в правильной кодировке?
Итак, что-то вроде new InputStreamReader(новый FileInputStream(fileDir), "UTF8").
Не забывайте, что одно аргументные конструкторы FileReader всегда используют кодировку платформы по умолчанию : конструкторы этого класса предполагают, что кодировка по умолчанию и Байт размер буфера по умолчанию являются подходящими.
попробуйте установить кодировку на вашем StreamResult конкретно:
StreamResult result = new StreamResult(new OutputStreamWriter(out, "UTF-8"));
таким образом, он должен иметь возможность писать только в UTF-8.