前端---SAX解析

SAX解析是基于事件编程的
返回事件编程的三要素:
1.事件源:要操作指定的xml文件
2.事件监听器:

  • 遇到文档触发方法startDocument()
  • 遇到开始标签触发方法startElement()
  • 遇到文本内容触发方法characters()
  • 遇到结束标签触发的方法endElement()
  • 遇到文档结束触发方法endDocument()

3.注册事件监听器:

开发步骤:

  • 1.创建SAXParser解析器对象,SAXParser是一个抽象类,他的实例需要通过工厂方法实现
    SAXParser parser=SAXParserFactory.newInstance().newSAXParser();//多态
  • 2.解析:定义 类 extends DefaultHandler,覆写方法,在事件监听器中实现事件处理逻辑
  • 3.注册监听事件parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("contact.xml"),DefaultHandler对象);

SAX解析特点
读一点取一点,节省空间,一旦遇到开始标签触发之后,及时从内存中将开始节点从内存中释放

SAX解析和DOM解析的区别

SAXDOM
原理读取一点解析一点,节省内存空间一次性加载整个xml文件,如果xml文件结构层次深OOM异常,浪费空间
使用过程只能读不仅能读还能修改,并且能往返读
编程思想面向事件编程面向对象编程

应用:解析contact.xml,遇到xml标签时,将Contact联系人对象
开发步骤:

  • 1.构造List
  • 2.遇到contact开始标签,创建一个联系人对象,封装属性
  • 3.遇到结束标签,读完之后,将contact 联系人对象添加到List
  • 4.遍历集合
public class MySAXDemo2 {
    /*SAX解析
    * 解析contact.xml,遇到xml标签时,将Contact联系人对象
    *

    * * */

    public static void main(String[] args) throws Exception {
        //创建SAXParser解析器对象,SAXParser是一个抽象类,他的实例需要通过工厂方法实现
        SAXParser parser=SAXParserFactory.newInstance().newSAXParser();//多态
        //解析
        //注册监听事件
        MyDefaultHandler2 handler2=new MyDefaultHandler2();
        parser.parse(MySAX.class.getResourceAsStream("contact.xml"),handler2);


    }
}

事件处理程序:

/*
 * 事件处理程序
 * 逻辑需要自己定义
 *
 * */
public class MyDefaultHandler2 extends DefaultHandler {
    List<Contact> list = new ArrayList<Contact>();
    private Contact contact = null;
    private String curTag;

    public List<Contact> getList() {
        return list;
    }


    /*
     * 文档开始时 触发此方法
     * */
    @Override
    public void startDocument() throws SAXException {

    }

    /**
     * @Description: 当遇见开始标签时触发方法
     * @Param: qName:开始标签名称
     * attributes 属性列表
     * @return:
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        curTag = qName;
        //如何判断读到的是开始标签
        if (qName.equals("contact")) {
            contact = new Contact();
            String id = attributes.getValue("id");
            contact.setId(id);
        }
    }

    /**
     * @Description: 当遇到标签的文本触发
     * @Param: ch:字符数组
     * start:从某个位置开始获取文本
     * length:指定长度:实际长度
     * @return:
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //遇到文本,每次读取的都是当前文本的实际内容
        String content=new String(ch,start,length);
        //判断curTag是name 还是phone...
        if("name".equals(curTag)){
            contact.setName(content);

        }
        if("phone".equals(curTag)){
            contact.setPhone(content);
        }
        if("email".equals(curTag)){
            contact.setEmail(content);

        }
        if("address".equals(curTag)){
            contact.setAddress(content);
        }
        if("gender".equals(curTag)){
            contact.setGender(content);
        }



    }


    /**
     * @Description: qName:结束标签名称
     * @Param:
     * @return:
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equals("contact")){
            System.out.println(contact);
        }
    }


}

运行时我遇到了这样的错误

Exception in thread "main" java.lang.IllegalArgumentException: InputStream cannot be null
	at javax.xml.parsers.SAXParser.parse(SAXParser.java:191)
	at www.github.sweeeeeet.sax.MySAX.main(MySAX.java:24)

我意识到这样的获取类加载器的方式是否有误,因为java天生是多线程的,因此需改为采用获取绝对classpath的方式,于是我将main方法中获取xml文件的方式改为:parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("contact.xml"),handler2);,于是就运行成功。

XML文件的约束

XML文件的DTD约束:开发者对xml文件制定的规则,分为内部约束方式和外部约束方式:
1.外部方式:
note.xml:

<?xml version="1.0"?>


<!--
xml文件的DTD约束:
 内部文件约束的方式
-->

<!--外部方式:

<!DOCTYPE 根元素 SYSTEM "文件名(约束文件)">
-->
<!DOCTYPE note SYSTEM "note.dtd">
<note>
    <to>Tove</to>
    <from>Jani</from>
    <heading>Reminder</heading>

    <body id="002">Don't forget me this weekend</body>
    <body id="002">Don't forget me this weekend</body>
</note>

note.dtd:


        <!ELEMENT note (to?,from*,heading,body+)>
        <!ELEMENT to      (#PCDATA)>
        <!ELEMENT from    (#PCDATA)>
        <!ELEMENT heading (#PCDATA)>
        <!ELEMENT body    (#PCDATA)>

<!--
<!ATTLIST 元素名称 属性名称 属性类型 默认值>
-->
        <!--body id CDATA:约束body的内容是普通字符串并且必须指定id属性-->
        <!ATTLIST body id CDATA #FIXED "002">

schema约束
schema约束文件后缀名:.xsd

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://www.bite.cn"
           elementFormDefault="qualified">

    <xs:element name='书架' >
        <xs:complexType>
            <xs:sequence maxOccurs='unbounded' >
                <xs:element name='书' >
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name='书名' type='xs:integer' />
                            <xs:element name='作者' type='xs:string' />
                            <xs:element name='售价' type='xs:string' />
                        </xs:sequence>
                   <xs:attribute name="id" type="xs:integer"></xs:attribute>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

<?xml version="1.0" encoding="UTF-8"?>
<bite:书架 xmlns:bite="http://www.bite.cn"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.bite.cn book.xsd">

    <bite:书 id="1">
        <bite:书名>10</bite:书名>
        <bite:作者>张三</bite:作者>
        <bite:售价>28.00元</bite:售价>
    </bite:书>
</bite:书架>

格式:名称空间:定义xmlns:名称空间=“别名”(url)
使用名称空间在xml文件中定义标签时,必须要指定别名“http://www…”
关联当前别名地址:schemaLocation=“别名1 地址1 别名2 地址2…”

定义后的名称空间指定标签名称格式:<名称空间:标签名称>,表示该标签被对应的名称空间约束,具体的约束写在了名称空间关联的别名(url地址)对应的.xsd文件中。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值