Как я могу заставить XSLT возвращать UTF-8 в Java

Я пытаюсь заставить свой XSL-скрипт работать с кодировкой UTF-8. Такие иероглифы, как åäö и греческие иероглифы, просто появляются как мусор. Единственный способ заставить его работать - записать результат в файл. Если я пишу его в выходной поток, он возвращает только мусор (System.out работает, но это может быть потому, что он перенаправляется в файл).

Результат должен быть возвращен сервлетом, и обратите внимание, что это не проблема конфигурации сервлета. Я могу вернуть жестко закодированную строку с греческими символами из сервлета, и она работает нормально, так что это проблема с преобразованием.

Вот мой текущий (упрощенный) код.

protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException,
IOException {
    try {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");

        final TransformerFactory factory = this.getFactory();

        final File inFile = new File("infile.xml");
        final File xslFile = new File("template.xsl");
        final File outFile = new File("outfile.html");

        final Templates templates = factory.newTemplates(new StreamSource(xslFile));
        final Transformer transformer = templates.newTransformer();
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

        final InputStream in = new FileInputStream(inFile);
        final StreamSource source = new StreamSource(in);

        final StreamResult result1 = new StreamResult(outFile);
        final StreamResult result2 = new StreamResult(System.out);
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final StreamResult result3 = new StreamResult(out);

        //transformer.transform(source, result1);
        //transformer.transform(source, result2);
        transformer.transform(source, result3);

        final Writer writer = response.getWriter();
        writer.write(new String(out.toByteArray()));
        writer.close();
        in.close();

    } catch (final TransformerConfigurationException e) {
        e.printStackTrace();
    } catch (final TransformerException e) {
        e.printStackTrace();
    }
}

Кроме того, мой XSL-скрипт содержит следующее

<xsl:output method="html" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

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


person Johan    schedule 20.11.2012    source источник


Ответы (1)


Почти наверняка проблема в этом:

writer.write(new String(out.toByteArray()));

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

Если вы все равно собираетесь писать Writer, почему вы начинаете писать ByteArrayOutputStream? Почему бы не пойти прямо к Writer?

Однако было бы лучше писать прямо в выходной поток ответа (response.getOutputStream()), а также установить тип содержимого ответа, чтобы указать, что это UTF-8.

Обратите внимание: если вы действительно хотите заранее получить результат в виде String, используйте StringWriter. Нет смысла писать в ByteArrayOutputStream, а затем преобразовывать в строку.

person Jon Skeet    schedule 20.11.2012
comment
Спасибо, вы указали мне правильное направление. Я только что обнаружил, что у ByteArrayOutputStream был метод out.toString("UTF-8"), поэтому после этого он работал. Я не могу использовать поток ответов сразу, так как у меня есть еще кое-что, связанное с результатом, но я думаю, что могу начать это сейчас. Спасибо! - person Johan; 20.11.2012
comment
Я собирался ответить на этот вопрос, но тут вижу @jonSkeet 0_0 - person Rakesh Juyal; 20.11.2012
comment
Если вы хотите, чтобы вывод в виде строки символов обрабатывался приложением Java, просто заставьте преобразователь выводить символы, предоставив Writer. Попросить его записать байты в byteOutputStream, а затем декодировать байты как символы, просто создает сложность и вероятность ошибки. - person Michael Kay; 20.11.2012