你不知道XML编程的那些事儿(二)

昨天谈了使用Jaxp采用DOM的方式进行解析XML文件,那么今天来看下SAX方式风采吧!另外还提供一种最常用的解释方法——DOM4j。
1.在使用SAX解析方式之前,必须要明白我们为什么会选用SAX方式来对XML进行解析?
这也正是昨天谈到的SAX和DOM方式之间的优缺点,在使用DOM方式进行解析时往往会因XML文件特别大而导致计算机大量内存消耗,最后导致内存溢出,而SAX方式恰恰弥补了这点,它允许在读取文档时就直接对文档进行处理,而不是像DOM方式那样要等待XML载入内存后才进行操作。
2.如何实现SAX方式对XML进行解析?
主要涉及到两部分:
(1).解析器
在解析某个XML文档时,只要解析到XML文档的一个组成部分,都会调用一个处理器事件;
(2).事件处理器:
这部分主要是由程序员自己来写,通过事件处理器中的方法参数就可以得到SAX解析器解析数据,从而决定如何对数据进行处理。

以下通过一个实例具体看SAX如何实现:

XML示例文件
//book.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<书架>
  <> 
    <书名 name="Thinking in Java">Java程序编程思想</书名>  
    <作者>张孝祥</作者>  
    <出厂价>69.0元</出厂价>  
    <售价>109.0元</售价>  
    <售价>209.0元</售价>  
  </>
  <> 
    <书名 name="CSS禅意花园">CSS禅意花园</书名>  
    <作者>某某</作者>  
    <出厂价>39.0元</出厂价>  
    <售价>45.0元</售价> 
  </>Cecilia
</书架>
实体类:book
public class Book {
    private String name;
    private String author;
    private String price;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getPrice() {
        return price;
    }
    public void setPrice(String price) {
        this.price = price;
    }
第一种事件处理器:ListHandler
/**
 * 用于获取全部的标签
 * @author 芷若初荨
 *
 */
public class ListHandler implements ContentHandler {
        //开始标签内容
        @Override
        public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
            // TODO Auto-generated method stub
            System.out.println("<"+qName+">");

            for(int i=0;atts!=null&&i<atts.getLength();i++){
                String attsName=atts.getQName(i);
                String attsValue=atts.getValue(i);
        //      System.out.println("attsName:"+attsName+"attsValue"+attsValue);
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            // TODO Auto-generated method stub
            System.out.println(new String(ch,start,length));
        }

        //结束标签内容
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            // TODO Auto-generated method stub
            System.out.println("</"+qName+">");

        }

        @Override
        public void setDocumentLocator(Locator locator) {
            // TODO Auto-generated method stub

        }

        @Override
        public void startDocument() throws SAXException {
            // TODO Auto-generated method stub

        }

        @Override
        public void endDocument() throws SAXException {
            // TODO Auto-generated method stub

        }

        @Override
        public void startPrefixMapping(String prefix, String uri) throws SAXException {
            // TODO Auto-generated method stub

        }

        @Override
        public void endPrefixMapping(String prefix) throws SAXException {
            // TODO Auto-generated method stub

        }

        @Override
        public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
            // TODO Auto-generated method stub

        }

        @Override
        public void processingInstruction(String target, String data) throws SAXException {
            // TODO Auto-generated method stub

        }

        @Override
        public void skippedEntity(String name) throws SAXException {
            // TODO Auto-generated method stub

        }

}
这种处理器主要是为了实现获取全部的内容,但是需要重写@Override全部的函数。
第二种事件处理器:TagValueHandler
/**
 * 获取指定的标签
 * @author 芷若初荨
 *
 */
public class TagValueHandler extends DefaultHandler {
    private String currentTag;//当前标签
    private int needNumber=2;//记住想获取的第几个作者标签的值
    private int currentNumber;//当前解析到的是第几个
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {
        // TODO Auto-generated method stub
        currentTag=qName;
//      System.out.println("<"+qName+">");
    if(currentTag.equals("作者")){
        currentNumber++;
    }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        // TODO Auto-generated method stub
//      如果到了结束标签,那么将其制空
        currentTag=null;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // TODO Auto-generated method stub
//      如果当前标签是作者并且当前标签值和所需要的值是相等的,那么就输出
        if("作者".equals(currentTag)&&currentNumber==needNumber){
                System.out.println(new String(ch, start, length));      
                    }
    }
}
这种处理器主要是为了实现获取指定标签内容。
第三种事件处理器:BeanListHandler
/**
 * 使用Bean来实现处理器
 * @author 芷若初荨
 *
 */
//把XML文档中的每一本书封装到book对象,并把多个book对象放在一个list集合中
class BeanListHandler extends DefaultHandler{
    private List list=new ArrayList();
    private String currentTag;
    private Book book;

    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
        // TODO Auto-generated method stub
        currentTag=name;
        if("书".equals(currentTag)){
            book=new Book();
        }
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // TODO Auto-generated method stub
        if("书名".equals(currentTag)){

            String name=new String(ch, start, length);
            book.setName(name);
        }
        if("作者".equals(currentTag)){
            String author=new String(ch, start, length);
            book.setAuthor(author);
        }
        if("售价".equals(currentTag)){
            String price=new String(ch, start, length);
            book.setPrice(price);
        }

    }
    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
        // TODO Auto-generated method stub
//      如果在标签名等于书,那么将其加入到list表
        if(name.equals("书")){
            list.add(book);
            book=null;
        }
