当前位置: 首页 > news >正文

SAX(三个实例)

 SAX(Simple API for XML)由XML-DEV邮件列表成员开发,目前版本2.0.x,民间标准.http://www.saxproject.org/
SAX是一种基于事件驱动的API。利用SAX解析XML文档牵涉到两个部分:解析器和事件处理器。
解析器负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件;而事件处理器则负责对事件作出相应,对传递的XML数据进行处理。

SAX特点:操作XML时不同全部读取到内存中。

SAX的处理机制:
Java代码
  1. <?xml version="1.0" encoding="gb2312"?>   
  2. <student>   
  3.    <name>张三</name>   
  4. </student>  

Java代码
  1. 文档开始   
  2.   元素开始(<student>)   
  3.     字符空白(">""<"之间的空白)   
  4.        元素开始(<name>)   
  5.           字符数据(张三)   
  6.        元素结束(</name>)   
  7.     字符空白(">""</"之间的空白)   
  8.   元素结束(</student>)   
  9. 文档结束  

SAX解析器接口和事件处理器接口在org.xml.sax包中定义。
XMLReader是SAX2.0解析器必须实现的接口。该接口允许应用程序设置和查询解析器的功能和特性,注册处理文档的事件处理器,以及启动文档的解析。

解析器提供商负责提供实现XMLReader接口的解析器类,我们只需编写事件处理器程序。
SAX API中的ContnetHandle接口是一个主要的处理器接口。如果应用程序要获得基本的解析事件就必须实现该接口,并使用XMLReader对象的setContentHandler()向解析器注册一个ContentHandler()实例。解析器使用这个实例来报告与文档相关的基本事件,例如,元素开始和结束,以及字符数据等。在这个接口中,事件的顺序是非常重要的,它反映了文档自身信息的顺序。例如,元素的所有内容(字符数据,处理指令,子元素)都依次在startElement事件和对应的endElement事件之间出现。

void setDocumentLocator(Locator locator)
该方法接收一个用于获取文档分析时产生的SAX事件定位信息的对象。该方法将在解析器报告任何其他文档事件之前被调用。作为参数传递给这个方法的定位器对象,允许应用程序测定任何与文档相关的事件的结束位置。通常,应用程序会使用这个信息来报告它自身的错误(例如,与应用程序的商业规则不匹配的字符内容)。

void startDocument() throws SAXException
该方法接收文档开始的通知。SAX解析器将在任何其它事件回调方法被调用之前调用该方法(除了setDocumentLocator方法),并只调用一次。

void endDocument() throws SAXException
该方法接收文档结束的通知。SAX解析器只调用这个方法一次,而且它是在解析过程中最后一次被调用的方法。

void startPrefixMapping(String prefix,String uri)throws SAXException
void endPrefixMapping(String prefix)throws SAXException
startPrefixMapping()在一个前缀-URI名称空间映射范围的开始时被调用。而endPrefixMapping()在前缀-URI映射范围结束时被调用。例如:下面的XML文档
<students xmlns:stu="http://www.javaeye.com/students">
   .....
</students>
SAX解析器在分析到<students>元素时,就会调用startPrefixMapping(),将stu传递给prefix参数,将http://www.javaeye.com/students传递给uri参数,然后产生<students>元素的startElement事件。在产生<students>元素的endElement事件后,解析器将调用endPrefixMapping(),将stu传递给prefix参数。

void startElement(String uri,String localName,String qName,Attribute atts)throws SAXException
该方法接收元素开始的通知。解析器在xml文档的每一个元素开始时调用这个方法。每一个startElement事件都有一个对应的endElement事件(即使是空元素),在endElement事件之前,元素的所有内容都被依次报告。
这个事件允许每个元素最多有三个名称部分:1.名称空间URI;2.本地名;3.限定名;是否有这几部分,取决于http://xml.org/sax/features/namespaces和http://xml.org/sax/features/namespace-prefixes属性的值.
a.当namespaces属性为true时,名称空间URI和本地名是必须的。当namespaces属性是false,那么二者是可选的(但如果指定了其中一个名称,那么另一个也必须指定)
b.当namespace-prefixes属性为true,那么限定名必需的,否则是可选的,缺省值为false.
注意:属性列表将只包含具有确切值(直接指定或缺省值)的属性,#IMPLIED属性将被忽略。只有当http://xml.org/sax/features/namespace-prefixes属性为true(缺省值为false,解析器对true值的支持是可选的),属性列表才会包括用于名称空间声明的属性(xmlns*属性)

