Java sax、dom、pull解析xml


-------------------------------------SAX解析xml----------------------------------

》Sax定義

         SAX是一個解析速度快並且占用內存少的xml解析器,非常適合用於android等移動設備

         SAX全稱是Simple API for Xml,既是指一種接口,也是一個軟件包

         作為接口,sax是事件驅動型xml解析的一個標准接口

》Sax特點

        1. 解析效率高,占用內存少

        2.可以隨時停止解析

        3.不能載入整個文檔到內存

        4.不能寫入xml

        5.SAX解析xml文件采用的是事件驅動

        ---sax並不需要解析完 整個文檔,在按內容順序解析文檔的過程中,sax會判斷當前讀到的字符是否合法xml語法中的某部分,如果符合就會觸發事件

》Sax工作原理

         Sax的工作原理簡單的說,就是對文檔進行順序掃描,掃描到文檔(document)開始與結束,掃描到元素(element)開始、結束等地方時調用事件處理

         處理函數做相應動作,然后繼續掃描,直到文檔結束。

》Sax解析文檔過程

           1.繼承DefaultHandler  ,並實現方法       

           2.創建SAX解析器工廠

           3.獲得解析器

           4.獲得輸入流

           5.使用輸入流,和實現接口作參數,調用解析器的解析方法進行解析

 

》defaultHandler 接口是實現contentHandler接口

         ContentHandler接口中的常用方法

                 >startDocument()

                            當遇到文檔開頭的時候,調用這個方法,可以在其中做一些與准備工作

                 >endDocument()

                             當文檔結束的時候,調用這個方法,可以在其中做一些善后工作

                 >startElement(String namespaceURL, String localName, String qName, Attributes atts)

                             當讀到一個開始標簽的時候,會觸發這個方法。namespaceURL就是命名空間,localName是不帶命名空間前綴的標簽名,

                             qName是待命名空間前綴的標簽名。通過atts可以得到所有的屬性名和相應的值。

                 >endElement(String uri, String localName, String name)

                            當遇到結束標簽的時候,調用這個方法

                  >characters(char[] ch, int start, int length)

                            這個方法用來處理在xml文件中讀到的內容,第一個參數為文件的字符串內容,后面兩個參數是讀到的字符串在這個數組中的起始位置和長度,

                            使用new String(ch, start, length)就可以獲取內容

 

》SAX解析實例

          -------------1.在src下創建xml 文件,並結合成實體類Userinfo.java-------------

<?xml version="1.0" encoding="UTF-8"?>
<admins>
<admin id="1">
<name>阿龍</name>
<age>23</age>
<sex>男</sex>
<email>along@qq.com</email>
</admin>
</admins>

 

          ----------Userinfo.java----

        String name;
int age;
String sex;
String email;
String id;

      。。。  生成get、set方法

     --------------------2.創建XmlPaser繼承defaultHandler----------------------

  public class XmlPaser extends DefaultHandler{

        //創建user對象為把查到的內容放到里面

        Userinfo user;
public Userinfo getUser() {
return user;
}
public void setUser(Userinfo user) {
this.user = user;
}

         //定義標簽變量

        String tagName = null;

        //開始文檔處理些准備工作

         public void startDocument() throws SAXException {
user = new Userinfo();
super.startDocument();
}

       

        //讀到第一個標簽觸發

         public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
tagName = localName;
if("admin".equals(tagName)){
user.setId(attributes.getValue(0));
System.out.println("id:  "+attributes.getValue(0));
}
}

        

       //讀取文本內容

      public void characters(char[] ch, int start, int length)
throws SAXException {
if(tagName!=null){
if("name".equals(tagName)){
String str = new String(ch,start,length);
user.setName(str);
System.out.println("name:  "+str);
}else if("age".equals(tagName)){
String str = new String(ch,start,length);
user.setAge(Integer.parseInt(str));
System.out.println("age:   "+str);
}else if("sex".equals(tagName)){
String str = new String(ch,start,length);
user.setSex(str);
System.out.println("sex:  "+str);
}else if("email".equals(tagName)){
String str = new String(ch,start,length);
user.setEmail(str);
System.out.println("email:  "+str);
}
}
}

        //遇到結束標簽

       public void endElement(String uri, String localName, String qName)
throws SAXException {
tagName=null;

}

        //文檔讀完

public void endDocument() throws SAXException {
super.endDocument();
}

 }

 