//      否则将当前的标签制为空
        currentTag=null;
    }
    public List getBooks(){
        return list;
    }

}
测试类:main
/**
 * 使用Sax解析XML文档
 * @author 芷若初荨
 *
 */
public class SAXAnalysisXML {
    public static void main(String[] args) throws Exception{
//      1.创建解析工厂
        SAXParserFactory saxfactory=SAXParserFactory.newInstance(); 
//      2.得到解析器
        SAXParser saxp=saxfactory.newSAXParser();
//      3.得到读取器
        XMLReader reader=saxp.getXMLReader();
//      4.设置内容处理器
        BeanListHandler handler=new BeanListHandler();
        reader.setContentHandler(handler);
//      5.读取文档内容
        reader.parse("msg/book.xml");
//      定义一个book对象的list集合,
        List<Book> list=handler.getBooks();
        System.out.println(list);
    }
}
经过以上的实例,相信应该对SAX的方式有所了解啦,接下来,让我们来看一种最常用的解析方式,那就是DOM4j解析方式。
3.DOM4j解析方式
DOM4j是一个简单灵活的开放源代码的库,是一个非常优秀的Java XML API,具有性能优异、功能强大、极易使用的优点。如Hibernate框架。
那么如何使用DOM4j来对XML文档进行增删改查的操作呢?还是通过一个实例来让大家体会DOM4j给大家解析XML带来的优势。
XML实例文档还是使用上面的book.xml文件

读取第二本书的书名

    @Test
//  读取第二本书的书名
    public void read() throws Exception{
        SAXReader reader=new SAXReader();
        Document document=reader.read(new File("msg/book.xml"));

//      得到根节点 
        Element root=document.getRootElement();
        Element book=(Element) root.elements("书").get(0);
        String value=book.element("书名").getText();
        System.out.println(value);
    }

读取第二本书的书的属性

//  读取第二本书的书的属性
    @Test
    public void readAttribute() throws Exception{
        SAXReader reader=new SAXReader();
        Document document=reader.read(new File("msg/book.xml"));

//      得到根节点 
        Element root=document.getRootElement();
        Element book=(Element) root.elements("书").get(0);
        String value=book.element("书名").attributeValue("name");
    }

添加新的售价(广泛地)

//  添加新的售价
    @Test
    public void Add() throws Exception{
        SAXReader reader=new SAXReader();
        Document document=reader.read(new File("msg/book.xml"));
//      获取根节点
        Element book=document.getRootElement().element("书");
        book.addElement("售价").setText("209.0元");

//      将XML解析文档进行进一步格式化地漂亮地输出
        OutputFormat format=OutputFormat.createPrettyPrint();
//      输出方式:紧凑地,表示之间没有任何的空格
//      OutputFormat format=OutputFormat.createCompactFormat();
//      格式化后设置对应的编码
        format.setEncoding("UTF-8");

//      使用XML写释器来完成XML文档的写入内存操作
//      写回的同时,并且注意编码和格式的问题,传入指定文件和格式化的方式的参数
        XMLWriter writer=new XMLWriter(new FileOutputStream("msg/book.xml"),format);
//      XMLWriter writer=new XMLWriter(new FileWriter("msg/book/xml"));
/*  上面最好使用字节流,不要使用字符流FileWriter("msg/book.xml",format),
    原因:如果使用字符流,由于底层流是个字符流,那么就不会去查询格式化输出器,只会直接去使用document的编码,不会进行检查,如果不一致,就会出现乱码问题;
    而如果使用字节流,那么会先将字节流转化成字符流,在转化的过程中会查询格式输出器,设置格式输出器对应的编码,由于document编码和格式输出器编码对应一致,那么就不会出现乱码现象。
*/
        writer.write(document);
        writer.close();

    }

在第一本书的指定位置上进行添加新的售价

/   在第一本书的指定位置上进行添加新的售价
    @Test
    public void AddPrice() throws Exception{
        SAXReader reader=new SAXReader();
        Document document=reader.read(new File("msg/book.xml"));
        Element book=document.getRootElement().element("书");
        List list=book.elements();//[书名,作者,售价]
        Element price=DocumentHelper.createElement("售价");
        price.setText("200元");
        list.add(2, price);
//      得到格式化输出器
        OutputFormat format=OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
//      写回XML文件中
        XMLWriter writer=new XMLWriter(new FileOutputStream("msg/book.xml"),format);
        writer.write(document);
        writer.close();
    }

删除售价的节点

    @Test
//  删除售价的节点
    public void removeNode() throws Exception{
        SAXReader reader=new SAXReader();
        Document document=reader.read(new File("msg/book.xml"));
//      得到售价节点
        Element price=document.getRootElement().element("书").element("售价");
        price.getParent().remove(price);
//      更新并写回xml文件中
//      得到格式化输出器
        OutputFormat format=OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
//      写回XML文件中
        XMLWriter writer=new XMLWriter(new FileOutputStream("msg/book.xml"),format);
        writer.write(document);
        writer.close(); 

    }

更新节点

    @Test
//  更新节点
    public void UpdateNode() throws Exception{
        SAXReader reader=new SAXReader();
        Document document=reader.read(new File("msg/book.xml"));
//      得到第二本书的作者
        Element book=(Element) document.getRootElement().elements("书").get(1);
//      更新作者节点内容
        book.getParent().setText("Cecilia");
//      更新并写回xml文件中
//      得到格式化输出器
        OutputFormat format=OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
//      写回XML文件中
        XMLWriter writer=new XMLWriter(new FileOutputStream("msg/book.xml"),format);
        writer.write(document);
        writer.close();     
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值