java - 如何将最初的 Latin-1 char[] 从 SAX 解析器转换为正确的 UTF-8 字符串?

标签 java xml character-encoding char sax

我一直在尝试使用 Java SAX 解析器来解析 ISO-8859-1 字符编码的 XML 文件。否则一切顺利,但是 ä 和 ö 等特殊字符让我头疼。简而言之,ContentHandler.characters(...)方法给我奇怪的字符,你甚至不能使用 char 数组来构造具有指定编码的 String。

这是两个文件中的一个完整的最小工作示例:

latin1.xml:

<?xml version='1.0' encoding='ISO-8859-1' standalone='no' ?>
<x>Motörhead</x>

该文件以上述 Latin-1 格式保存,因此 hexdump 给出:

$ hexdump -C latin1.xml 
00000000  3c 3f 78 6d 6c 20 76 65  72 73 69 6f 6e 3d 27 31  |<?xml version='1|
00000010  2e 30 27 20 65 6e 63 6f  64 69 6e 67 3d 27 49 53  |.0' encoding='IS|
00000020  4f 2d 38 38 35 39 2d 31  27 20 73 74 61 6e 64 61  |O-8859-1' standa|
00000030  6c 6f 6e 65 3d 27 6e 6f  27 20 3f 3e 0a 3c 78 3e  |lone='no' ?>.<x>|
00000040  4d 6f 74 f6 72 68 65 61  64 3c 2f 78 3e           |Mot.rhead</x>|

因此,正如您所期望的那样,“ö”是用单个字节 f6 编码的。

然后,这是以 UTF-8 格式保存的 Java 文件:

MySAXHandler.java:

import java.io.File;
import java.io.FileReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class MySAXHandler extends DefaultHandler {
private static final String FILE = "latin1.xml"; // Edit this to point to the correct file

@Override
public void characters(char[] ch, int start, int length) {
    char[] dstCharArray = new char[length];
    System.arraycopy(ch, start, dstCharArray, 0, length);
    String strValue = new String(dstCharArray);
    System.out.println("Read: '"+strValue+"'");
    assert("Motörhead".equals(strValue));
}

private XMLReader getXMLReader() {
    try {
        SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
        XMLReader xmlReader = saxParser.getXMLReader();
        xmlReader.setContentHandler(new MySAXHandler());
        return xmlReader;
    } catch (Exception ex) {
        throw new RuntimeException("Epic fail.", ex);
    }
}

public void go() {
    try {
        XMLReader reader = getXMLReader();
        reader.parse(new InputSource(new FileReader(new File(FILE))));
    } catch (Exception ex) {
        throw new RuntimeException("The most epic fail.", ex);
    }
}

public static void main(String[] args) {
    MySAXHandler tester = new MySAXHandler();
    tester.go();
}
}

运行该程序的结果是它输出 Read: 'Mot�rhead'(ö 替换为“? in a box”),然后由于断言错误而崩溃。如果查看 char 数组,您会发现编码字母 ö 的 char 由三个字节组成。它们对我来说没有任何意义,因为在 UTF-8 中,ö 应该用两个字节编码。

我尝试过的

我曾尝试将字符数组转换为字符串,然后将该字符串的字节传递给另一个带有字符集编码参数的字符串构造函数。我也玩过 CharBuffers 并试图找到可能与 Locale 类一起使用的东西来解决这个问题,但我尝试的似乎没有任何效果。

最佳答案

问题是您正在使用 FileReader 来读取文件,而不是之前评论者建议的 FileInputStream。在go方法中,取出FileReader,替换为FileInputStream

public void go() {
    try {
        XMLReader reader = getXMLReader();
        reader.parse(new InputSource(new FileInputStream(new File(FILE))));
    } catch (Exception ex) {
        throw new RuntimeException("The most epic fail.", ex);
    }
}

按照您现在的方式,FileReader 使用默认平台编码在将字符传递给 SAX 解析器之前对其进行解码,这不是您想要的。如果您替换为 FileInputStream,那么 XML 解析器应该正确读取具有字符集编码的处理指令,并为您处理字符集解码。

因为 FileReader 正在进行解码,所以您看到的是无效字符。如果您让 SAX 解析器处理它,它应该会顺利通过。

关于java - 如何将最初的 Latin-1 char[] 从 SAX 解析器转换为正确的 UTF-8 字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10451033/

相关文章:

c# - 使用 C# 创建和写入数据到 CSV 文件的问题

Java URL编码转义特殊字符

php - 如何用php打印所有ascii字符的列表?

java - 首次保存后出现 TransientObjectException 错误

java - 使用泛型对整数数组进行排序 (Java)

java - 如何更改一堆 java 可序列化类的包

java - 在 GlassFish 上创建和运行 RESTful Web 服务

c# - 序列化作为通用 List<> 的基类时,WCF 调用失败

javascript - 如何使用 XSLT 转换 XML 文档并在 IE 中添加参数?

java - Android 和 Oracle Java 的字符串字符编码