2011-09-13 114 views
0

我正在嘗試使用Java和SAX爲Android設備解析XML文件。我從互聯網上獲得,並解析它時,我得到一個ExpatException:對字符「é」沒有格式良好(無效標記)。 有沒有辦法處理這些字符,而不必更改xml文件中的所有特殊字符?處理特殊字符的SAX

編輯: 這是我的代碼寫入我的SDcard的文件的一部分。

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(); 
     } 

詢問是否需要其他代碼部分。

檢查後,SDcard中的xml文件顯示「é」爲「½」。 這應該是問題,但我沒有任何線索爲什麼。 我也嘗試用URI解析,但它不會改變任何我總是得到相同的異常。

+0

SAX解析器應該處理非ASCII字符沒有任何問題。顯示你的代碼,以及你的XML的例子。 – parsifal

+0

聲音如下:1. XML文件編碼錯誤,或2. XML文件在Internet上正確傳輸,其HTTP編碼指示的字符編碼,並在本地保存文件時丟失了該信息。 –

+0

顯示的代碼只是將數據複製爲原始字節,因此不能以任何方式將XML編碼混淆。您需要顯示解析代碼。 –

回答

1

我終於找到了解決辦法。 而不是使用SAXparder的,我用

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

謝謝大家對你提供給我的幫助。

0

可能是編碼問題。嘗試將其更改爲ISO-8859-1

在你的XML嘗試:

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

,或者在你的代碼,使用:

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

在我的xml編碼設置正確。我從來不使用inputSource,我應該在哪裏使用它? – Alexis

1

檢查後,似乎在SD卡中的XML文件顯示 「é」 爲「 �" 。

這確實表示編碼問題。

您發佈的代碼似乎是從URL到文件的正確逐字節副本,因此該文件應該完全代表您從URL獲得的內容。這意味着來自服務器的響應可能不在ISO-8859-1中。

我的下一步是使用一個工具,如Fiddler檢查整個響應,要特別注意:

  • 的Content-Type頭。如果它告訴你一個不同的字符集,你必須將這些信息傳遞給解析器和/或手動轉換它。
  • 返回的實際字節數。大家知道,都是,Content-Type和XML序言可能在說謊。如果文件是真正的ISO-8859-1,那麼重音符號應該有一個字節值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"); 
} 
+0

這是提琴手的結果,響應標題: HTTP/1.0 200 OK 日期:2011-09-09 16:01:44 GMT 服務器:Apache Last-Modified:Wed,14 Sep 2011 15:18:40 GMT 的ETag: 「da80c9-1e634-46611400」 接受-範圍:字節 的Content-Length:124468 連接:關閉 的Content-Type:application/xml進行 我檢查和 「E」 實際上是0xE9在十六進制結果。 我覺得我得到的唯一解決方案是將所有「é」更改爲「e」,即使需要一些時間來處理。 這裏是xml文件網址: http://www.disvu.u-bordeaux1.fr/et/edt_etudiants2/Master/Semestre1/g56065.xml – Alexis

+0

@Alexis - 我不得不承認我很難過。我加載了你的鏈接,果然,內容似乎是在ISO-8859-1編碼中。所有的標題看起來都是正確的。而你的代碼看起來正確的是一個簡單的逐字節拷貝。 – parsifal

+0

我覺得很奇怪,SD卡上的文件顯示不同的字節。你只是簡單地把它發送到終端,或者你在使用十六進制轉儲程序嗎?如果是前者,請嘗試後者來驗證文件中的字節實際上是否被擴展。 – parsifal