天天看點

(轉)Dom4j中的中文編碼問題

一、“中文問題沒商量”之Dom4j中的編碼問題 

  本文主要講述的是Dom4j在把Document儲存到檔案過程中出現的一個中文問題,本文跟《

80前

》一文一樣,以Spring項目無關,請“春迷”們自重、沒事勿擾,文中不足之處歡迎大家批評指教。

  Dom4j是一個比較優秀的java開源xml解析項目,支援DOM, SAX and JAXP.,并提供對XPath查詢語言的強大支援。是以,在EasyJF團隊的很多開源項目中,如EasyJWeb、EasyDBO等都是使用Dom4j來處理xml檔案相關操作。

1、從一個xml檔案中載入一個Dom到記憶體:

  FileInputStream in = new FileInputStream(new File(fileName));

  SAXReader reader = new SAXReader();

  doc = reader.read(in);

2、把Dom中的資料寫入到xml檔案中 

  使用Dom4j,要把一個Dom中的資料寫入到檔案非常簡單,API如下:

   public void write(Writer writer) throws IOException;

  是以,假如我們要把一個Document寫入到c:\test.xml檔案中,可以簡單的使用下面的代碼即可:

java.io.Writer wr= new java.io.FileWrite(filename);

  doc.write(wr);

 wr.close();//注意,必須要執行close()方法,才會實作真正的寫入

  

  這種用法也是Dom4j所推薦我們使用的非常簡單的方法。然而,當我們的dom中包含有中文字元資料的時候,這種方法寫入的xml文檔卻無法使直覺打開。會提示類似如下的錯誤:

   org.dom4j.DocumentException: invalid byte 1 of 1-byte UTF-8 sequence (0xb2) Nested exception: invalid byte 1 of 1-byte UTF-8 sequence (0xb2)

 at org.dom4j.io.SAXReader.read(SAXReader.java:484)

 at org.dom4j.io.SAXReader.read(SAXReader.java:343)

 at 

  我們可以看生成的xml檔案編碼,内容是utf-8的,但檔案格式确是ANSI的,如下圖所示:

原因分析:

  由于FileWriter預設的輸出編碼是ANSI編碼,而Dom4j中的wirte方法提供的内容實際是以UTF-8儲存的,是以造成了包括中文字元的XML檔案無法正常閱讀。查了半天代碼,最後才發現:是UTF字元的問題。當XML中含有中文,而沒有指定XML Encoding="UTF-8"的時候,就會産生這樣的錯誤。

解決方法:

   不能使用簡單的FileWriter,而應該是使用一個能指定具體輸出編碼的Writer,在JDK的io包中, OutputStreamWriter可以指定輸出編碼。

  正确的代碼如下:

java.io.OutputStream out=new java.io.FileOutputStream(fileName);

  java.io.Writer wr=new java.io.OutputStreamWriter(out,"UTF-8");  

  doc.write(wr);  

  wr.close();

  out.close();

  簡化一下可以寫成下面的樣式:

   java.io.Writer wr=new java.io.OutputStreamWriter(new java.io.FileOutputStream(fileName),"UTF-8");  

小結: 

  由于大多數優秀的基礎性開源項目都是老外開發,他們不大可能在中文平台下進行測試,用例資料也很少會使用中文平台,是以,我們即使按照這些開源項目的通用說明文檔及使用者指南去操作,也會出現很多不可預知的錯誤。這也是為什麼本人要參與組建開源團隊EasyJF,提倡搞國産開源,并開發一些基礎性的開源架構如EasyJWeb、EasyDBO的一個初衷。

  當然,這裡提出的中文問題,算是一個還“沒來得及商量”以及要通過一些罕見的處理才能正确運作的中文問題。是以,同樣歸并到了“中文問題沒商量”系列中。

(注:本文作者,

EasyJF開源團隊

 

大峽

,轉載請保留作者聲明!)

二、DOM4J中文問題 Invalid byte 1 of 1-byte UTF-8 sequence

http://hlwlemon.blog.sohu.com/81841115.html 本文出處

在用dom4j的時候發現有時會出現這個問題:無法以UTF-8儲存xml檔案,儲存後再次讀出的時候會報“Invalid byte 2 of 2-byte UTF-8 sequence.”這樣一個錯誤,檢查發現由dom4j生成的這個檔案,在使用可正确處理XML編碼的任何的編輯器中中文成亂碼,從記事本檢視并不會出現亂碼會正确顯示中文。讓我很是頭痛。。。。

  試着使用GBK、gb2312編碼來生成的xml檔案卻可以正常的被解析。是以懷疑的dom4j沒有對utf-8編碼進行處理。便開始檢視dom4j的原代碼。終于發現的問題所在,是自己程式的問題。

在dom4j的範例中建立一個xml文檔的代碼都類似如下

