2010/08/06

[C#][Java] 處理讀取 XML 時發生的 The entity "xxx" was referenced, but not declared 例外

在XML的應用上, 有時會處理到一些無預期的資料, 例如以下的 sample:
<?xml version="1.0" encoding="UTF-8" ?>
<message>
  <from>yilin</from>
  <content>copyright &copy; 2008  Power by Test site</content>
<message>


<content>標籤的內容可能是別人給的, 如果此時字串中包含了一些以 Entity Name 所表示的字元符號(ex: &nbsp; , &copy; , etc) .
程式在讀入這些 XML 資料時, 將會因為不知如何轉換這些符號, 而產生以下的 Exception:
  • The entity "xxx" was referenced, but not declared. (參考了未宣告的實體 'xxx')
    • 其中, xxx表示 Entity Name (copy, yen, etc)
網路有一種解法是在 XML 中宣告 Html 的 DOCTYPE :
例如:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<message>
  <from>yilin</from>
  <content>copyright &copy; 2008  Power by Test site</content>
</message>
將 XML 改成上述的樣子後, 錯誤訊息將會因為該網址無法讀取, 而改為:
  • Server returned HTTP response code: 503 for URL: http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd (遠端伺服器傳回一個錯誤: (503) 伺服器無法使用)
為了解決此 503 問題, 可能又要翻遍網路去找解法.
找到解法後, 可能又會因為 XML 中出現了新的 Entity Name , 且未在原先宣告的 DOCTYPE 中, 因而產生一開始的錯誤, 最後陷入 DOCTYPE 和 ENTITY 無止盡的循環中.
所以我後來放棄這樣的作法, 主要原因在於我無法預期會收到哪一種 Entity Name , 所以也無法填入相對應的 DOCTYPE .
若是建立一個自己的 XML Resolver , 又會擔心處理上過於複雜.
最後我的作法是不在 XML 中新增其他的宣告, 僅將所有的 & 換為 &amp; , 做法如下:
  • C#:
    XmlDocument doc = new XmlDocument();
    string strXmlContent = File.ReadAllText(@"C:\test.xml");
    doc.LoadXml(strXmlContent.Replace("&", "&amp;"));
  • Java:
    String strXmlFile = "C:\\test.xml";
    BufferedReader br = new BufferedReader(new FileReader(new File(strXmlFile)));
    StringBuffer sb = new StringBuffer();
    String line;
    while ((line = br.readLine()) != null) {
      sb.append(line);
    }
    br.close();
    StringReader sr = new StringReader(sb.toString().replaceAll("&", "&amp;"));
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new InputSource(sr));
    sr.close();

沒有留言: