SAX 2.0 - Simple API for XML

一.什么是SAX?

  SAX(Sample API for XML),即“XML简单API”,它是由一组接口和类构成的,用于提供一种解析XML文档的方法。我们知道XML是用一种层次化的结构来存储数据的,解析的意思就是用某种方法来提取出其中的元素,属性和数据,以便用这些信息进行进一步的操作,比如用提取出的某些符合条件的信息与客户端交互。解析的方法除了SAX方法外,还有DOM(Document Object Model)。这两种方法差别很大:SAX是基于事件的方法,它很类似于标签库的处理机制,在标签开始,标签结束以及错误发生等等地方调用相应的接口实现方法。这就给我们提供了一个可以分析元素和数据的机会。SAX是顺序的,层次化的分析XML文档,着眼于当前的事件连续的处理,不是全部文档都读入内存,而DOM的做法正是将XML文档元素全部读入内存,生成一棵包含全部内容的树,以便全局的控制各个节点元素。解析一个XML文档需要借助XML解析器来完成,它将验证文档的结构是否良好。有些解析器还具有验证功能(带有或打开验证功能的解析器称为验证解析器或有效解析器;不带验证功能的解析器称为未验证解析器或无效解析器),可以进一步验证文档的有效性。比较常用的解析器有Apache Xerces,IBM XML4J,Sun ProjectX,Oracle XML Parser等等,基于性能和规范性的考虑,这里使用Apache Xerces。

二.常用SAX 2.0 API

org.xml.asx.Attrbutes 接口:用于得到属性的个数,名字和值。
org.xml.asx.ContentHandler 接口:定义了处理XML文档所能调用的事件方法。
org.xml.asx.DTDHandler 接口:定义了解析DTD时所能调用的事件方法。
org.xml.sax.EntityResolver 接口:用来处理调用外部实体事件。
org.xml.sax.ErrorHandler 接口:定义了三种级别的异常事件。
org.xml.sax.InputSource 类:用于封装压缩XML文档,供SAX解析器输入。
org.xml.sax.Locator 类:用于对解析过程进行定位,可以取得当前行数等信息。
org.xml.sax.SAXException 类:SAX的异常基础。
org.xml.sax.SAXNotRecongnizedException 类:发现不可识别的标示符异常。
org.xml.sax.SAXNotSupportedException 类:发现可识别但是不支持的标示符异常。
org.xml.sax.SAXParseException 类:解析过程中发生异常。
org.xml.sax.XMLFilter 接口:用来取得XMLReader自身信息。
org.xml.sax.XMLReader 类:用于解析XML文档。
org.xml.sax.helpers.XMLReaderAdapter 类:用SAX1.0的格式执行SAX2.0 XMLReader
org.xml.sax.helpers.XMLReaderFactory 类:动态创建XMLReader实例。

三.解析XML的例子

  这个例子演示了使用Apache Xerces解析器对存有学生资料的XML文档进行解析,并将解析后得到的数据显示出来。

---------- SutInfo.xml ----------

<? xml version="1.0" ?>
<? xml-stylesheet href="xslStuInfo.xsl" type="text/xsl" ?>
<! DOCTYPE LIT:StuInfo SYSTEM "dtdstudent.dtd" >

< LIT:StuInfo  xmlns:LIT ="http://www.lit.edu.cn/student/" >
    
    
< LIT:student >
        
< LIT:name > bigmouse </ LIT:name >
        
< LIT:sex > male </ LIT:sex >
        
< LIT:lesson >
            
< LIT:lessonName > math </ LIT:lessonName >
            
< LIT:lessonScore > 60 </ LIT:lessonScore >
        
</ LIT:lesson >
        
< LIT:lesson >
            
< LIT:lessonName > Englist </ LIT:lessonName >
            
< LIT:lessonScore > 59 </ LIT:lessonScore >
        
</ LIT:lesson >
        
< LIT:lesson >
            
< LIT:lessonName > autoCAD </ LIT:lessonName >
            
< LIT:lessonScore > 80 </ LIT:lessonScore >
        
</ LIT:lesson >
        
< LIT:lesson >
            
< LIT:lessonName > SCM </ LIT:lessonName >
            
< LIT:lessonScore > 90 </ LIT:lessonScore >
        