void endElement(String uri,String localName,String qName) throws SAXException
该方法接收元素结束的通知。解析器在XML文档的每一个元素结束时调用这个方法。

void characters(char[] ch,int start,int length)throws SAXException
该方法接收字符数据的通知。解析器调用这个方法来报告字符数据块。SAX解析器会把所有连续的字符数据放在一个单独的块中返回,或者把它们分成几个数据块。不过,在任何一个单独的所有字符都必须来自同一个外部实体,以便Locator提供有用的信息(Locator要提供文档中事件结束的位置信息)。应用程序不要试图读取ch数组中指定范围以外的的数据。注意:有些解析器使用ignorableWhitespace()来报告元素内容中的空白,而不是用characters()(进行有效性验证的解析器就是如此)。

void processingInstruction(String target,String data)throws SAXException
该方法接收处理指令的通知。解析器每遇到一个处理指令就调用该方法一次。注意:处理指令可以在XML文档的根元素(文档元素)之前或之后出现。

void skippedEntity(String name)throws SAXException
该方法接收跳过的实体的通知。解析器每跳过一个实体就会调用该方法。非验证的解析器如果没有看到实体声明的话(例如实体在外部的DTD子集中的声明),可以跳过实体。所有的处理器是否跳过外部的实体取决于http://xml.org/sax/features/external-general-entities和http://xml.org/sax/features/exteral-parameter-entities属性(property)的值。

配置SAX解析器有两种方法:功能和特性。
功能包括打开和关闭某个功能。例如验证。
特性包括设置解析器所使用的特定项的值,例如设置SAX词法分析器实例。
1.功能(feature)是通过XMLReader接口中的setFeature()来设置的,例如要打开验证功能可调用setFeature(): xmlReader.setFeature("http://xml.org/sax/feature/validation",true);

注意:在SAX中每一个功能都是由一个特定的URI来标识,当前的标准功能的URI都以http://xml.org/sax/features/作为前缀,下面列出常用功能的URI:
-http://xml.org/sax/features/namespaces
如果namespace为true,则解析器执行名称空间处理。在事件处理器的相应方法中,所有元素和属性的名称空间URI和未限定的本地名称可以使用。任何SAX2.0兼容的解析器都支持将namespaces的默认值设成true。
-http://xml.org/sax/features/namespace=prefixes
如果namespace-prefixes设为true时,则解析器对名称空间前缀的解析提供支持。在事件处理器的相应方法中,XML限定名(带前缀的名称)和属性(包括xmlns*属性)将可以使用。任何SAX2.0兼容的解析器都支持将namespace-prefixes的默认值设为false。
-http://xml.org/sax/features/external-general-entities
设置解析器是否处理外部的一般实体。如果对解析器启用了验证功能。则external-general-entities将总是true。
-http://xml.org/sax/features/external-parameter-entities
设置解析器是否处理外部的参数实体。如果对解析器启用了验证功能。则external-general-entities将总是true。
-http://xml.org/sax/features/validation
设置解析器是否验证文档。如果为true,则所有的外部实体都将被处理。

2.特性(property)是通过XMLReader接口中的setProperty()来设置的。特性和功能的设置是类似的,区别是特性以对象作为参数,而功能以布尔值作为参数。例如要设置词法分析器实例 ,可调用setProperty(): xmlReader.setProperty("http://xml.org/sax/properties/lexical-handle",new MyLexicalHandler());

SAX解析器工厂:javax.xml.parsers.SAXParserFactory
如果使用Apache的Xerces解析器,可配置如下:
javax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl

