<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    xml文件解析辦法

    xml是為了提高web數(shù)據(jù)交換量而出現(xiàn)的,雖然他現(xiàn)在web應(yīng)用中并不廣泛,但是由于他的格式良好,經(jīng)常被用做配置文件的格式。比如tomcat的主配置文件server.xml,web.xml等等。
     
    首先我們看一下需求。我們的目的主要是提取xml文件中的特定內(nèi)容,又因?yàn)閤ml文件本身的格式良好,這種查詢是非常有規(guī)律的,非常有利于我們找到需要的信息。有時我們還可能把特定信息寫回xml中,但是這種需求并不是必需的,因?yàn)榕渲梦募疾粫螅覀兺耆梢酝ㄟ^手工辦法進(jìn)行修改。
     
    對xml進(jìn)行解析的標(biāo)準(zhǔn)有兩種,sax以及dom。
    首先這兩種標(biāo)準(zhǔn)并不是針對java的,他們在各種語言環(huán)境下都可以實(shí)現(xiàn)。dom是真正的國際標(biāo)準(zhǔn)。sax是事實(shí)的標(biāo)準(zhǔn),他不由任何商業(yè)組織維護(hù),而是由一個非商業(yè)的組織在運(yùn)作。就像iso7層模型和tcp/ip一樣,雖然sax不是正式的標(biāo)準(zhǔn),但是一點(diǎn)不影響他在xml解析領(lǐng)域的地位。
     
    dom實(shí)現(xiàn)的原理是把整個xml文檔一次性讀出,放在一個樹型結(jié)構(gòu)里。在需要的時候,查找特定節(jié)點(diǎn),然后對節(jié)點(diǎn)進(jìn)行讀或?qū)憽K闹饕獌?yōu)勢是實(shí)現(xiàn)簡單,讀寫平衡;缺點(diǎn)是比較占內(nèi)存,因?yàn)樗颜麄€xml文檔都讀入內(nèi)存,文件越大,這種缺點(diǎn)就越明顯。
     
    sax的實(shí)現(xiàn)方法和dom不同。他只在xml文檔中查找特定條件的內(nèi)容,并且只提取需要的內(nèi)容。這樣做占用內(nèi)存小,靈活,正好滿足我們的需求。他的缺點(diǎn)就是寫,有些資料介紹了寫入的方法,但是我感覺這對本例沒有必要。后面主要講解用sax2.0實(shí)現(xiàn)xml文檔解析。
     
     
    首先講一下sax的工作流程,以下面的book.xml為例(不做dtd定義的驗(yàn)證,如果有這方面需求,可以查更詳細(xì)的文檔)。
    <?xml version="1.0"?>
    <books>
           <book type="computer">
                  <title>java 2</title>
                  <page>600</page>
                  <author>Jim</author>
           </book>
                  <book type="fiction">
                  <title>fly to moon</title>
                  <page>300</page>
                  <author>Vernia</author>
           </book>
    </books>
     
    1.我們需要注冊一個實(shí)現(xiàn)了sax標(biāo)準(zhǔn)的解析器,sun,java,apache等廠商和組織都實(shí)現(xiàn)了自己的解析器,大家可以直接拿過來用。
    2.然后告訴解析器,我們會用哪個xml解析程序來處理xml文檔。這個解析程序是由我們自己來實(shí)現(xiàn)的。
    3在解析開始時,解析器會觸發(fā)解析程序的startDocument()方法,告訴應(yīng)用程序,文檔解析開始了。
    要注意以下幾點(diǎn):
    1.區(qū)分解析器,解析程序的概念。
    2.sax實(shí)現(xiàn)是事件驅(qū)動的,由解析器觸發(fā)應(yīng)用程序,而不是由應(yīng)用程序來調(diào)用解析器。這和ui里的Actionlistener實(shí)現(xiàn)差不多。
    3.startDocument()方法是由ContentHandler接口定義的,我們必須要實(shí)現(xiàn)他。xml解析程序就是用來實(shí)現(xiàn)這些方法的。為什么要這么做?因?yàn)閟ax不會定義在接收到方法觸發(fā)后,會采取什么動作。只有我們自己才知道在解析的過程中,我們會做什么。不明白沒有關(guān)系,再往下看。
    4.當(dāng)遇到<books>后,解析器會觸發(fā)解析程序的startElement()方法,告訴應(yīng)用程序,我遇到一個開始的標(biāo)簽。這個startElement()方法也是由ContentHandler接口定義的,他只是提醒應(yīng)用程序他遇到一個標(biāo)簽的開始,至于是什么標(biāo)簽,他不知道,也不想知道。而由xml解析程序?qū)崿F(xiàn)了的startElement()方法,功能就大了。比如我們可以判斷這個標(biāo)簽的內(nèi)容是什么,如果是books,好,正是我們需要的,要記到內(nèi)存里;如果不是,放棄,繼續(xù)往下走。
    5.過了<books>后,解析器會觸發(fā)解析程序的characters()方法,告訴應(yīng)用程序,我遇到了標(biāo)簽的內(nèi)容。同樣的原理,由xml解析程序?qū)崿F(xiàn)了的characters()方法會處理這個內(nèi)容。當(dāng)然了如果是我們需要的,就留下;如果不是就放棄。在這個例子里,<books>后面是空格,沒有實(shí)際價值。
    6.再往下遇到了<book type="computer">標(biāo)簽,同樣觸發(fā)的是startElement()方法。以此類推,在標(biāo)簽結(jié)束時,會觸發(fā)endElement()方法,在文檔結(jié)束時會觸發(fā)endDocument()方法。至于每次觸發(fā)一個方法后,產(chǎn)生什么動作,都是由我們的解析程序來控制的。
     
    下面是一個程序例子,解析book.xml文件,把是book,并且類型是fiction的內(nèi)容挑出來。
     
    文件XmlParseAction,接收xml文件輸入,調(diào)用xml解析程序,并返回結(jié)果。
    package myb.hi.sample.action;
     
    import java.io.File;
     
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.apache.struts.action.ActionForm;
    import org.apache.struts.action.ActionForward;
    import org.apache.struts.action.ActionMapping;
    import org.apache.struts.actions.DispatchAction;
    import org.xml.sax.*;
    import org.apache.xerces.jaxp.*;
    import myb.hi.sample.form.XmlFileForm;
    import myb.hi.sample.business.*;
    import javax.servlet.*;
     
    public class XmlParseAction extends DispatchAction{
     
           /**
            * Accept the jsp request, parset the xml file
            * @param mapping
            * @param form
            * @param request
            * @param response
            * @return ActionForward
            */
           public ActionForward xmlParse(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception{
                  log.info("Start xml parse: XmlParseAction.xmlParse()");
                  XmlFileForm userForm=(XmlFileForm)form;
                  try{
                         //注冊一個解析器,我用的是apache xerces的,所以導(dǎo)入了org.apache.xerces.jaxp.*
                         XMLReader xmlReader=new SAXParserFactoryImpl().newSAXParser().getXMLReader();
                         //聲明一個XmlParseBusiness類,這個類就是我們自己的xml解析程序
    XmlParseBusiness xmlParseBusiness=new XmlParseBusiness();
    //把我們自己的解析程序注冊到解析器,告訴解析器誰來接收事件
                         xmlReader.setContentHandler(xmlParseBusiness);
                         //解析文件
                         // userForm.getFileName()是指定的xml文件名稱,本例子中就是book.xml
                         // getPath(servlet)方法找到book.xml的路徑
                         //.toURL().toString()把文件轉(zhuǎn)換成url形式
                         //parse()方法的參數(shù)為inputSource,可以是字符流,字節(jié)流或文件的url字符串,所以必須要把以上幾種轉(zhuǎn)換成inputSource
                         xmlReader.parse(new File(getPath(servlet)+"/WEB-INF/classes/"+userForm.getFileName()).toURL().toString());
                        
                         request.setAttribute("iValue",xmlParseBusiness.getI());
                         request.setAttribute("bookList",xmlParseBusiness.getBookList());
                         log.info("End xml parse: XmlParseAction.xmlParse()");
                  }catch(Exception ex){
                         System.out.println("Action Exception: xmlParse, caused by: "+ex);
                  }
                  return mapping.findForward("xmlParseResult");
           }
     
           /**
            * Return the absolute path of the servlet
            */
           //這個方法就是查找此應(yīng)用程序的絕對路徑,供解析用,因?yàn)閟ax不會自動識別上下文路徑
           private String getPath(Servlet servlet){
                  String strPath=servlet.getServletConfig().getServletContext().getRealPath("");
                  return strPath;
           }
     
    }
     
     
    文件XmlParseBusiness,接收解析事件,查找符合book,類型是fiction的內(nèi)容
     
    package myb.hi.sample.business;
     
    import java.util.*;
     
    import org.xml.sax.Attributes;
    import org.xml.sax.SAXException;
    import org.xml.sax.helpers.AttributesImpl;
    import org.xml.sax.helpers.DefaultHandler;
    // DefaultHandler是一個實(shí)現(xiàn)了ContentHander等接口的類,繼承這個類就不用挨個實(shí)現(xiàn)接口了 
    public class XmlParseBusiness extends DefaultHandler{
           //定義整形變量i,存放共有幾本書
           private int i=0;
           //接收標(biāo)簽內(nèi)容,因?yàn)閏haracters()方法是以字符流的形式接收內(nèi)容,如果用string,有可能造成內(nèi)容缺失
           private StringBuffer xmlContent=new StringBuffer();
           //聲明一個mapp對象,并不做初始化
           private HashMap bookMap=null;
           //定義list對象,存放書的列表
           private List bookList=new ArrayList();
           //定義堆棧,存放上下文信息。在解析過程中,我們需要記錄一些信息,比如我現(xiàn)在是在<book></book>之間,等等。堆棧是一個很好的辦法,他采用后進(jìn)先出,后面定義的方法,有他的實(shí)現(xiàn)
           private Stack context=new Stack();
          
           /**
            * Default Constructor
            */
           public XmlParseBusiness(){
                 
           }
          
           /**
            * Start Document
            */
           public void startDocument(){
                 
           }
          
           /**
            * End Document
            */
           public void endDocument(){
                 
           }
          
           /**
            * Start Element
            * @param uri
            * @param localName
            * @param qName
            * @param attr
            * @return void
            */
           public void startElement(String uri, String localName,String qName,Attributes attribute) throws SAXException{
                  //聲明一個ElementDetails類的實(shí)例,這個類存放的就是標(biāo)簽信息,目的是放到堆棧中
                  ElementDetails elem=new ElementDetails(uri, localName,qName, attribute);
                  //把信息推入堆棧
                  context.push(elem);
                  //如果標(biāo)簽是<book>,就執(zhí)行下面代碼
                  if(qName.equals("book")){
                         //如果book類型是fiction,就執(zhí)行下面代碼
                         if(isFictionBook()){
                                //初始化bookMap為一個map對象實(shí)例
                                bookMap=new HashMap();
                         }
                         //給i自增,代表又多了一本書
                         i++;
                  }
                  //給stringbuffer清空,以便接收新內(nèi)容
                  xmlContent.setLength(0);
           }
          
           /**
            * End Element
            */
           public void endElement(String uri, String localName,String qName) throws SAXException{
    //根據(jù)上下文做判斷,如果還在<book></book>之間
                  if(isBook()){
                         //如果是</title>
                         if(qName.equals("title")){
                                //把書名內(nèi)容放到map里
                                bookMap.put("title",xmlContent.toString());
                         //如果是</page>
                         }else if(qName.equals("page")){
                                //把書的頁數(shù)放到map里
                                bookMap.put("page",xmlContent.toString());
                         //如果是</author>
                         }else if(qName.equals("author")){
                                //把作者名稱放到map里
                                bookMap.put("author",xmlContent.toString());
                      //如果是</book>
                         }else if(qName.equals("book")){
                                //說明book標(biāo)簽結(jié)束了,把整本書放到列表里
                                bookList.add(bookMap);
                         }
                  }
                  //給stringbuffer清空,以便接收新內(nèi)容
                  xmlContent.setLength(0);
                  //把最后進(jìn)來的對象彈出堆棧,因?yàn)樗臉?biāo)簽已經(jīng)結(jié)束,沒有再存在的必要了(后進(jìn)先出
                  context.pop();
           }
          
           /**
            * Get i value
            */
           public int getI(){
                  return i;
           }
          
           /**
            *Handle the context between the element
            *@param ch[]
            *@param start
            *@param length
            *@return void
            */
            public void characters (char ch[], int start, int length) throws SAXException{
    //把標(biāo)簽內(nèi)容存到一個stringbuffer對象里,以備處理
                   xmlContent.append(ch,start,length);
            }
          
           /**
           * Get strA value
           */
           public String getContent(){
                  return xmlContent.toString();
           }
          
           /**
            * Return bookList
            */
           public List getBookList(){
                  return bookList;
           }
          
           /**
            * Define a internal Class, for transfor the element details
            */
           //定義一個內(nèi)部類,接收標(biāo)簽元素信息,供堆棧用
           private class ElementDetails {
                  private String uri;
                  private String localName;
                  private String qName;
                  private Attributes attribute;
                 
                  /*
                   * Defalut Constructor
                   */
                  public ElementDetails(String uri, String localName,String qName,Attributes attribute){
                         this.uri=uri;
                         this.localName=localName;
                         this.qName=qName;
                         //注意Attributes是一個接口,所以要把他轉(zhuǎn)化為一個AttributesImpl對象
                         this.attribute=new AttributesImpl(attribute);
                  }
     
     
                  public Attributes getAttribute() {
                         return attribute;
                  }
     
     
                  public void setAttribute(Attributes attribute) {
                         this.attribute = new AttributesImpl(attribute);
                  }
     
     
                  public String getLocalName() {
                         return localName;
                  }
     
                  public void setLocalName(String localName) {
                         this.localName = localName;
                  }
     
                  public String getQName() {
                         return qName;
                  }
     
                  public void setQName(String name) {
                         qName = name;
                  }
     
                  public String getUri() {
                         return uri;
                  }
     
                  public void setUri(String uri) {
                         this.uri = uri;
                  }    
           }
          
           /**
            * Estimate the element content, if it's 'book', return true, otherwise, false
            */
           //利用堆棧,判斷是否還在<book></book>之間
           private Boolean isBook(){
                  //判斷堆棧里對象數(shù)目,并做循環(huán)
                  for(int p=context.size()-1;p>=0;p--){
                         //把位置p出的對象取出來,是一個ElementDetails類的實(shí)例
                         ElementDetails elem=(ElementDetails)context.elementAt(p);
                         //如果這個標(biāo)簽的信息是<book>,返回true,不用再往下循環(huán)了。因?yàn)?lt;/book>后,會被彈出堆棧,所以不會有2個<book>在堆棧里。除非xml不規(guī)范,有相同的標(biāo)簽嵌套出現(xiàn),像<book><book></book></book>這樣,但是在這里因?yàn)楹筮M(jìn)先出的原則不會出問題,相反程序里的其他判斷就要出亂子了
                         if(elem.getQName().equals("book")){
                                return true;
                         }
                  }
                  return false;
           }
     
           /**
            * Estimate the element content, if it's a "fiction book", return true, otherwise, false
            */
           private Boolean isFictionBook(){
                  for(int p=context.size()-1;p>=0;p--){
                         ElementDetails elem=(ElementDetails)context.elementAt(p);
                         if(elem.getQName().equals("book") && elem.getAttribute().getValue("type").equals("fiction")){
                                return true;
                         }
                  }
                  return false;
           }
    }
     
    注意:上面程序只實(shí)現(xiàn)了ContentHandler接口的部分方法。并且對帶dtd驗(yàn)證的xml解析,以及錯誤處理沒有做講解和實(shí)例,感興趣的朋友可以自己去參考文檔。不過對于解析簡單的xml配置文檔,這些也足夠了。
     
    Sax的api包含在j2se的api文擋中,在org.xml.sax包里。apache的xerces包,ibm,oracle等廠商發(fā)行的xml解析器包都會包含他。
    Xerces是apache的子項(xiàng)目,專門做xml解析,他不僅包含了sax實(shí)現(xiàn),也包含了dom實(shí)現(xiàn)。
    最后講一下sax1和sax2的幾點(diǎn)差別:
    1. sax2中,用XMLReader代替了Parser
    2. sax2支持namespace
    3. sax2中用ContentHandler代替了DocumentHandler
    4. sax2 DefaultHandler代替了HandlerBase



     

    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1486724

    posted on 2007-04-06 13:07 蘆葦 閱讀(3944) 評論(0)  編輯  收藏 所屬分類: JAVA其他
    主站蜘蛛池模板: 国产精品国产亚洲区艳妇糸列短篇 | 亚洲噜噜噜噜噜影院在线播放| 亚洲 自拍 另类小说综合图区| 性xxxxx免费视频播放 | 亚洲AV无码一区二区三区系列| 国产一级一片免费播放i| 狼群影院在线观看免费观看直播| 国产特黄一级一片免费| 特级av毛片免费观看| 亚洲一区二区三区四区视频 | 黄色视屏在线免费播放| 亚洲成a人无码亚洲成www牛牛| 亚洲色偷偷av男人的天堂| 国产亚洲精品a在线观看 | 久久久久亚洲精品无码网址色欲 | 又黄又大的激情视频在线观看免费视频社区在线 | 亚洲aⅴ无码专区在线观看| 亚洲三级在线视频| 77777_亚洲午夜久久多人| 亚洲日韩一页精品发布| MM131亚洲国产美女久久| 免费观看日本污污ww网站一区| 中文字幕无码视频手机免费看| 91免费福利精品国产| 久久99热精品免费观看牛牛| 全黄大全大色全免费大片| 一级一看免费完整版毛片| 丰满妇女做a级毛片免费观看| 精品韩国亚洲av无码不卡区| 亚洲av永久无码精品网址| 亚洲国产高清国产拍精品| 亚洲精品无码成人片久久不卡| 亚洲一级视频在线观看| 亚洲国产精品久久久久秋霞影院 | 在线观看免费视频网站色| 国产精品免费看久久久香蕉| 亚美影视免费在线观看| 国产福利电影一区二区三区,免费久久久久久久精 | 亚洲国产成人手机在线观看 | 国产免费av一区二区三区| 国产免费观看黄AV片|