----------------布局文件main省略-----------

----------------------3.-類SAXActivity繼承Activity----------------

         Button btnOk;

        public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

btnOk = (Button)this.findViewById(R.id.button1);
        btnOk.setOnClickListener(new OnClickListener() {

public void onClick(View v){

//創建解析工廠和解析器

                        SAXParserFactory spf = SAXParserFactory.newInstance();

                        try{

SAXParser sp = spf.newSAXParser();

                                //解析

                               XmlPaser xp = new XmlPaser();

                                InputStream is = this.getClass().getClassLoader().getResourceAsStream("user.xml");

sp.parse(is,xp);

 

//獲得讀取到的內容

                                 Userinfo user = xp.getUser();

//在頁面顯示

.................

}

}

       });

     }

 

---------------------------------------Dom解析Xml--------------------------------------------

》DOM簡介

        dom全稱Document Object Model ,為xml文檔的已解析版本定義了一組接口。解析器讀入整個文檔,然后構建一個主流內存的樹結構,

         然后代碼就可以使用dom接口來操作這個樹結構

》DOM的特點

         >優點

                  1.整個文檔樹在內存中,便於操作;支持刪除、修改、重新排列等多種功能

                  2.通過樹形結構存取xml文檔

                  3.可以在樹的某個節點上向前或向后移動

           >缺點

                  1.將整個文檔調入內存(包括無用的節點),浪費時間和空間

            >適用場合

                  一旦解析了文檔還需多次訪問這些數據;硬件資源充足(內存,cpu)

》DOM解析步驟

      1.創建解析器工廠

      2.獲得解析器工廠

      3.接受一個xml文檔作為輸入參數名,並得到一個xml的文檔對象(Document)

      4.操作文檔對象

 

》解析實例:

-----------------------1.創建要解析的xml文件、和實體類(Person)---------------------------

<?xml version="1.0" encoding="utf-8"?>
<users>
<user id="1">
<name>Tom</name>
<age>19</age>
</user>
<user id="2">
<name>Jaary</name>
<age>18</age>
</user>
</users>

 

實體類 略

-----------------------2. Dom解析(DomService.java)-----------------------------------

public List<Person> getPersons(InputStream input) throws Throwable{

//獲得解析器工廠

         DocumentBuilderFactory    factory = DocumentBuilderFactory.newInstance();

         //獲得解析器

          DocumentBuilder builder = factory.newDocumentBuilder();

        //進行解析

         Document  doc = builder.parse(input);

 

        List<Person> personlist = new new ArrayList<Person>();

       //獲得所有叫user的節點

        NodeList  list = doc.getElementsByTagName(user);

        String id="";
String name="";
String age="";
for(int i=0;i<list.getLength();i++){
//取得第i個user節點
Element node=(Element)list.item(i);
Person p=new Person();
//獲取id屬性
id=node.getAttribute("id");
//獲得user節點下的子節點列表
NodeList userList=node.getChildNodes();
for(int j=0;j<userList.getLength();j++){
//判斷是否是元素節點,name和age屬於元素節點
if(userList.item(j).getNodeType()==Node.ELEMENT_NODE){

Element childNode=(Element)userList.item(j);
if("name".equals(childNode.getNodeName())){
name=childNode.getFirstChild().getNodeValue();
}
else if("age".equals(childNode.getNodeName())){
age=childNode.getFirstChild().getNodeValue();
}
p.setName(name);
p.setAge(age);
p.setId(Integer.parseInt(id));
}

}

personList.add(p);
}
return personList;

}

-------------------------3.Activity01繼承Activity類----------------------------------------------------

 

 public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        InputStream is=this.getClass().getClassLoader().getResourceAsStream("test.xml");
        DomService dom=new DomService();
        
        try {
List<Person> ps=dom.getPersons(is);
for(Person p:ps){
System.out.println(p.getId());
System.out.println(p.getName());
System.out.println(p.getAge());
}
} catch (Exception e) {
e.printStackTrace();
}
    }

 

--------------------------------------pull解析-----------------------------

》pull解析器簡介

        1.pull解析器是android內置的解析器,解析原理與sax類似

        2.pull它提供了類似的事件。

              如:開始元素和結束元素事件,使用parse.next()可以進入下一個元素並觸發相應的事件,事件將作為數值代碼被發送

                      因此可以使用一個switch對感興趣的事件進行處理。當元素開始解析時,調用parser.nextText()方法獲取下一個Text類型節點的值 

 

