【问题标题】:SAX handling special charactersSAX 处理特殊字符
【发布时间】:2011-11-16 05:06:33
【问题描述】:

我正在尝试使用 Java 和 SAX 为 Android 设备解析 XML 文件。我从互联网上得到,在解析它时,我得到了一个 ExpatException:字符“é”上的格式不正确(无效标记)。 有没有办法处理这些字符而无需更改 xml 文件中的所有特殊字符?

编辑: 这是我将文件写入 SD 卡的部分代码。

File SDCardRoot = Environment.getExternalStorageDirectory();
            File f = new File(SDCardRoot,"edt.xml");
            f.createNewFile();
            FileOutputStream fileOutput = new FileOutputStream(f);
            InputStream inputStream = urlConnection.getInputStream();


            byte[] buffer = new byte[1024];
            int bufferLength = 0;
            while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
                fileOutput.write(buffer, 0, bufferLength);
            }

            fileOutput.close();

这是我的 xml 的一部分:

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet type="text/xsl" href="ttss.xsl"?>

<timetable>
<option combined="0" totalweeks="0" showemptydays="0" dayclass="reverse">
<link href="g56065.xml" class="xml">Imprimer</link>
<link href="g56065.pdf" class="pdf">Version PDF</link>
<weeks>Semaines</weeks>
<dates>Dates</dates>
<week>Semaine</week>
<date>Date</date>
<all>Toutes les semaines</all>
<notes>Remarques</notes>
<id>ID</id>
<tag>Champs Libre</tag>
<footer>Publié le 10/09/2011 22:14:28</footer>
... </timetable>

这里是解析代码:

public class ParserSemaines extends DefaultHandler {
    private final String SEMAINE = "span";
    private final String DESCRIPTION = "description";
    private ArrayList<Semaine> semaines;
    private boolean inSemaine;
    private Semaine currentSemaine;
    private StringBuffer buffer;
    @Override
    public void processingInstruction(String target, String data) throws SAXException {
        super.processingInstruction(target, data);
    }
    public ParserSemaines() {
        super();
    }

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        semaines = new ArrayList<Semaine>();
    }

    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
        buffer = new StringBuffer();
        if (localName.equalsIgnoreCase(SEMAINE)){
            this.currentSemaine = new Semaine();
            this.currentSemaine.setDate(attributes.getValue("date"));
            this.inSemaine = true;
        }
        if(localName.equalsIgnoreCase(DESCRIPTION)){
            this.currentSemaine.setDescription(buffer.toString());
        }
    }

    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
        if (localName.equalsIgnoreCase(SEMAINE)){
            this.semaines.add(currentSemaine);
            this.inSemaine = false;
        }
    }

    public void characters(char[] ch,int start, int length) throws SAXException{
        String lecture = new String(ch,start,length);
        if(buffer != null) buffer.append(lecture);
    }

    public ArrayList<Semaine> getData(){
        return semaines;
    }
}

这是我用来调用解析器的代码:

SAXParserFactory fabrique = SAXParserFactory.newInstance();
        SAXParser parseur = null;
        ArrayList<Semaine> semaines = null;
        try {
            parseur = fabrique.newSAXParser();
            DefaultHandler handler = new ParserSemaines();
            File f = new File(Environment.getExternalStorageDirectory(),"edt.xml");
            parseur.parse(f, handler);  
            semaines = ((ParserSemaines) handler).getData();
        }

询问是否需要任何其他代码部分。

检查后,SD 卡中的 xml 文件似乎将“é”显示为“�”。 这应该是问题,但我不知道为什么。 我也尝试使用 URI 进行解析,但它并没有改变任何东西,我总是遇到同样的异常。

【问题讨论】:

  • SAX 解析器应该可以毫无问题地处理非 ASCII 字符。显示您的代码和 XML 示例。
  • 听起来像:1. XML 文件编码不正确,或 2. XML 文件在 Internet 上正确提供,其字符编码由 HTTP 标头指示,并且您在保存时丢失了该信息本地文件。
  • 显示的代码只是将数据复制为原始字节,因此不能以任何方式与 XML 编码混淆。您需要显示解析代码。
  • 请在您设置实际 SAX 解析器的位置添加代码(即,从解析器工厂获取解析器并调用 parse())。
  • 你的解析代码看起来很好,这表明服务器给你的内容不正确。

