SAX初步解析XML文件可能遇到的問題詳解(實例展示)
剛學習 SAX初步解析XML文件,第一個代碼就看了好久,終於明白,在這裏記錄一下吧。我相信很多人想知道的並不是SAX解析的大致步驟,而是詳細的細節問題。
下面的代碼目的是:通過SAX解析一個XML文件,然後存儲在Person類中。
下面結合一個實例來具體說明:
XML文件代碼如下:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person>
<name>至尊寶</name>
<age>9000</age>
</person>
<person>
<name>白晶晶</name>
<age>7000</age>
</person>
</persons>
Person類的代碼如下(用來存儲解析過的結果):
package Server.basic;
public class Person {
private String name;
private int age;
public Person() {//建議養成習慣加上空構造器
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
XMLTest02類的代碼(重頭戲來了):
package Server.basic;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* 熟悉SAX對XML的解析流程
*/
public class XMLTest02 {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//SAX解析流程:(可以直接拷貝,沒必要自己敲)
//1、獲取解析工廠
SAXParserFactory factory=SAXParserFactory.newInstance();
//2、從解析工廠獲取解析器
SAXParser parse=factory.newSAXParser();
//3、編寫處理器
//4、加載文檔Document註冊處理器
PersonHandler hander=new PersonHandler();
//5、解析
parse.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("Server/basic/p.xml"), hander);
//獲取數據
List<Person> persons=hander.getPersons();
for(Person p:persons) {
System.out.println(p.getName()+"-->"+p.getAge());
}
}
}
class PersonHandler extends DefaultHandler{
private List<Person> persons;
private Person person;
private String tag;//存儲當前時刻操作的標籤
@Override
public void startDocument() throws SAXException {
System.out.println("-------start 解析-------");
persons=new ArrayList<Person>();
}
@Override
//開始解析元素(標籤),我們只關注qName(標籤名),其他的幾個名稱不用管,我們也幾乎不會用到
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println(qName+"-->"+"解析開始");
//if(null!=qName) {//這裏不用判斷,因爲既然開始解析標籤,那麼qName就不會爲空
tag=qName;
if(tag.equals("person")) {
person=new Person();
}
//}
}
//解析內容,.trim()作用:去掉了任何前導和尾隨空格(相當於當前一個標籤後面的換行,以及下一個標籤前面的空格都沒啦)
//,如果沒有前導或尾隨空格,則刪除該字符串。
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String contents=new String(ch,start,length).trim();
if(tag!=null) {//處理的空的問題,注意這裏很重要,意思是如果不是空標籤(被丟棄的標籤)
if(tag.equals("name")) {
//如果不丟棄有些tag的話,會導致前面已經被賦值的person的name屬性,重新被控內容覆蓋
person.setName(contents);
}else if(tag.equals("age")) {
person.setAge(Integer.valueOf(contents));
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println(qName+"-->"+"解析結束");
//if(null!=qName) {//個人覺得這裏沒有必要,因爲讀取到結束標籤的時候,qName就不會是空的
if(qName.equals("person")) {
persons.add(person);
}
//}
tag=null;//將tag丟棄掉,注意這裏很重要
}
@Override
public void endDocument() throws SAXException {
}
public List<Person> getPersons() {
return persons;
}
}
下面針對以上的代碼提出初學時,你可能會遇到的基本所有的問題還有解決辦法(注意:所有的問題都是針對該例子而提出來的):
- 【1】某個標籤後面的換行以及前面的幾個空格是怎麼處理的?
- answer:使用trim函數,去掉了任何前導和尾隨空格,相當於去掉了某個標籤後面的換行以及前面的幾個空格,之間的內容爲空字符串。
- 【2】判定字符串是否爲空,使用length函數
【3】name開始標籤,後面的內容是至尊寶,name結束標籤後面的內容是換行(這裏會出現對person的屬性name的覆蓋的情況),why???
- 當讀取 至尊寶 內容的時候,此時的當前標籤爲name,這一點是沒有任何問題的,但是讀取結束標籤name後面的換行內容時
- (這個時候換行由於trim函數,已經被處理成了空的字符串),當前標籤依然是name,但是此時由於person.setName(contents);
- 這個操作會使得person裏面的屬性name被重新賦值爲空。
- 【4】我們要避免【3】這種情況的發生,解決辦法是什麼?
- 當讀取到結束標籤name後面的換行時,丟棄掉當前是name的標籤(可以將當前標籤賦值爲空),即丟棄掉name結束標籤 後面的換行(已經爲空) 的內容(通過判定當前標籤是否爲空,如果爲空不處理即可)
- 【5】爲了不能出現空指針異常的簡便情況,就是在開始標籤和結束標籤和讀取內容的時候都加一個判定條件即可