SAX实例一:
SAXPrinter.java输出跟students.xml一样的数据。
Java代码
  1. import java.io.File;   
  2. import java.io.IOException;   
  3. import javax.xml.parsers.ParserConfigurationException;   
  4. import javax.xml.parsers.SAXParser;   
  5. import javax.xml.parsers.SAXParserFactory;   
  6. import org.xml.sax.Attributes;   
  7. import org.xml.sax.SAXException;   
  8. import org.xml.sax.helpers.DefaultHandler;   
  9.   
  10. //重写了DefaultHandler的5个方法   
  11. public class SAXPrinter extends DefaultHandler{   
  12.   
  13.     @Override  
  14.     //文档开始   
  15.     public void startDocument() throws SAXException {   
  16.         //输出双引号可以用反斜杠也可输出单引号   
  17.         System.out.println("<?xml version=/"1.0/" encoding='gb2312'?>");   
  18.     }   
  19.        
  20.     @Override  
  21.     //处理指令   
  22.     public void processingInstruction(String target, String data) throws SAXException {   
  23.         System.out.println("<?"+target+" "+data+"?>");   
  24.     }   
  25.        
  26.     @Override  
  27.     //元素开始   
  28.     public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {   
  29.         System.out.print("<"+qName);   
  30.         int len = attrs.getLength();   
  31.         for(int i=0;i<len;i++){   
  32.             System.out.print(" ");   
  33.             System.out.print(attrs.getQName(i));   
  34.             System.out.print("=/"");   
  35.             System.out.print(attrs.getValue(i));   
  36.             System.out.print("/"");   
  37.         }   
  38.         System.out.print(">");   
  39.     }   
  40.        
  41.     @Override  
  42.     //处理字符(由空白组成的数据,可以看成格式)   
  43.     public void characters(char[] ch, int start, int length) throws SAXException {   
  44.         System.out.print(new String(ch,start,length));   
  45.     }   
  46.   
  47.   
  48.     @Override  
  49.     //元素结束   
  50.     public void endElement(String uri, String localName, String qName) throws SAXException {   
  51.         System.out.print("</"+qName+">");   
  52.     }   
  53.   
  54.     public static void main(String[] args) {   
  55.         SAXParserFactory spf = SAXParserFactory.newInstance();   
  56.         try {   
  57.             SAXParser sp = spf.newSAXParser();   
  58.             sp.parse(new File("students.xml"),new SAXPrinter());   
  59.         } catch (ParserConfigurationException e) {   
  60.             // TODO 自动生成 catch 块   
  61.             e.printStackTrace();   
  62.         } catch (SAXException e) {   
  63.             // TODO 自动生成 catch 块   
  64.             e.printStackTrace();   
  65.         } catch (IOException e) {   
  66.             // TODO 自动生成 catch 块   
  67.             e.printStackTrace();   
  68.         }   
  69.     }   
  70.   
  71. }  

SAX实例二:
ErrorProcessor.java演示错误处理器的使用
如果SAX应用程序需要实现定制的错误处理,那么它必须实现这个接口,并调用XMLReader对象的setErrorHandler()向解析器注册一个实例。之后解析器将通过这个接口报告所有的错误和
警告。
students2.xml
Java代码
  1. <?xml version="1.0" encoding="gb2312"?>   
  2.   
  3. <?xml-stylesheet type="text/xsl" href="student.xsl"?>   
  4.   
  5. <!DOCTYPE students[   
  6. <!ELEMENT students (student+)>   
  7. <!ELEMENT student (name,age,score)>   
  8. <!ELEMENT name (#PCDATA)>   
  9. <!ELEMENT age (#PCDATA)>   
  10. <!ELEMENT score (#PCDATA)>   
  11. <!ATTLIST student sn CDATA #REQUIRED>   
  12. ]>   
  13.   
  14. <students>   
  15.   <student sn="01">   
  16.      <name>张三</name>   
  17.      <age>11</age>   
  18.   </student>   
  19.   <student sn="02">   
  20.      <name>李四</name>   
  21.      <age>14</age>   
  22.   </student>   
  23. </students>  

ErrorProcessor.java:
Java代码 复制代码
  1. import java.io.FileInputStream;   
  2. import java.io.FileNotFoundException;   
  3. import java.io.IOException;   
  4. import org.xml.sax.InputSource;   
  5. import org.xml.sax.SAXException;   
  6. import org.xml.sax.SAXParseException;   
  7. import org.xml.sax.XMLReader;   
  8. import org.xml.sax.helpers.DefaultHandler;   
  9. import org.xml.sax.helpers.XMLReaderFactory;   
  10.   
  11. //覆盖了warning(),error(),fatalError(),endElement()   
  12. public class ErrorProcessor extends DefaultHandler{   
  13.   
  14.     @Override  
  15.     //警告信息   
  16.     public void warning(SAXParseException e) throws SAXException {   
  17.         System.out.println("[Warning:"+getLocationString(e)+":"+e.getMessage());   
  18.     }   
  19.        
  20.     @Override  
  21.     //可恢复错误   
  22.     public void error(SAXParseException e) throws SAXException {   
  23.         System.out.println("[Error:"+getLocationString(e)+":"+e.getMessage());   
  24.     }   
  25.   
  26.     @Override  
  27.     //不可恢复错误   
  28.     public void fatalError(SAXParseException e) throws SAXException {   
  29.         System.out.println("[FatalError:"+getLocationString(e)+":"+e.getMessage());   
  30.     }   
  31.        
  32.     //自定义方法   
  33.     private String getLocationString(SAXParseException e){   
  34.         StringBuffer sb = new StringBuffer();   
  35.         String publicId = e.getPublicId();   
  36.         if(null != publicId ){   
  37.             sb.append(publicId);   
  38.             sb.append(" ");   
  39.         }   
  40.         String systemId = e.getSystemId();   
  41.         if(null != systemId ){   
  42.             sb.append(systemId);   
  43.             sb.append(" ");   
  44.         }   
  45.         sb.append(e.getLineNumber());//行号   
  46.         sb.append(":");   
  47.         sb.append(e.getColumnNumber());//列号   
  48.         return sb.toString();   
  49.     }   
  50.        
  51.     @Override  
  52.     public void endElement(String uri, String localName, String qName) throws SAXException {   
  53.         System.out.println("</"+qName+">");   
  54.     }   
  55.        
  56.     public static void main(String[] args) {   
  57.         try {   
  58.             XMLReader xmlReader = XMLReaderFactory.createXMLReader();   
  59.             //打开验证功能   
  60.             xmlReader.setFeature("http://xml.org/sax/features/validation",true);   
  61.             ErrorProcessor ep = new ErrorProcessor();   
  62.             xmlReader.setContentHandler(ep);   
  63.             xmlReader.setErrorHandler(ep);   
  64.             xmlReader.parse(new InputSource(new FileInputStream("students2.xml")));   
  65.         } catch (SAXException e) {   
  66.             // TODO 自动生成 catch 块   
  67.             e.printStackTrace();   
  68.         } catch (FileNotFoundException e) {   
  69.             // TODO 自动生成 catch 块   
  70.             e.printStackTrace();   
  71.         } catch (IOException e) {   
  72.             // TODO 自动生成 catch 块   
  73.             e.printStackTrace();   
  74.         }   
  75.            
  76.     }   
  77.   
  78. }  

SAX实例三:查找students.xml中特定学生的信息。
利用栈的数据结构来处理XML
StudentLookup.java
Java代码
  1. import java.io.File;   
  2. import java.io.IOException;   
  3. import java.util.Stack;   
  4. import javax.xml.parsers.ParserConfigurationException;   
  5. import javax.xml.parsers.SAXParser;   
  6. import javax.xml.parsers.SAXParserFactory;   
  7. import org.xml.sax.Attributes;   
  8. import org.xml.sax.SAXException;   
  9. import org.xml.sax.helpers.DefaultHandler;   
  10.   
  11.   
  12. public class StudentLookup extends DefaultHandler{   
  13.        
  14.     private String name;   
  15.     private String age;   
  16.     private String attrName;   
  17.     private String attrValue;   
  18.     private Stack tagsStack = new Stack();   
  19.        
  20.     public void setAttrName(String attrName) {   
  21.         this.attrName = attrName;   
  22.     }   
  23.   
  24.     public void setAttrValue(String attrValue) {   
  25.         this.attrValue = attrValue;   
  26.     }   
  27.        
  28.     @Override  
  29.     public void startElement(String arg0, String localName, String qName, Attributes attrs) throws SAXException {   
  30.         if(tagsStack.empty()){   
  31.             if("student".equals(qName)){   
  32.                 int len = attrs.getLength();   
  33.                 for(int i=0;i<len;i++){   
  34.                     if(attrName.equals(attrs.getQName(i)) && attrValue.equals(attrs.getValue(i))){   
  35.                         tagsStack.push(qName);   
  36.                         break;   
  37.                     }   
  38.                 }   
  39.             }   
  40.         }else{   
  41.             tagsStack.push(qName);   
  42.         }   
  43.     }   
  44.   
  45.     @Override  
  46.     public void characters(char[] ch, int start, int length) throws SAXException {   
  47.         if(!tagsStack.empty()){   
  48.             String tag = (String)tagsStack.peek();   
  49.             if("name".equals(tag)){   
  50.                 name = new String(ch,start,length);   
  51.             }   
  52.             if("age".equals(tag)){   
  53.                 age = new String(ch,start,length);   
  54.             }   
  55.         }   
  56.     }   
  57.   
  58.     @Override  
  59.     public void endElement(String uri, String localName, String qName) throws SAXException {   
  60.         if(!tagsStack.empty()){   
  61.             String tag = (String)tagsStack.pop();   
  62.             if(tagsStack.empty() && "student".equals(tag)){   
  63.                 System.out.println("name"+name);   
  64.                 System.out.println("age"+age);   
  65.                 throw new SAXException("找到了匹配的学生");   
  66.             }   
  67.         }   
  68.     }   
  69.   
  70.     @Override  
  71.     public void endDocument() throws SAXException {   
  72.         System.out.println("没有找到匹配的学生");   
  73.     }   
  74.        
  75.     public static void main(String[] args) {   
  76.         if(args.length!=1){   
  77.             System.out.println("Usage:java StudentLookup key=value");   
  78.             System.exit(1);   
  79.         }   
  80.         int index = args[0].indexOf("=");   
  81.         if(-1 == index){   
  82.             System.out.println("Usage:key-value");   
  83.             System.exit(1);   
  84.         }   
  85.         String str = args[0].substring(0,index);   
  86.         StudentLookup sl = new StudentLookup();   
  87.         sl.setAttrName(str);   
  88.         str = args[0].substring(index+1);   
  89.         sl.setAttrValue(str);   
  90.         SAXParserFactory spf=SAXParserFactory.newInstance();       
  91.         try{   
  92.             SAXParser sp=spf.newSAXParser();   
  93.             sp.parse(new File("students.xml"),sl);   
  94.         }   
  95.         catch (ParserConfigurationException e){        
  96.             e.printStackTrace();   
  97.         }   
  98.         catch (SAXException e){   
  99.             System.out.println(e.getMessage());   
  100.         }   
  101.         catch (IOException e){   
  102.             e.printStackTrace();   
  103.         }   
  104.     }   
  105.        
  106. }  

相关文章:

  • [数据库]redis与redis操作
  • XMLHttpRequest Ajax 实例简介
  • Android开发之数据存储——SharedPreferences基础知识详解,饿补学会基本知识,开发者必会它的用法。...
  • xml的SAX解析过程详解
  • xml文件操作(利用dom4j)
  • aspx页面导出为word
  • mysql优化之索引优化
  • 使用SAX解析XML
  • AJAX实现类Google Suggest效果
  • Android:百度地图 + 百度导航
  • 文章太长了!~关于 XML 的一些基础知识
  • iOS: FFmpeg的使用一
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • HD1285(拓扑排序)
  • 如何用javascript设置延时执行
  • 分享一款快速APP功能测试工具
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • Android交互
  • CSS3 变换
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • laravel with 查询列表限制条数
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • 前端性能优化——回流与重绘
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 深入 Nginx 之配置篇
  • 听说你叫Java(二)–Servlet请求
  • 由插件封装引出的一丢丢思考
  • 阿里云服务器如何修改远程端口?
  • 仓管云——企业云erp功能有哪些?
  • 湖北分布式智能数据采集方法有哪些?
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (八十八)VFL语言初步 - 实现布局
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (三)mysql_MYSQL(三)
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • .Net 4.0并行库实用性演练
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .Net环境下的缓存技术介绍
  • @param注解什么意思_9000字,通俗易懂的讲解下Java注解
  • [20171113]修改表结构删除列相关问题4.txt
  • [BZOJ 4598][Sdoi2016]模式字符串
  • [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)
  • [CF703D]Mishka and Interesting sum/[BZOJ5476]位运算
  • [CISCN 2023 初赛]go_session
  • [Contiki系列论文之2]WSN的自适应通信架构
  • [CSS]CSS 的背景
  • [HTML API]HTMLCollection
  • [iOS]-网络请求总结
  • [kubernetes]控制平面ETCD
  • [NOIP2014普及组]子矩阵
  • [Prism]Composite Application Guidance for WPF(9)——命令