</ LIT:lesson >
        
< LIT:lesson >
            
< LIT:lessonName > mechanics </ LIT:lessonName >
            
< LIT:lessonScore > 61 </ LIT:lessonScore >
        
</ LIT:lesson >
    
</ LIT:student >

    
< LIT:breakLine />

    
< LIT:student >
        
< LIT:name > coco </ LIT:name >
        
< LIT:sex > female </ LIT:sex >
        
< LIT:lesson >
            
< LIT:lessonName > math </ LIT:lessonName >
            
< LIT:lessonScore > 90 </ LIT:lessonScore >
        
</ LIT:lesson >
        
< LIT:lesson >
            
< LIT:lessonName > Englist </ LIT:lessonName >
            
< LIT:lessonScore > 95 </ LIT:lessonScore >
        
</ LIT:lesson >
        
< LIT:lesson >
            
< LIT:lessonName > C++ </ LIT:lessonName >
            
< LIT:lessonScore > 80 </ LIT:lessonScore >
        
</ LIT:lesson >
        
< LIT:lesson >
            
< LIT:lessonName > Java </ LIT:lessonName >
            
< LIT:lessonScore > 85 </ LIT:lessonScore >
        
</ LIT:lesson >
    
</ LIT:student >

    
< LIT:breakLine />

    
< LIT:master > &masterName; </ LIT:master >

</ LIT:StuInfo >

---------- StuInfo.xsl ----------

<? xml version="1.0" ?>

< xsl:stylesheet  xmlns:xsl ="http://www.w3.org/1999/XSL/Transform"
        xmlns:LIT
="http://www.lit.edu.cn/student/"
        version
="1.0" >

    
< xsl:template  match ="LIT:StuInfo" >
        
< html >
            
< head >
                
< title > Student Information </ title >
            
</ head >
            
< body >
                
< xsl:apply-templates  select ="*" />
            
</ body >
        
</ html >
    
</ xsl:template >

    
< xsl:template  match ="LIT:student" >
        
< li > Name: < xsl:value-of  select ="LIT:name" /></ li >
        
< li > Sex: < xsl:value-of  select ="LIT:sex" /></ li >
        
< xsl:for-each  select ="LIT:lesson" >
            
< li > Lesson: < xsl:value-of  select ="LIT:lessonName" /> ( < xsl:value-of  select ="LIT:lessonScore" /> ) </ li >
        
</ xsl:for-each >
    
</ xsl:template >

    
< xsl:template  match ="LIT:breakLine" >
        
< hr />
    
</ xsl:template >

    
< xsl:template  match ="master" >
        
< xsl:copy-of  select ="*" />
    
</ xsl:template >

</ xsl:stylesheet >

---------- student.dtd ----------

