Подтвердить что ты не робот

Transformer.setOutputProperty(OutputKeys.ENCODING, "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"?>...

Как вы можете ясно видеть, я устанавливаю выходной ключ ENCODING в UTF-8. Эти тесты использовались для более ранней версии Java. Я не запускал тесты через некоторое время (более года), но работает сегодня в среде Java Runtime Environment (build 1.6.0_22-b04) "Я получаю это смешное поведение.

Я проверил, что документы, вызывающие проблему, были прочитаны из файлов, которые первоначально имели такую ​​кодировку. Кажется, что новые версии библиотек пытаются сохранить кодировку исходного файла, который был прочитан. Но это не то, что я хочу... Я действительно хочу, чтобы выход был в UTF-8.

Кто-нибудь знает какой-либо другой фактор, который может заставить трансформатор игнорировать настройку кодировки UTF-8? Есть ли что-то еще, что должно быть установлено в документе, чтобы сказать, чтобы забыть кодировку файла, который был первоначально прочитан?

UPDATE:

Я проверил один и тот же проект на другой машине, построил и проверил тесты там. На этой машине проходят все тесты! Все файлы имеют "UTF-8" в заголовке. У этой машины есть "среда выполнения Java (TM) SE Runtime Environment (сборка 1.6.0_29-b11)". Обе машины работают под управлением Windows 7. На новом компьютере, который работает правильно, jdk1.5.0_11 используется для создания сборки, но на старой машина jdk1.6.0_26 используется для создания сборки. Библиотеки, используемые для обеих сборников, абсолютно одинаковы. Может ли это быть несовместимостью JDK 1.6 с 1.5 во время сборки?

UPDATE:

Через 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 в выходной поток. Хромой, но он дает правильные результаты. Тесты, разбитые более 4 лет назад, теперь снова запущены!

4b9b3361

Ответ 1

У меня была такая же проблема на Android, когда вы сериализуете символы эмози. При использовании кодировки 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"));

Ответ 2

Чтобы ответить на вопрос, следующий код работает для меня. Это может принимать входные кодировки и преобразовывать данные в выходное кодирование.

        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);

Ответ 3

Я потратил значительное количество времени на отладку этой проблемы, потому что она хорошо работала на моей машине (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)

Ответ 4

что??

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

Ответ 5

Я мог бы обойти проблему, обернув объект Document, переданный конструктору DOMSource. Метод getXmlEncoding моей оболочки всегда возвращает значение null, все другие методы делегируются обернутому объекту Document.

Ответ 6

Я делаю здесь дикий выстрел, но вы говорите, что вы читаете файлы для данных тестов. Можете ли вы убедиться, что вы читаете файлы с использованием правильной кодировки, поэтому, когда вы записываете в свой OutputStream, у вас уже есть данные в правильной кодировке?

Итак, есть что-то вроде нового InputStreamReader (новый FileInputStream (fileDir), "UTF8" ).

Не забывайте, что конструкторы с одним аргументом FileReader всегда используют кодировку по умолчанию для платформы: Конструкторы этого класса предполагают, что кодировка по умолчанию и значение по умолчанию размер байтового буфера соответствует.

Ответ 7

Попробуйте настроить кодировку в StreamResult специально:

StreamResult result = new StreamResult(new OutputStreamWriter(out, "UTF-8"));

Таким образом, он должен иметь возможность записывать только в UTF-8.