标签: java sax


【解决方案1】:

我终于找到了解决办法。 我没有使用 SAXparder,而是使用

android.util.Xml.parse(InputStream,Xml.Encoding.ISO_8859_1, DefaultHandler);

感谢大家为我提供的所有帮助。

【讨论】:

    【解决方案2】:

    检查后,SD卡中的xml文件显示“é”为“�”。

    这确实表明存在编码问题。

    您发布的代码似乎是从 URL 到文件的正确逐字节副本,因此该文件应该准确地代表您从 URL 获得的内容。这意味着来自服务器的响应可能不在 ISO-8859-1 中。

    我的下一步是使用Fiddler 之类的工具来检查整个回复,特别注意:

    • Content-Type 标头。如果它告诉您不同的字符集,您必须将该信息传递给解析器和/或手动转换它。
    • 返回的实际字节数。就您所知,both Content-Type 和 XML 序言都可能在撒谎。如果文件是真正的 ISO-8859-1,那么重音 e 的字节值应该是 0xE9。如果内容实际上是 UTF-8,则应该有两字节序列 0xC3 0xA9(参见here)。您正在显示一个三字节序列,这没有意义。但最好查一下来源。

    另外,在将文件传递给 SAX 解析器之前,请确认您没有将文件转换为字符串。


    供参考:我编写了一个连接到 OP 的 URL 并将该连接直接传递给最小 SAX 解析器的最小程序。它似乎运行没有错误。我还使用了 DOM 解析器,并验证了至少根元素已被正确解析。

    public static void main(String[] argv)
    throws Exception
    {
       URL url = new URL("http://www.disvu.u-bordeaux1.fr/et/edt_etudiants2/Master/Semestre1/g56065.xml");
       InputStream in = url.openConnection().getInputStream();
    
       SAXParserFactory spf = SAXParserFactory.newInstance();
       SAXParser parser = spf.newSAXParser();
       parser.parse(in, new DefaultHandler());
       System.out.println("parse successful");
    }
    

    【讨论】:

    • 这里是提琴手结果,响应头:HTTP/1.0 200 OK 日期:星期三,2011 年 9 月 14 日 16:01:44 GMT 服务器:Apache Last-Modified:星期三,2011 年 9 月 14 日 15:18 :40 GMT ETag:“da80c9-1e634-46611400”接受范围:字节内容长度:124468 连接:关闭内容类型:application/xml 我检查了,“é”在十六进制结果中实际上是 0xE9。我觉得我得到的唯一解决方案是将所有“é”更改为“e”,即使这需要一些时间来处理。这是 xml 文件 URL:disvu.u-bordeaux1.fr/et/edt_etudiants2/Master/Semestre1/…
    • @Alexis - 我不得不承认我被难住了。我加载了您的链接,果然,内容似乎采用 ISO-8859-1 编码。所有的标题看起来都是正确的。而且您的代码看起来适合简单的逐字节复制。
    • 我觉得奇怪的是 SD 卡上的文件显示不同的字节。您只是将其发送到终端,还是使用十六进制转储程序?如果是前者,请尝试后者来验证文件中的字节是否实际被扩展。
    • 您可以完全消除副本吗? SAX 解析器将直接从 InputStream 中获取其输入。
    • 第一个问题:我确实将文件复制到我的计算机上阅读它。当我回到我的电脑上时,我会尝试检查字节。我试图直接从 URI 获取 xml,它也是这样做的。我用 parser.parse(URI,handler); 调用了解析器;
    【解决方案3】:

    可能是编码问题。尝试将其更改为ISO-8859-1

    在你的 xml 中尝试:

    <?xml version="1.0" encoding="ISO-8859-1"?>
    

    或者,在您的代码中,使用:

    inputSource.setEncoding("ISO-8859-1");
    

    【讨论】:

    • 在我的 xml 中,编码设置正确。我从不使用 inputSource,我应该在哪里使用它?
    猜你喜欢
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多