<! ELEMENT LIT:StuInfo ((LIT:student, LIT:breakLine)*, LIT:master) >
<! ATTLIST LIT:StuInfo xmlns:LIT CDATA #REQUIRED >
<! ELEMENT LIT:student (LIT:name, LIT:sex, LIT:lesson*) >
<! ELEMENT LIT:name (#PCDATA) >
<! ELEMENT LIT:sex (#PCDATA) >
<! ELEMENT LIT:lesson (LIT:lessonName, LIT:lessonScore) >
<! ELEMENT LIT:lessonName (#PCDATA) >
<! ELEMENT LIT:lessonScore (#PCDATA) >
<! ELEMENT LIT:breakLine EMPTY >
<! ELEMENT LIT:master (#PCDATA) >
<! ENTITY masterName SYSTEM "master.txt" >

 ---------- MySAXParser.java ----------
import  java.io. * ;
import  org.xml.sax. * ;
import  org.xml.sax.helpers. * ;

public   class  MySAXParser
{
  
public MySAXParser()
  
{
  }


  
public static void main(String[] args)
  
{
    
if (args.length != 1)
    
{
      System.out.println(
"Usage:java MySAXParser XMLFileURI");
      System.exit(
0);
    }


    MySAXParser mySAXParser 
= new MySAXParser();
    mySAXParser.parserXMLFile(args[
0]);
  }


  
/**
   * 解析文档
   * 
@param fileURI XML文档的URI
   
*/

  
private void parserXMLFile(String fileURI)
  
{
    
try
    
{
      
//通过指定解析器的名称来动态加载解析器
      XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");

      
//处理内容前要注册内容管理器
      parser.setContentHandler(new MyContentHandler());

      
//处理错误前要注册错误管理器
      parser.setErrorHandler(new MyErrorHandler());

      
//处理DTD前要注册DTD管理器
      parser.setDTDHandler(new MyDTDHandler());

      
//打开解析器的验证
      parser.setFeature("http://xml.org/sax/features/validation"true);

      
//开始解析文档
      parser.parse(fileURI);
    }

    
catch (IOException ioe)
    
{
      System.out.println(ioe.getMessage());
    }

    
catch (SAXException saxe)
    
{
      System.out.println(saxe.getMessage());
    }

  }

}


----------  MyContentHandle.java  ----------

import  org.xml.sax.Locator;
import  org.xml.sax.Attributes;
import  org.xml.sax.ContentHandler;
import  org.xml.sax.SAXException;

public   class  MyContentHandler  implements  ContentHandler
{
  
//DTD中定义的元素
  private static final String ELEMENT_NAME = "name";
  
private static final String ELEMENT_SEX = "sex";
  
private static final String ELEMENT_LESSON = "lesson";
  
private static final String ELEMENT_LESSON_NAME = "lessonName";
  
private static final String ELEMENT_LESSON_SCORE = "lessonScore";
  
private static final String ELEMENT_STUDENT = "student";
  
private static final String ELEMENT_LINE = "breakLine";

  
private String currentData = "";  //当前元素的数据
  private String lessonName = "";
  
private String lessonScore = "";

  
public MyContentHandler()
  
{
  }


  
/**
   * 当其他某一个调用事件发生时,先调用此方法来在文档中定位。
   * 
@param locator
   
*/

  
public void setDocumentLocator(Locator locator)
  
{

  }


  
/**
   * 在解析整个文档开始时调用
   * 
@throws SAXException
   
*/

  
public void startDocument() throws SAXException
  
{
    System.out.println(
"**** Student information start ****");
  }


  
/**
   * 在解析整个文档结束时调用
   * 
@throws SAXException
   
*/

  
public void endDocument() throws SAXException
  
{
    System.out.println(
"**** Student information end ****");
  }


  
/**
   * 在解析名字空间开始时调用
   * 
@param prefix
   * 
@param uri
   * 
@throws SAXException
   
*/

  
public void startPrefixMapping(String prefix, String uri) throws SAXException
  
{

  }


  
/**
   * 在解析名字空间结束时调用
   * 
@param prefix
   * 
@throws SAXException
   
*/

  
public void endPrefixMapping(String prefix) throws SAXException
  
{

  }


  
/**
   * 在解析元素开始时调用
   * 
@param namespaceURI
   * 
@param localName
   * 
@param qName
   * 
@param atts
   * 
@throws SAXException
   
*/

  
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException
  
{

  }


  
/**
   * 在解析元素结束时调用
   * 
@param namespaceURI
   * 
@param localName 本地名,如student
   * 
@param qName 原始名,如LIT:student
   * 
@throws SAXException
   
*/

  
public void endElement(String namespaceURI, String localName, String qName) throws SAXException
  
{
    
if (localName.equals(ELEMENT_NAME))
    
{
      System.out.println(localName 
+ ":" + currentData);
    }


    
if (localName.equals(ELEMENT_SEX))
    
{
      System.out.println(localName 
+ ":" + currentData);
    }


    
if (localName.equals(ELEMENT_LESSON_NAME))
    
{
      
this.lessonName = currentData;
    }


    
if (localName.equals(ELEMENT_LESSON_SCORE))
    
{
      
this.lessonScore = currentData;
    }


    
if (localName.equals(ELEMENT_LESSON))
    
{
      System.out.println(lessonName 
+ ":" + lessonScore);
    }


    
if (localName.equals(ELEMENT_LINE))
    
{
      System.out.println(
"------------------------------------");
    }

  }


  
/**
   * 取得元素数据
   * 
@param ch
   * 
@param start
   * 
@param length
   * 
@throws SAXException
   
*/

  
public void characters(char[] ch, int start, int length) throws SAXException
  
{
    currentData 
= new String(ch, start, length).trim();
  }


  
/**
   * 取得元素数据中的空白
   * 
@param ch
   * 
@param start
   * 
@param length
   * 
@throws SAXException
   
*/

  
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
  
{

  }


  
/**
   * 在解析到处理指令时,调用此方法。
   * 这些处理指令不包括XML的版权指令,它由解析器本身识别。
   * 
@param target
   * 
@param data
   * 
@throws SAXException
   
*/

  
public void processingInstruction(String target, String data) throws SAXException
  
{

  }


  
/**
   * 当未验证解析器忽略实体时调用此方法
   * 
@param name
   * 
@throws SAXException
   
*/

  
public void skippedEntity(String name) throws SAXException
  
{

  }

}


----------  MyErrorHandler.java  ----------

import  org.xml.sax.SAXException;
import  org.xml.sax.SAXParseException;
import  org.xml.sax.ErrorHandler;
public   class  MyErrorHandler  implements  ErrorHandler
{

  
public MyErrorHandler()
  
{
  }


  
/**
   * XML的警告信息
   * 
@param exception
   * 
@throws SAXException
   
*/

  
public void warning(SAXParseException exception) throws SAXException
  
{
    System.out.println(
"!!!WARNING!!!");
    System.out.println(exception.getLineNumber() 
+ ":(" + exception.getSystemId() + ")" + exception.getMessage());
  }


  
/**
   * 不符合XML规范时调用此方法
   * 
@param exception
   * 
@throws SAXException
   
*/

  
public void error(SAXParseException exception) throws SAXException
  
{
     System.out.println(
"!!!ERROR!!!");
    System.out.println(exception.getLineNumber() 
+ ":(" + exception.getSystemId() + ")" + exception.getMessage());
  }


  
/**
   * 非良构的文档时调用此方法
   * 
@param exception
   * 
@throws SAXException
   
*/

  
public void fatalError(SAXParseException exception) throws SAXException
  
{
     System.out.println(
"!!!FATAL!!!");
    System.out.println(exception.getLineNumber() 
+ ":(" + exception.getSystemId() + ")" + exception.getMessage());
  }

}

---------- MyDTDHandler.java ----------

 

import  org.xml.sax.SAXException;
import  org.xml.sax.DTDHandler;

public   class  MyDTDHandler  implements  DTDHandler
{

  
public MyDTDHandler()
  
{
  }


  
/**
   * 当实体声明为不必解析的实体时调用此方法,比如NDATA类型。
   * 
@param name
   * 
@param publicId
   * 
@param systemId
   * 
@throws SAXException
   
*/

  
public void notationDecl(String name, String publicId, String systemId) throws SAXException
  
{
    System.out.println(
"**notationDecl**");
    System.out.println(
"name:" + name);
    System.out.println(
"publicId" + publicId);
    System.out.println(
"systemId:" + systemId);
  }


  
/**
   * 当处理符号声明时调用此方法,比如NOTATION。
   * 
@param name
   * 
@param publicId
   * 
@param systemId
   * 
@param notationName
   * 
@throws SAXException
   
*/

  
public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) throws SAXException
  
{
    System.out.println(
"**unparsedEntityDecl**");
    System.out.println(
"name:" + name);
    System.out.println(
"publicId" + publicId);
    System.out.println(
"systemId:" + systemId);
    System.out.println(
"notationName:" + notationName);
  }

}


---------- 解析后得到结果 ----------

**** Student information start ****
name:bigmouse
sex:male
math:60
Englist:59
autoCAD:80
SCM:90
mechanics:61
------------------------------------
name:coco
sex:female
math:90
Englist:95
C++:80
Java:85
------------------------------------
**** Student information end ****


四.关于其他技术

  上面介绍了SAX解析XML文档的方法,它不将整个文档放入内存,而是以基于事件的方式来处理文档,因此在速度和性能上优于DOM。但是在可读性上,SAX却不如DOM操作清楚简单。因此在文档不是特别大的时候,还是采用DOM方法比较合适。另外还有一种解析XML的API -- JDOM,它是一种基于Java2的完整API,同样具有SAX的高效,快速的特点,而且还可以像DOM那样从整体上操纵文档,提供一种比DOM更简单的生成和访问元素节点的方法。我将会在以后的文章中介绍DOM,JDOM以及JAXP等技术。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值