public void createXML(String fileName) {

  Document doc = org.dom4j.DocumentHelper.createDocument();

  Element root = doc.addElement("book");

  root.addAttribute("name", "我的圖書");

  Element childTmp;

  childTmp = root.addElement("price");

  childTmp.setText("21.22");

  Element writer = root.addElement("author");

  writer.setText("李四");

  writer.addAttribute("ID", "001");

  try {

  org.dom4j.io.XMLWriter xmlWriter = new org.dom4j.io.XMLWriter(

  new FileWriter(fileName));

  xmlWriter.write(doc);

  xmlWriter.close();

  }

  catch (Exception e) {

  System.out.println(e);

}

  在上面的代碼中輸出使用的是FileWriter對象進行檔案的輸出。這就是不能

正确進行檔案編碼的原因所在,java中由Writer類繼承下來的子類沒有提供編碼

格式處理,是以dom4j也就無法對輸出的檔案進行正确的格式處理。這時候所保

存的檔案會以系統的預設編碼對檔案進行儲存,在中文版的window下java的預設

的編碼為GBK,也就是所雖然我們辨別了要将xml儲存為utf-8格式但實際上檔案

是以GBK格式來儲存的,是以這也就是為什麼能夠我們使用GBK、GB2312編碼來生

成xml檔案能正确的被解析,而以UTF-8格式生成的檔案不能被xml解析器所解析

的原因。

  好了現在我們找到了原因所在了,我們來找解決辦法吧。首先我們看看dom4j

是如何實作編碼處理的

  public XMLWriter(OutputStream out) throws UnsupportedEncodingException {

  //System.out.println("In OutputStream");

  this.format = DEFAULT_FORMAT;

  this.writer = createWriter(out, format.getEncoding());

  this.autoFlush = true;

  namespaceStack.push(Namespace.NO_NAMESPACE);

  public XMLWriter(OutputStream out, OutputFormat format) throws UnsupportedEncodingException {

  //System.out.println("In OutputStream,OutputFormat");

  this.format = format;

  protected Writer createWriter(OutputStream outStream, String 

  encoding) throws UnsupportedEncodingException {

  return new BufferedWriter(

  new OutputStreamWriter( outStream, encoding )

  );

  由上面的代碼我們可以看出dom4j對編碼并沒有進行什麼很複雜的處理,完全通過java本身的功能來完成。是以我們在使用dom4j的來生成我們的XML檔案時不應該直接為在建構XMLWriter時,不應該直接為其賦一個Writer對象,而應該通過一個OutputStream的子類對象來建構。也就是說在我們上面的代碼中,不應該用FileWriter對象來建構xml文檔,而應該使用FileOutputStream對象來建構,是以将代碼修改入下:

  public void createXML(String fileName) {

  //注意這裡的修改

  new FileOutputStream(fileName));

這樣生成的代碼就是中文的了

異常:Invalid byte 1 of 1-byte UTF-8 sequence.

三、dom4j 中文處理問題編碼轉換

http://topic.csdn.net/t/20040329/17/2900049.html

正好昨天我遇到這個問題,如此解決:  

  SAXReader reader = new SAXReader();  

  org.dom4j.Document document = reader.read("D:\\ha.xml");  

  OutputFormat of = new OutputFormat();  

  of.setEncoding("gb2312"); //改變編碼方式  

  XMLWriter writer = new XMLWriter(new FileWriter "d:\\dom4j.xml"), of);  

  List list = document.selectNodes(  

  "//PersonId[@name = 'chen_zhen']");  

  if (list.size() > 0)  

  {  

  org.dom4j.Element e = (org.dom4j.Element)list.get(0);  

  System.out.println(e.toString());  

  e.setAttributue("name", "huo_yuanjia");  

  e.setAttributue("age", "20");  

  e.setName("Fighter"); //改變tag  

  e.setText("0001"); //改變value  

  }  

  writer.write(document);  

  writer.close();

以下函數可以實作編碼轉換:  

  public void writeXML(String file,Document document,String encoding){  

  try{  

  FileWriter out = new FileWriter(new File(file));  

  OutputFormat format = OutputFormat.createPrettyPrint();  

  format.setEncoding(encoding == null ? format.getEncoding() : encoding);  

  XMLWriter writer = new XMLWriter(out, format);  

  writer.close();  

  catch(IOException ex){  

  ex.printStackTrace();  

四、dom4j 輸出UTF-8 XML時中文亂碼

http://royboy.javaeye.com/blog/337948

  使用DOM4J的XMLWriter輸出UTF-8編碼的XML檔案時,出現亂碼。 

  首先,設定輸出的編碼,在這我們使用“utf-8”

Java代碼 

OutputFormat format = OutputFormat.createPrettyPrint();  

  format.setEncoding("utf-8");  

OutputFormat format = OutputFormat.createPrettyPrint();

  format.setEncoding("utf-8");

輸出代碼:

try {  

  output = new XMLWriter(new FileWriter("entity.xml"), format);  

  output.write(document);  

  output.close();  

  } catch (IOException e) {  

  e.printStackTrace();  

try {

  output = new XMLWriter(new FileWriter("entity.xml"), format);

  output.write(document);

  output.close();

  } catch (IOException e) {

  e.printStackTrace();

上面的輸出如果有中文,可以會出現亂碼的問題,将上面的FileWriter改成FileOutputStream便可以了。

  output = new XMLWriter(new FileOutputStream("entity.xml"), format);  

五、dom4j中文指定XML編碼為GBK(注:指定為utf-8時仍會出現編碼問題,見上面四)

1、檔案形式:

  XMLWriter writer = null;

  OutputFormat format = OutputFormat.createPrettyPrint();

  format.setEncoding("GBK");

try{

  writer= new XMLWriter(new FileWriter(new File("test.xml")),format);//用FileOutputStream更好。

  writer.write(document);

 }

catch(IOException ioe){ioe.printStackTrace();}

 2、String形式,我現在做的架構中,是PO<-->XML--Servlet,不需要生成檔案,搜尋了半天沒搜尋出來,後來幹脆自己試出來了。

StringWriter sw=new StringWriter();

XMLWriter writer = null;

writer=new XMLWriter(format);

 writer.setWriter(sw);

 writer.write(document);

 System.out.println(sw.toString());