XML文件解析技术:SAX解析(一)

SAX解析:非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说, SAX 还比它的替代者 DOM 快许多。
  
 选择 DOM 还是选择 SAX ?
对于需要自己编写代码来处理 XML 文档的开发人员来说,选择 DOM 还是 SAX 解析模型是一个非常重要的设计决策。
区别:
   DOM 采用建立树形结构的方式访问 XML 文档,而 SAX 采用的事件模型。   
       DOM 解析器把 XML 文档转化为一个包含其内容的树,并可以对树进行遍历。
用 DOM 解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用 DOM 解析器的时候需要处理整个 XML 文档,所以对性能和内存的要求比较高,尤其是遇到很大的 XML 文件的时候。由于它的遍历能力,DOM 解析器常用于 XML 文档需要频繁的改变的服务中。

       SAX 解析器采用了基于事件的模型,它在解析 XML 文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX 对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX 这种扩展能力得到了更好的体现。
但是用 SAX 解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。
准备活动
1. java.util.Stack<E>java.util.Vector的子类。<E>
    Stack 类表示后进先出(LIFO)的对象堆栈。它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈。它提供了通常的 push()pop() 操作,以及取栈顶点的 peek() 方法,测试堆栈是否为空的 empty()方法、在堆栈中查找项并确定到栈顶距离的 search 方法。 
   首次创建堆栈时,它不包含数据项。
2.       org.xml.sax.helpers.DefaultHandler
public class DefaultHandler
extends Object
implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler
startElement();接收元素开始的通知。
characters();//接收元素中字符数据的通知。
例如:
创建 H://zmb//Sweet_ForTest_back//source.xml
<?xml version="1.0" encoding="SHIFT_JIS"?>
   <elements>
        <H-element id="h1">
             <moto>_ExtentX</moto>
             <pattern>_ExtentX</pattern>
             <saki>_cx</saki>
        </H-element>
         <H-element id="h2">
             <moto>_ExtentY</moto>
             <pattern>_ExtentY</pattern>
             <saki>_cy</saki>
         </H-element>
               <B-element >
                                    <moto>.Col2</moto>
                                    <pattern>//.Col2</pattern>
                                  <saki>.ColSel</saki>
                   </B-element >
                     <B-element >
                                   <moto>.MaxRows</moto>
                                <pattern>//.MaxRows</pattern>
                                  <saki>.Rows</saki>
                       </B-element >
</elements>
 
解析类:
 package doxml;
import java.util.ArrayList;
         import java.util.HashMap;
         import java.util.List;
         import java.util.Stack;
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.AttributesImpl;
         import org.xml.sax.helpers.DefaultHandler;
public class SrcXMLParse extends DefaultHandler {
 
 
 private int iHeader = 0;
 private int iBody = 0;
 // 接收标签内容,因为characters()方法是以字符流的形式接收内容,
 // 如果用string,有可能造成内容缺失
 private StringBuffer xmlContent = new StringBuffer();
 // 声明一个map对象,并不做初始化
 private HashMap<String,String> elementMap = null;
 // 定义list对象,存放xml文件内容的列表
 private List<HashMap<String,String>> headerElementList = new ArrayList<HashMap<String,String>>();
 private List<HashMap<String,String>> bodyElementList = new ArrayList<HashMap<String,String>>();
 
 private Stack<ElementDetails> context = new Stack<ElementDetails>();
 
 /** Default Constructor  */
 public SrcXMLParse(){
  
 }
 /** * Start Document */
 public void startDocument() {
 }
 /** * End Document */
 public void endDocument() {
 }
 
 
 /**  Start Element */
 public void startElement(String uri, String localName, String qName,
   Attributes attribute) throws SAXException {
  // 声明一个ElementDetails类的实例,
  // 这个类存放的就是标签信息,目的是放到堆栈中
  ElementDetails elem = new ElementDetails(uri, localName, qName,
    attribute);
  // 把信息推入堆栈
  context.push(elem);
  if (qName.equals("H-element")) {
   elementMap = new HashMap<String, String>();
   iHeader ++;
  }else if(qName.equals("B-element")){
   elementMap = new HashMap<String, String>();
   iBody ++;
  }
  // 给stringbuffer清空,以便接收新内容
  xmlContent.setLength(0);
 }
 /** * End Element */
 public void endElement(String uri, String localName, String qName)
   throws SAXException {
  // 如果是</moto>
  if (qName.equals("moto")) {
   
   elementMap.put("moto", xmlContent.toString());
   // 如果是</pattern>
  } else if (qName.equals("pattern")) {
   
   elementMap.put("pattern", xmlContent.toString());
   // 如果是</saki>
  } else if (qName.equals("saki")) {
   
   elementMap.put("saki", xmlContent.toString());
   // 如果是</H-element>
  } else if (qName.equals("H-element")) {
   // 说明B-element标签结束了,把内容放到列表里(解析的结果---我们的目标)
   headerElementList.add(elementMap);
  } else if(qName.equals("B-element")){
//(解析的结果---我们的目标)
   bodyElementList.add(elementMap);
  }
        //给stringbuffer清空,以便接收新内容             
  xmlContent.setLength(0);             
  //把最后进来的对象弹出堆栈,因为他的标签已经结束,没有再存在的必要了(后进先出)             
  context.pop();
 }
 
 /**
  * *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 {
  // 把标签内容存到一个stringbuffer对象里,以备处理
  xmlContent.append(ch, start, length);
 }
 
 /** * Get strA value */
 public String getContent() {
  return xmlContent.toString();
 }
 /** * Return headerElementList*/
 public List<HashMap<String,String>> getHeaderElementList() {
  return headerElementList;
 }
 /** * Return bodyElementList*/
 public List<HashMap<String,String>> getBodyElementList() {
  return bodyElementList;
 } 
 // 定义一个内部类,接收标签元素信息,供堆栈用
 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是一个接口,所以要把他转化为一个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;
  }
 }
 
 public static void main(String[] args) {
  
  SrcXMLParse xmlParse = new SrcXMLParse();  
  SAXParserFactory factory = SAXParserFactory.newInstance();
  String absFilePath = "H://zmb//Sweet_ForTest_back//source.xml";
  try {
   SAXParser parser = factory.newSAXParser();
   parser.parse(absFilePath, xmlParse);
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 
 }
}
另外startElement方法中的
            String attName = attrs.getQName(0);
            String attValue = attrs.getValue(0);
也是经常使用到的。
例如
publicvoid startElement(String uri, String localName, String qName,
            Attributes attrs) {
        tags .push(qName); // 把项压入栈顶
        // System.out.println(qName);
        if (qName.equals( "emp" )) {
            String attName = attrs.getQName(0);
            String attValue = attrs.getValue(0);
            System. out .print( " <" + qName + " " );
            System. out .println(attName + "=/"" + attValue + "/">" );
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值