2013-05-22 2 views
1

Обратите внимание, что это не тот же вопрос, что упоминалось выше, так как возможно ускорение XML для сохранения кодовых точек.Сохранять кодировки unicode между преобразованиями ISO-8859-1 и UTF-8 в XML в Java

У меня есть XML-файл UTF-8, который я могу отправить через HTTP в другую систему, в которой я не контролирую. По какой-то сумасшедшей причине он решает преобразовать его в ISO-8859-1, потеряв много символов Unicode и заменив их на «?». Затем эта система отправляет кому-то еще этот преобразованный XML-документ.

Как в Java на отправляющей стороне я могу избежать любого произвольного XML с кодовыми точками без ASCII, чтобы они выдержали эту промежуточную систему и все еще могут быть правильно декодированы конечной точкой?

A - (UTF-8) -> B - (ISO-8859-1) -> C (декодирует внутреннее представление Юникода).

import java.text.Normalizer; 
import java.text.Normalizer.Form; 

import org.apache.commons.lang3.StringEscapeUtils; 
import org.apache.commons.lang3.text.translate.CharSequenceTranslator; 
import org.apache.commons.lang3.text.translate.NumericEntityEscaper; 

public class Test { 
    private static CharSequenceTranslator translator = StringEscapeUtils.ESCAPE_XML 
      .with(NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE)); 

    public static void main(String[] args) { 
     String s = "<note>\n<to>Tove</to>\n<from>Jani</from>\n<heading>Reminder</heading>\n<body>Don't forget me this weekend!test☠ä</body>\n</note>"; 
     String xmlEscapedS = xmlToRobustXml(s); 
     System.out.println(xmlEscapedS); 
    } 

    /** 
    * @param s 
    * @return 
    */ 
    public static String xmlToRobustXml(String s) { 
     s = Normalizer.normalize(s, Form.NFC); 
     String xmlEscapedS = translator.translate(s); 
     return xmlEscapedS; 
    } 
} 

Я пробовал это, но он избегает всего.

&lt;note&gt; 
&lt;to&gt;Tove&lt;/to&gt; 
&lt;from&gt;Jani&lt;/from&gt; 
&lt;heading&gt;Reminder&lt;/heading&gt; 
&lt;body&gt;Don&apos;t forget me this weekend!test&#9760;&#228;&lt;/body&gt; 
&lt;/note&gt; 
+0

возможный дубликат [Как конвертировать между ISO-8859-1 и UTF-8 в Java?] (Http://stackoverflow.com/questions/652161/how-do-i-convert-between-iso-8859-1-and-utf-8-in-java) –

+0

@PaulVargas Немного отличается в случае XML с &#xxx;. Я не уверен, как это сделать с любой существующей библиотекой XML. –

+0

Не можете ли вы просто отправить ISO-8859-1 закодированный документ? Все кодовые точки вне этого диапазона могут быть экранированы с помощью [ссылок на символы] (http://www.w3.org/TR/REC-xml/#sec-references). – McDowell

ответ

1

Вот три стандартных метода API для получения ISO-8859-1 закодированных документов.

Использование StAX API:

// output stream 
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
// transcode 
StringReader xml = new StringReader("<x>pi: \u03A0</x>"); 
XMLEventReader reader = XMLInputFactory.newFactory().createXMLEventReader(
    xml); 
XMLEventWriter writer = XMLOutputFactory.newFactory().createXMLEventWriter(
    buffer, "ISO-8859-1"); 
try { 
    writer.add(reader); 
} finally { 
    writer.close(); 
} 
// proof 
String decoded = new String(buffer.toByteArray(), 
    Charset.forName("ISO-8859-1")); 
System.out.println(decoded); 

Использование DOM API:

// output stream 
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
// create XML DOM 
InputSource src = new InputSource(new StringReader("<x>pi: \u03A0</x>")); 
Document doc = DocumentBuilderFactory.newInstance() 
    .newDocumentBuilder() 
    .parse(src); 
// serialize 
DOMImplementationLS impl = (DOMImplementationLS) doc.getImplementation(); 
LSOutput out = impl.createLSOutput(); 
out.setEncoding("ISO-8859-1"); 
out.setByteStream(buffer); 
impl.createLSSerializer().write(doc, out); 
// proof 
String decoded = new String(buffer.toByteArray(), 
    Charset.forName("ISO-8859-1")); 
System.out.println(decoded); 

Использование transform package:

// output stream 
ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
// transformation 
StreamSource src = new StreamSource(new StringReader("<x>pi: \u03A0</x>")); 
StreamResult res = new StreamResult(buffer); 
Transformer transformer = TransformerFactory.newInstance().newTransformer(); 
transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); 
transformer.transform(src, res); 
// proof 
String decoded = new String(buffer.toByteArray(), 
    Charset.forName("ISO-8859-1")); 
System.out.println(decoded); 

Что вы будете использовать, зависит от случая использования; API StAX, вероятно, наиболее эффективен.

Все это образец кода будет выдавать документы, эквивалентные:

<?xml version="1.0"?><x>pi: &#x3a0;</x> 
+0

Каковы результаты этих разных методов для ввода моего примера? –

+0

@EricdesCourtis Строка образца не отображается правильно в моем браузере - '! Test☠ä' - Я вижу символ замены Unicode, за которым следует U + 00E4 SMALL LETTER A WITH DIARESIS. ä поддерживается ISO-8859-1, поэтому нет гарантии, что он будет экранирован. – McDowell

+0

Я отвечу на завтра и приму ответ, если он закончит работу. –

0

Точки коды Unicode выше 127 может быть закодирована как числовые сущности, как &#123;, используя следующее:

От Apache Commons StringEscapeUtils. Прочтите javadoc, по умолчанию escapeXML не конвертирует в числовые объекты.

StringEscapeUtils.ESCAPE_XML 
    .with(NumericEntityEscaper.between(0x7f, Integer.MAX_VALUE)); 

Кстати вы попробуйте отправить оригинальный XML используя заголовок Content-Type: application/x-xml, поэтому двоичная передачи.

+0

Узел B правильно принимает UTF-8, а затем записывается на ISO-8859-1 при записи на диск. К сожалению, я не контролирую эту часть. –

 Смежные вопросы

  • Нет связанных вопросов^_^