》pull與sax的不同之處

          1.pull讀取xml文件后觸發相應的事件調用方法返回的是數字。

          2.pull可以在程序中控制,想解析到哪里就可以停止到哪里

          3.Android中更推薦使用pull解析

 

》pull解析步驟

      1.創建解析器對象

          XmlPullParser paser = Xml.newPullParser();

      2.進行解析

             paser.setInput(input,"utf-8");

      3.產生第一個解析事件

              int eventType = paser.getEventType();

       4.可以使用循環判斷是否繼續解析

                while(eventType!=XmlPullParser.END_DOCUMENT){}

 

 

 

 

》解析實例

-------------------1。創建xml.及實例對象(Person.java)----------------略

--------------------2.pull解析(PullService .java)----------------------

List<Person> getAlPerson(InputStream is) throws XmlPullParserException, IOException{

List<Person> persons=null;
Person p=null;
XmlPullParser parser=Xml.newPullParser();
parser.setInput(is,"utf-8");
//獲得事件類型
int type=parser.getEventType();
while(type!=XmlPullParser.END_DOCUMENT){

switch(type){

case XmlPullParser.START_DOCUMENT://文檔開始
persons=new ArrayList<Person>();
break;
case XmlPullParser.START_TAG://元素開始
if(parser.getName().equals("user")){

p=new Person();
String id=parser.getAttributeValue(0);
p.setId(Integer.parseInt(id));
}
else if(parser.getName().equals("name")){
if(p!=null){

String name=parser.nextText();
p.setName(name);
}
}
else if(parser.getName().equals("age")){

String age=parser.nextText();
p.setAge(age);
}
break;
case XmlPullParser.END_TAG:
if("user".equals(parser.getName())){

persons.add(p);
p=null;
}
break;

}
type=parser.next();
}
return persons;
}
}

------------------------------------Activity類-----------------------------------

 public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        InputStream is=this.getClass().getClassLoader().getResourceAsStream("test.xml");
        PullService pps=new PullService();
        
        try {
List<Person> ps=pps.getPersons(is);
for(Person p:ps){
System.out.println(p.getId());
System.out.println(p.getName());
System.out.println(p.getAge());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
    }

 

SAX、DOM、PULL的比較

SAX、DOM、PULL各有自己的特點,具體操作XML的時候該如何選擇呢?

1.內存占用

這是一個根本性問題。由於Android手機性能相對於現在的應用操作還是有限的,程序對內存的占用直接影響到了解析XML的速度。在這點上,SAX、Pull以它們比DOM占用更少的內存的解析方式,更適合於Android手機開發。

2.編程方式

SAX采用事件驅動,在相應事件觸發的時候,會調用用戶編寫好的方法。也就是說,每解析一類XML,就要編寫一個新的適合該類XML的處理類。這顯然不是一個好的解決辦法,盡管其在解析速度上是那么優秀。而這點,DOM因為是W3C的規范。所以被更多程序員所知道和使用。所以在開發過程中,沒有太大困難。Pull雖然屬於一個小眾的,甚至是不為人知的解析器,但是通過上面對其介紹和示例,我們應該能看出它的簡潔性。

3.訪問與修改

由於采用的是流式解析,這就說明它們不能像DOM那樣隨機訪問,XML的其中任意一個節點。並且,SAX並沒有提供對文檔中加節點的API,更沒有刪除,修改文檔內容的方法。

4.訪問方式

這是產生它們解析快慢的根本原因。如果把SAX和Pull比喻成一目十行,很快但是是走馬觀花的閱讀方式的話,那么DOM就是逐字逐句的閱讀,很慢,但是是過目不忘。這里還要需要注意的是,SAX,Pull解析的方式是同步的,即解析器讀到哪里,就對哪里進行處理。而DOM是已經將文件解析好后,供用戶提取XML中感興趣的信息。

總結:

出於對內存占用的考慮,推薦使用SAX或者Pull來工作。可是根據它們工作的原理:如果只是需要XML最后的幾個節點的相關信息,或者出現反復檢索XML文件的情況。那么基本上三者在性能上就沒有什么差異,反而在這時,SAX的處理類會使程序顯得比其他的實現方式顯得臃腫。所以,想做一個高性能的Android軟件,還是要多分析,選擇合適的工具,才能發揮它的作用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM