2013-08-07 4 views
3

Мои трансформации XSLT были успешными в течение нескольких месяцев, пока я не наткнулся на XML-файл с символами Unicode (скорее всего, emoji). Мне нужно сохранить Unicode, но XSLT преобразует его в HTML-объекты. Я думал, что установка кодировки в UTF-8 решит мою проблему, но у меня все еще возникают проблемы.Преобразование XML и сохранение символов Юникода с помощью XSLT

Любая помощь приветствуется. Код:

private byte[] transform(InputStream stream) throws Exception{ 
    System.setProperty("javax.xml.transform.TransformerFactory", "org.apache.xalan.processor.TransformerFactoryImpl"); 

    Transformer xmlTransformer; 

    xmlTransformer = (TransformerImpl) TransformerFactory.newInstance().newTransformer(new StreamSource(createXsltStylesheet())); 
    xmlTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 

    XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(stream,"UTF-8"); 
    Source staxSource = new StAXSource(reader, true); 
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 
    Writer writer = new OutputStreamWriter(outputStream, "UTF-8"); 
    xmlTransformer.transform(staxSource, new StreamResult(writer)); 


    return outputStream.toByteArray(); 
} 

Если добавить

xmlTransformer.setOutputProperty(OutputKeys.METHOD, "text"); 

сохраняется Unicode, но XML не является.

+0

Похожие (но, к сожалению, также без ответа) http://stackoverflow.com/questions/15592025/transformer-setoutputpropertyoutputkeys-encoding-utf-8-is-not-working, это выглядит лучше: HTTP: // stackoverflow.com/questions/443305/producing-valid-xml-with-java-and-utf-8-encoding – Tomalak

ответ

0

Эта линия является подозрительным:

stream = IOUtils.toInputStream(outputStream.toString(),"UTF-8"); 

Вы преобразуете ByteArrayOutputStream в строку, используя кодировку по умолчанию платформы, которая, вероятно, не UTF-8. Измените его на

stream = IOUtils.toInputStream(outputStream.toString("UTF-8"),"UTF-8"); 

или, для более высокой производительности, просто обернуть массив байтов в ByteArrayInputStream:

return new ByteArrayInputStream(outputStream.toByteArray()); 
+0

благодарит за комментарий. Эта строка на самом деле после проблемы. Эможи меняются, когда я называю трансформатор. Я обновил свой код, чтобы отразить мои последние изменения. – l15a

0

Попытка преобразовать в строку в XML с помощью Apache Serializer.

//Serialize DOM 
OutputFormat format = new OutputFormat (doc); 
// as a String 
StringWriter stringOut = new StringWriter();  
XMLSerializer serial = new XMLSerializer (stringOut, 
                format); 
serial.serialize(doc); 
// Display the XML 
System.out.println(stringOut.toString()); 
0

Я просто натыкался на этот же вопрос, и после того, как слишком долго исследовать его, вот что я пришел к выводу.

процессоров Java XSLT избежать мультибайтных UTF-8 символов в HTML сущности даже если режим вывода является XML ... если многобайтовые символы встречаются в тексте() узле, который не завернутый в CDATA. Если символы завернуты в CDATA (для вывода), то многобайтовый символ будет сохранен.

Моя проблема:

У меня была файл XML, который выглядел так, в комплекте с смайликами.

<events> 
    <event> 
     <id>RANDOMID</id> 
     <blah> 
      <blahId>FOOONE</blahId> 
     </blah> 
     <blah> 
      <blahId>FOOTWO</blahId> 
     </blah> 
     <eventComment>Did some things. Had some Fun. </eventComment> 
    </event> 
</events> 

Я начал с таблицей стилей XSL, который выглядел так:

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns="http://www.w3.org/TR/xhtml1/strict" 
> 
    <xsl:output method = "xml" version="1.0" encoding = "UTF-8" omit-xml-declaration="no" indent="yes" /> 

    <xsl:template match="/"> 
     <events> 
      <xsl:for-each select="/events/event"> 
       <event> 
        <xsl:copy-of select="./*[name() != 'blah'"/> 
        <xsl:for-each select="./blah"> 
         <blahId><xsl:copy-of select="./blahId/text()"/></blahId> 
        </xsl:for-each> 
       </event> 
      </xsl:for-each> 
     </events> 
    </xsl:template> 
</xsl:stylesheet> 

Запуск этого с Java Transformer последовательно производится &#55357;&#56397; где мои смайлики должны быть. Последующие попытки проанализировать результирующий документ не удались со следующим сообщением об исключении:

org.xml.sax.SAXParseException; lineNumber: y; columnNumber: x; Character reference "&#55357" is an invalid XML character. 

HOGWASH!

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

РЕШЕНИЕ

Имея XSLT обернуть eventComment в CDATA, указав QName в теге cdata-section-elements атрибут xsl:output сохранит байт и работает с xsltproc и Java Transformer.

Магия здесь - это результат cdata-secion-elements property from the <xsl:output> tag. https://www.w3.org/TR/xslt#output

Я обновил свой шаблон XSL быть:

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns="http://www.w3.org/TR/xhtml1/strict" 
> 
    <xsl:output cdata-section-elements="eventComment" method="xml" version="1.0" encoding="UTF-8" omit-xml-declaration="no" indent="yes"/> 

    <xsl:template match="/"> 
     <events> 
      <xsl:for-each select="/events/event"> 
       <event> 
        <xsl:copy-of select="./*[name() != 'blah' and name() != 'eventComment']"/> 
        <!-- For the cdata-section-elements to resolve that eventComment needs to be preserved as CDATA 
         (so we don't get java doing stupid things with unicode escapment) 
         it needs to be explicitly referenced here. 
        --> 
        <eventComment><xsl:copy-of select="./eventComment/text()"/></eventComment> 
        <xsl:for-each select="./blah"> 
         <blahId><xsl:copy-of select="./blahId/text()"/></blahId> 
        </xsl:for-each> 
       </event> 
      </xsl:for-each> 
     </events> 
    </xsl:template> 
</xsl:stylesheet> 

А теперь мой выход из обоих xsltproc и ява Transformer выглядит следующим образом, и разбирает счастливо с ява DocumentBuilders.

<?xml version="1.0" encoding="UTF-8"?> 
<events xmlns="http://www.w3.org/TR/xhtml1/strict"> 
    <event> 
    <id xmlns="">RANDOMID</id> 
    <eventComment><![CDATA[Did some things. Had some Fun. ]]></eventComment> 
    <blahId>FOO</blahId> 
    <blahId>FOOTOO</blahId> 
    </event> 
</events> 
Смежные вопросы