XML相关知识点

本文内容:

一、XML语言概述

  1.1 XML和HTML的区别

  1.2 XML的常用场景

二、XML文件的基本语法知识(如何编写一个XML文件)

三、如何使用CSS或者XSL来控制XML文件的显示样式

四、如何解析一个XML文件(java中直接提供的两种XML文档解析方式)

  4.1概述

  4.2DOM法解析*.xml

  4.3SAX法解析*.xml

  4.4xml文件两种解析方法的比较(DOM和SAX的比较)

五、对用于XML文件解析(读取、写/修改)的Java API的进一步封装(用于xml文件解析的三方组件,需要手动导入相应jar包才可以使用其提供的API)

  5.1概述

  5.2 JDOM(由Jason Hunter和Brett Mclaughlin联合发布)

  5.3 DOM4J(由SourceForge发布)

一、XML语言概述:

1.1 XML和HTML的区别

    • HTML和XML都是由SGML发展而来的,但是两者又有很多的不同之处。其中最大的不同便是:

      • HTML中的元素都是固定的,且以显示为主

      • XML中的元素不是固定的,都是程序员自定义的,主要以数据保存为主
    • 实例:由下面的例子可以看出,HTML中的标签都是固定的,是由HTML标准定义好的,每种标签怎么写,拥有什么含义都是HTML标准中已经定义好的,要想编写出一个能够运行的HTML文件就必须按照HTML规则来使用相应的标签,并且按照HTML语法要求来写。而XML中的元素(标签)则是由程序员来根据实际需求自定义的,XML中的标签的标识符怎么写,各个标签代表什么意思,完全都是由程序员来定义的。
      •   
      •       
      •  上述例子中HTML页面中的<html> <head> <title> <body> <ul> <li> 等标签都是HTML标准中已经定义好的,HTML文件中程序员只能使用这些标签,不能使用其他标签

      • 上述例子中XML文件的<addresslist> <linkman> <name> <id> <company> <email> <tel> <site> 都是程序员自己定义的,程序员还可以在该XML文件中添加更多的自定义标签

      • XML文件中除了含有自定义标签之外,还必须含有一个文件头来表示这个文件是XML文件,这个文件头是必不可少的,如下:

        <?xml version="1.0" encoding="utf-8" standalone=“”?>
        <自定义标签1>
        
            ....其他自定义标签...
        
        </自定义标签1>

        这个文件头规定了该XML页面的一些属性:如version规定了当前xml版本,encoding规定了该xml页面使用的编码方式,standalone表示该xml文件是否是独立显示的(XML文件可以结合CSS或者XSL来控制xml文件的显示样式)

1.2 XML的常用场景

    • 数据交换
    • 系统配置
    • 内容管理  

二、XML文件语法知识(编写第一个xml文件)

  • 首先,所有的XML文件都必须含有文件头(即前导区)和数据区,前导区用于定义该XML文件的一些属性,数据区即为该XML文件的有效内容
  • 前导区:
    • <?xml version="1.0" encoding="utf-8" standalone=“”?>
    • 这个文件头规定了该XML页面的一些属性:如version规定了当前xml版本,encoding规定了该xml页面使用的编码方式,standalone表示该xml文件是否是独立显示的(XML文件可以结合CSS或者XSL来控制xml文件的显示样式)

    • 前导区的三个属性必须按照version  encoding  standalone的顺序来写,否则该XML编译时会出错 
  • 数据区:
    • 数据区就是开发人员自定义的一些标签了,他们的标识符、含义都是由开发者自行定义的
    • 所有的数据区必须有一个根元素,一个根元素下可以存放多个子元素,且要求每一个元素必须完结(即</**>)
    • XML中的每一个标记都是区分大小写的  
    • 自定义标签也可以拥有属性,但是属性的值必须用“”括起来。如果一个自定义标签有多个自定义属性,则属性之间用空格隔开
    • 什么时候用自定义标签,什么时候用自定义属性?(答:一般不建议使用自定义属性。因为如果该xml文件需要结合CSS或XSL来显示的话,XML文件的标签属性的值是无法显示的。)
    • 数据区的自定义标签要赋值,赋值时有一些特殊符号必须使用转义字符来表示:
    • XML文件内部注释:使用CDATA添加注释。

      • 当XML解析器处理到CDATA标识符处时,就知道这一块实际上只是注释,所以解析器不会解析CDATA内部所包含的内容。

      • 语法:<![CDATA[注释(该部分内容不会被XML解析器解析)]]>  

    • 如上所述,XML数据区的标签是可以由开发者自由定义的,如果要对一个XML文件中经常出现的元素或属性进行严格的定义,则需要使用DTD和Schema技术。

      • 如,Spring的配置文件*.xml中,<bean>标签专门用于定义bean,至于它的bean标签就是根据DTD技术定义的。   

  • xml文件实例:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <?xml-stylesheet type="text/css" href="../css/test.css"?>
    <linklist>
        <id>001</id>
        <name chinese="yes">lxrm</name>
        <email>123@qq.com</email>
        <textbook>&lt;&lt;Java Web开发实战经典&gt;&gt;</textbook>
        <![CDATA[
            ..注释..
            CDATA中包含的所有内容都不会被XML解析器解析
            相当于HTML中的<!--  -->
        ]]>
    </linklist>

     

三、通过CSS或者XSL来控制XML文件内容的显示样式

概述:如果xml文件前导区定义的standalone=“yes”,那么该XML文件运行后显示结果就如本文第二部分展示的那样,只是将数据区的内容以树的形式展示出来。

        如果将xml绑定了其他CSS文件或者XSL文件,则该XML文件中的内容就可以按照CSS或XSL中定义的格式来显示。

实例:

  • <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <?xml-stylesheet type="text/css" href="../css/test.css"?>
    <linklist>
        <id>001</id>
        <name chinese="yes">lxrm</name>
        <email>123@qq.com</email>
    </linklist>

    @CHARSET "UTF-8";
    id{
        display:block;
        color:red;
        font-weight:bold;
        font-size:20pt;
    }
    name,email{
        dispaly:block;
        color:blue;
        font-weight:normal;
        font-size:16pt;    
    }

四、XML文件的解析 

4.1 概述:

    • XML文件有多种解析方式,如DOM解析、SAX解析法

4.2 DOM解析*.xml文件

基于DOM解析的XML分析器  
*.xml——>DOM树  
优点:支持随机访问,即支持应用程序在任何时候随机访问XML文档的任何一部分内容  

缺点:

  • 对内存的需求比较高(因为这种解析器是将XML文档全部存成一个DOM树放在内存中,所以当XML文档较大或者较为复杂时,对设备的内存的需求会比较高)
  • 由于DOM解析是将XML文件中元素存储成一个树结构,所以对XML中内容的随机访问就相当于对树的随机访问,每次访问都需要遍历树,而树的遍历又会非常慢,所以基于DOM解析的XML分析器,对于XML文件内容的随机访问速度也是很慢的
 
 

 基于DOM的XML文件解析器,所提供的DOM接口:

  • 应用程序中可以使用下述接口获取XML文件中的元素及其值。
  • Document接口
  • Node接口
  • NodeList接口
  • NameNodeMap接口
 

1. 读取*.xml文件:(编程思路)

    • 如何对一个XML文件施行DOM解析,并且在应用程序中使用XML文件中的元素:(编程思路)
    • 涉及到的类:
    • import java.io.File;
      import java.io.IOException;
      
      import javax.xml.parsers.DocumentBuilder;
      import javax.xml.parsers.DocumentBuilderFactory;
      import javax.xml.parsers.ParserConfigurationException;
      
      import org.w3c.dom.Document;
      import org.w3c.dom.Element;
      import org.w3c.dom.NodeList;
      import org.xml.sax.SAXException;
        

2.写*.xml文件:(编程思路)

    • 如何通过java程序修改一个*.xml文件
    • 编程思路:
      *    step1,创建DocumentBuilderFactory对象
      *    step2,通过DocumentBuilderFactory对象获取DocumentBuilder对象
      *    step3,通过DocumentBuilder对象创建DOM树(即Document对象)
      *    step4,使用Element元素定义*.xml文件中的元素
      *    step5,为step4中定义的xml元素进行赋值
      *    step6,设置上述所定义的xml元素的父子节点关系(也即为DOM树添加节点)
      *    step7,创建TransformerFactory对象
      *    step8,通过TransformerFactory对象获取Transformer对象
      *        step8.1  将DOM树(即step3中所获得的Document对象)封装成DOMSource对象
      *        step8.2  将{path}/*.xml封装成StreamResult对象
      *        step8.3  使用Transformer对象中的成员函数设置*.xml文件的属性(如编码方式等)
      *    step9,使用Transformer对象将上述DOM对象转化成*.xml文件(如果相应路径已经存在同名xml文件,则覆盖原有同名xml文件)

      涉及到的类:

      import java.io.File;
      
      import javax.xml.parsers.DocumentBuilder;
      import javax.xml.parsers.DocumentBuilderFactory;
      import javax.xml.parsers.ParserConfigurationException;
      import javax.xml.transform.OutputKeys;
      import javax.xml.transform.Transformer;
      import javax.xml.transform.TransformerConfigurationException;
      import javax.xml.transform.TransformerException;
      import javax.xml.transform.TransformerFactory;
      import javax.xml.transform.dom.DOMSource;
      import javax.xml.transform.stream.StreamResult;
      
      import org.w3c.dom.Document;
      import org.w3c.dom.Element;

 

 在应用程序中使用基于DOM的XML文件解析器解析*.xml文件,并且调用该XML文件解析器提供的DOM接口获取xml文件的内容,并做出后续操作:

  • 实例一,D:/testDOM.xml
  • <?xml version="1.0" encoding="UTF-8"?>
    <addresslist>
        <name>lxrm</name>
    </addresslist>
  • import java.io.File;
    import java.io.IOException;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.NodeList;
    import org.xml.sax.SAXException;
    
    /**
     *@Author chen
     *@date 2017-4-2
     *@description:本程序用于测试XML文件的DOM解析
     *在应用程序中使用基于DOM的XML文件解析器解析xml文件,并且使用该解析器提供的DOM接口
     *获取该xml文档中的元素及其对应的值,并做出后续操作
     */
    
    public class TestXMLDOM {
        public static void main(String[] args){
            //1.建立DocumentBuilderFactory,以用于取得DocumentBuilder
            DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
            //2.通过DocumentBuilderFactory实例获取DocumentBuilder对象
            DocumentBuilder builder=null;
            try{
                builder=factory.newDocumentBuilder();
            }catch(ParserConfigurationException e){
                e.printStackTrace();
            }
            //3.使用DocumentBuilder建立*.xml文件对应的DOM树(即Document对象)
            Document doc=null;
            String file="D:"+File.separator+"testDOM.xml";
            try{
                doc=builder.parse(file);
            }catch(SAXException e){
                e.printStackTrace();
            }catch(IOException e){
                e.printStackTrace();
            }
            //4.查找xml文件对应的DOM树中的节点
            NodeList nl=doc.getElementsByTagName("name");
            //5.操作4中所获取的xml文件的元素的值(本例中是在后台输出该元素的值)
            System.out.println(file+"中的<name>标签的值:"+nl.item(0).getFirstChild().getNodeValue());
        }
    }

     

  • 实例二:解析一个更复杂的*.xml文件,将其转化成一个DOM树,并且获取该xml文件中某些元素的值
  • D:/testDOM.xml
  • <?xml version="1.0" encoding="UTF-8"?>
    <addresslist>
        <linkman>
            <name>lxrm</name>       
            <email>123@**.cn</email>
        </linkman>
        <linkman>
            <name>lm</name>      
            <email>123@**.cn</email>
        </linkman>
    </addresslist>
    
    

    package
    xml.operation; import java.io.File; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** *@Author chen *@date 2017-4-2 *@description:本程序用于测试XML文件的DOM解析 *在应用程序中使用基于DOM的XML文件解析器解析xml文件,并且使用该解析器提供的DOM接口 *获取该xml文档中的元素及其对应的值,并做出后续操作 */ public class TestXMLDOM { public static void main(String[] args){ //1.建立DocumentBuilderFactory,以用于取得DocumentBuilder DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); //2.通过DocumentBuilderFactory实例获取DocumentBuilder对象 DocumentBuilder builder=null; try{ builder=factory.newDocumentBuilder(); }catch(ParserConfigurationException e){ e.printStackTrace(); } //3.使用DocumentBuilder建立*.xml文件对应的DOM树(即Document对象) Document doc=null; String file="D:"+File.separator+"testDOM.xml"; try{ doc=builder.parse(file); }catch(SAXException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } //4.查找xml文件对应的DOM树中的节点 NodeList nl=doc.getElementsByTagName("linkman"); //5.操作4中所获取的xml文件的元素的值(本例中是在后台输出该元素的值) System.out.println("从"+file+"中获取的信息:"); for(int i=0;i<nl.getLength();i++){ Element e=(Element) nl.item(i); System.out.println("姓名:"+e.getElementsByTagName("name").item(0).getFirstChild().getNodeValue()+" 联系方式:"+e.getElementsByTagName("phone").item(0).getFirstChild().getNodeValue()); }//end for }//end main }//end class
  • 实例三,将DOM树转变成*.xml文档
  • /**
    *@author lxrm
    *@date 2017年4月3日
    *@description:通过java程序创建一个*.xml文件,或者覆盖已经存在的同名xml文件
    *编程思路:
    *    step1,创建DocumentBuilderFactory对象
    *    step2,通过DocumentBuilderFactory对象获取DocumentBuilder对象
    *    step3,通过DocumentBuilder对象创建DOM树(即Document对象)
    *    step4,使用Element元素定义*.xml文件中的元素
    *    step5,为step4中定义的xml元素进行赋值
    *    step6,设置上述所定义的xml元素的父子节点关系(也即为DOM树添加节点)
    *    step7,创建TransformerFactory对象
    *    step8,通过TransformerFactory对象获取Transformer对象
    *        step8.1  将DOM树(即step3中所获得的Document对象)封装成DOMSource对象
    *        step8.2  将{path}/*.xml封装成StreamResult对象
    *        step8.3  使用Transformer对象中的成员函数设置*.xml文件的属性(如编码方式等)
    *    step9,使用Transformer对象将上述DOM对象转化成*.xml文件(如果相应路径已经存在同名xml文件,则覆盖原有同名xml文件)
    **/
    package xml.operation;
    
    import java.io.File;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerConfigurationException;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.dom.DOMSource;
    import javax.xml.transform.stream.StreamResult;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    
    public class BuildXMLFile {
        public static void main(String[] args){
            //step1,创建DocumentBuilderFactory对象,以便于获取DocumentBuilder对象
            DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
            //step2,通过step1中所获取的DocumentBuilderFactory对象获取DocumentBuilder对象
            DocumentBuilder builder=null;
            try{
                builder=factory.newDocumentBuilder();
            }catch(ParserConfigurationException e){
                e.printStackTrace();
            }
            //step2,通过step2所获得的DocumentBuilder对象创建DOM树(也即Document对象)
            Document doc=null;
            doc=builder.newDocument();
            //step4,定义xml文件中的元素的标识符
            Element addresslist=doc.createElement("addresslist");
            Element linkman=doc.createElement("linkman");
            Element name=doc.createElement("name");
            Element email=doc.createElement("email");
            //step5,为xml文件中的元素赋值
            name.appendChild(doc.createTextNode("lxrm2"));
            email.appendChild(doc.createTextNode("123@qq.com"));
            
            //step6,设置xml文件中元素的父子关系(也即他们在DOM树中的父子节点关系)
            linkman.appendChild(name);
            linkman.appendChild(email);
            addresslist.appendChild(linkman);
            doc.appendChild(addresslist);//用Document对象指定父节点
            //step7,将上述建立好的DOM树存放至*.xml之前的准备工作
            TransformerFactory tranFactory=TransformerFactory.newInstance();
            Transformer tran=null;
            try{
                tran=tranFactory.newTransformer();
            }catch(TransformerConfigurationException e){
                e.printStackTrace();
            }
            tran.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            DOMSource source=new DOMSource(doc);//将上述DOM树(即Document对象)包装成DOMSource对象,以便于写入*.xml
            String file="D:"+File.separator+"new.xml";//待修改的xml文件(如果该文件不存在则新建该文件并写入内容。如果该文件存在则新的DOM树会覆盖原有文件内容)
            StreamResult result=new StreamResult(new File(file));
            try{
                tran.transform(source, result);//将DOM树中内容转变成*.xml文件
            }catch(TransformerException e){
                e.printStackTrace();
            }
        }
    }

    <?xml version="1.0" encoding="utf-8" standalone="no"?>

    <addresslist>
      <
    linkman>
    <
    name>lxrm2</name>
    <
    email>123@qq.com</email>
    </
    linkman>
    </
    addresslist>
 

4.3 SAX法解析*.xml文件

SAX法解析*.xml文件

原理:

  • 采用顺序模式进行访问,是一种快速读取XML文件数据的方式。
  • SAX法读取*.xml文件的时候,会触发一系列的事件,如扫描到文档(也即Document对象)的开始和结束,XML文档的元素(也即Element对象)的开始和结束的时候,都会触发一定的事件,作出相应的操作,直至扫描完整个文档。
 

优点:

  对内存的需求不会随着*.xml文件的大小而改变,也就是说,即使*.xml文件很大,SAX解析法依然可以使用,因为SAX解析法对内存的需求不大

 

缺点:

  • 不支持随意读取,只能对*.xml从头到尾的顺序遍历
  • 只能读取*.xml文件,不可以修改该xml文件
  • 开发起来较为复杂,需要继承一些接口,实现一些函数(事件),如需要在子类中实现读取到文档开始和结束,读取到element开始与结束时触发的事件函数

 SAX法构造*.xml文件解析器:(编程思路)

  • 涉及到的类
    • import org.xml.sax.Attributes;
      import org.xml.sax.SAXException;
      import org.xml.sax.helpers.DefaultHandler;
      import javax.xml.parsers.ParserConfigurationException;
      import javax.xml.parsers.SAXParser;
      import javax.xml.parsers.SAXParserFactory;
      
      import org.xml.sax.SAXException;
        
  • 编程思路
    • step1,建立一个SAX解析器(实际上就是一个继承了org.xml.sax.helpers.DefaultHandlers类的Java class对象)  
      • step1.1,建立一个java class,使得该类继承DefaultHandlers类
      • step1.2,复写(@override)DefaultHandlers类中的成员方法(包括startDocument()、endDocument()、startElement()、endElement()、character()等函数的覆写)  
    • step2,使用step1中建立的SAX解析器解析*.xml文件  
      • step2.1,建立SAXParserFactory对象
      • step2.2,通过SAXParserFactory对象获取SAXParser对象
      • step2.3,通过step2.2中获得的SAXParser对象的parse(String path,DefaultHandlers saxParser)函数解析*.xml
          • parse()函数的两个参数分别制定了待解析*.xml文件的路径和将要用于解析*.xml文件的SAX解析器(也就是step1中所建立的SAX解析器)      
  • 实现示例(见下文)
    • 实例一,使用SAX解析方法解析d:/testDOM.xml文件(读取该文件内容,并且将他们在后台输出)
      • 编程思路,
        • step1,创建SAX解析器——SAX_Build_MySAXParser.java
        • step2,在SAX_Use_MySAXParser_readXML.java中测试自己创建的SAX解析器(即读取*.xml文件内容并在后台输出)      

 示例一:使用SAX解析方法解析d:/testDOM.xml文件(读取该文件内容,并且将他们在后台输出)

      • step1,创建SAX解析器——SAX_Build_MySAXParser.java
      • /**
        *@author lxrm
        *@date 2017年4月9日
        *@description:使用SAX解析法解析*.xml文件的第一步就是创建自己的SAX解析器(实际上就是一个继承了DefaultHandler类的class)
        *构建自己的SAX解析器的编程思路:
        *    step1.1,建立一个java class,使得该类继承DefaultHandlers类
        *    step1.2,复写(@override)DefaultHandlers类中的成员方法(包括startDocument()、endDocument()、startElement()、endElement()、character()等函数的覆写)      */
        package xml.operation;
        
        import org.xml.sax.Attributes;
        import org.xml.sax.SAXException;
        import org.xml.sax.helpers.DefaultHandler;
        
        public class SAX_Build_MySAXParser extends DefaultHandler{
        
            @Override
            public void startDocument() throws SAXException{
                System.out.println("扫描到了文档开头,实际工程中可能有一些后续操作。");
                
            }
            
            @Override
            public void endDocument() throws SAXException{
                System.out.println("扫描到了文档结尾,整个xml文件的SAX解析过程结束。");
            }
            
            /**
             * @param uri
             * @param localName
             * @param name *.xml文件中元素(标签)的名称
             * @param attributes XML文件中标签的属性
             * */
            @Override
            public void startElement(String uri,String localName,String name,
                    Attributes attributes) throws SAXException{
                System.out.println("<"+name);
                if(attributes!=null){
                    for(int i=0;i<attributes.getLength();i++){
                        System.out.print(" "+attributes.getQName(i)+"=""+attributes.getValue(i)+""");
                    }
                }
                System.out.print(">");
                
            }
            
            @Override
            public void characters(char[] ch,int start,int length) throws SAXException{
                System.out.println(ch);
            }
            
            @Override 
            public void endElement(String uri,String localName,String name)throws SAXException{
                System.out.println("</"+name+">");
            }
        }

         

        step2,

        /**
        *@author lxrm
        *@date 2017年4月9日
        *@description:*/
        package xml.operation;
        
        import java.io.File;
        import java.io.IOException;
        
        import javax.xml.parsers.ParserConfigurationException;
        import javax.xml.parsers.SAXParser;
        import javax.xml.parsers.SAXParserFactory;
        
        import org.xml.sax.SAXException;
        
        public class SAX_use_MySAXParser_to_readXML {
            public static void main(String[] args) {
                SAXParserFactory factory=SAXParserFactory.newInstance();
                SAXParser saxParser=null;
                try{
                    saxParser=factory.newSAXParser();
                }catch(ParserConfigurationException | SAXException e){
                    e.printStackTrace();
                }
                String path="D:"+File.separator+"testDOM.xml";
                try {
                    saxParser.parse(path, new SAX_Build_MySAXParser());
                } catch (SAXException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        程序运行结果:(有点儿小bug,如下)

        <addresslist>
            <linkman>
                <name>lxrm</name>
                <phone>188**</phone>
                <email>123@**.cn</email>
            </linkman>
            <linkman>
                <name>lm</name>
                <phone>188**</phone>
                <email>123@**.cn</email>
            </linkman>
        </addresslist>
        扫描到了文档结尾,整个xml文件的SAX解析过程结束。
        

4.4 DOM解析法和SAX解析法的比较

基于DOM解析的XML分析器 基于SAX解析法的xml文件解析器
原理:将整个xml文件转化成一个DOM树,并且放到内存中

原理:

  • 采用顺序模式进行访问,是一种快速读取XML文件数据的方式。
  • SAX法读取*.xml文件的时候,会触发一系列的事件,如扫描到文档(也即Document对象)的开始和结束,XML文档的元素(也即Element对象)的开始和结束的时候,都会触发一定的事件,作出相应的操作,直至扫描完整个文档。

优点:

  支持随机访问,即支持应用程序在任何时候随机访问XML文档的任何一部分内容

优点:

  对内存的需求不会随着*.xml文件的大小而改变,也就是说,即使*.xml文件很大,SAX解析法依然可以使用,因为SAX解析法对内存的需求不大

缺点:

  • 对内存的需求比较高(因为这种解析器是将XML文档全部存成一个DOM树放在内存中,所以当XML文档较大或者较为复杂时,对设备的内存的需求会比较高)
  • 由于DOM解析是将XML文件中元素存储成一个树结构,所以对XML中内容的随机访问就相当于对树的随机访问,每次访问都需要遍历树,而树的遍历又会非常慢,所以基于DOM解析的XML分析器,对于XML文件内容的随机访问速度也是很慢的

缺点:

  • 不支持随意读取,只能对*.xml从头到尾的顺序遍历
  • 只能读取*.xml文件,不可以修改该xml文件
  • 开发起来较为复杂,需要继承一些接口,实现一些函数(事件),如需要在子类中实现读取到文档开始和结束,读取到element开始与结束时触发的事件函数

DOM法解析*.xml,编程实现:

  1.读取*.xml文件

    • 涉及到的类
      • import javax.xml.parsers.DocumentBuilder;
        import javax.xml.parsers.DocumentBuilderFactory;
        import javax.xml.parsers.ParserConfigurationException;
        
        import org.w3c.dom.Document;
        import org.w3c.dom.Element;
        import org.w3c.dom.NodeList;
        import org.xml.sax.SAXException;
          
    • 编程思路
    • 使用实例
      • 实例一,读取*.xml文件  
      • 实例二,读取复杂的*.xml文件

  2.java程序中修改*.xml文件(或者新建一个*.xml文件)

    • 涉及到的类
    • 编程思路
    • 使用实例
      • 实例三,修改已经存在的xml文件(或者生成一个新的*.xml)

SAX法解析*.xml文件,编程实现:

  • 涉及到的类
    • import org.xml.sax.Attributes;
      import org.xml.sax.SAXException;
      import org.xml.sax.helpers.DefaultHandler;
      import javax.xml.parsers.ParserConfigurationException;
      import javax.xml.parsers.SAXParser;
      import javax.xml.parsers.SAXParserFactory;
      
      import org.xml.sax.SAXException;
        
  • 编程思路
  • 使用实例

DOM解析法的适用场景:

  • 适用于需要对*.xml文件进行修改的场景
  • 适用于需要对*.xml文件中元素进行随机访问的场景
  • 但是,DOM解析不适用于大型xml文件的解析

SAX解析法的适用场景:

  • 适用于对大型xml文件进行解析的场景
  • 但是,不支持文件内容的修改,也不支持对文件内容的随机访问

五、对用于XML文件解析(读取、写/修改)的Java API的进一步封装

5.1 概述

  • XML语法是由W3C提供的
  • W3C除了提供XML语法的标准化文档之外,还提供了用于XML文档解析的java API(包括DOM解析相关API和SAX解析相关API)  
  • 但是上述两种XML文件的解析方法都有各自的缺点,所以其他一些组织就开始思考有没有更加好的方法可以集成两种解析方法的优点,同时又能避免他们各自的缺点
  • 经过漫长的探索,产生了JDOM和

5.2 JDOM(一种专门用于XML文件解析的Java组件)

5.2.1概述

    • JDOM(由Jason Hunter和Brett Mclaughlin联合发布),是开源的
    • 可以在http://www.jdom.org/上下载相应的JDOM包(即用于XML文件解析的java API)
    • JDOM是对DOM解析和SAX解析的改良,同时拥有两种解析方法的优点
    • JDOM是专门为java application设计的,为在java应用中的xml操作过程提供了一种更低消耗的方法
    • JDOM的主要操作类:

5.2.2使用JDOM组件操作XML文件(即XML文件解析操作)

    • 涉及到的java API
      • import org.jdom2.Document;
        import org.jdom2.Element;
        import org.jdom2.JDOMException;
        import org.jdom2.input.SAXBuilder;
        import org.jdom2.Attribute;
        import org.jdom2.Document;
        import org.jdom2.Element;
        import org.jdom2.output.XMLOutputter;
    • 编程思路:
      • 首先从http://www.jdom.org/下载JDOM相应开发包,并且将其集成至自己的project中
      • 其次针对项目实际需求使用JDOM组件提供的相应java API编写程序实现相应操作
        • 实例1,xml文件的读取
          • 涉及到的类:
            • import java.io.File;
              import java.io.IOException;
              import java.util.List;
              
              import org.jdom2.Document;
              import org.jdom2.Element;
              import org.jdom2.JDOMException;
              import org.jdom2.input.SAXBuilder;
          • 编程思路:  
            • /**
               * step1,创建SAXBuilder,并且使用该对象创建DOM树
               * step2,通过前面创建的*.xml对应的DOM树访问树中的元素
                       * */
        • 实例2,修改已有xml文件(或者新建一个xml文件)
          • 涉及到的类:
            import java.io.File;
            import java.io.FileNotFoundException;
            import java.io.FileOutputStream;
            import java.io.IOException;
            
            import org.jdom2.Attribute;
            import org.jdom2.Document;
            import org.jdom2.Element;
            import org.jdom2.output.XMLOutputter;
          • 编程思路:

            • /**step1,创建待写入到*.xml中的元素(标签、属性、标签内容)
              *    step2,创建DOM树并且向该DOM树中添加子节点
              *   step3,将上面创建的DOM树写入到*.xml中
                       * 
                       */
    • 示例:
      • 示例一,使用JDOM组件提供的java API生成一个xml文件,使得该文件包含以下内容
        • 编程实现:
          • /**
            *@author lxrm
            *@date 2017年4月10日
            *@description:*/
            package xml.operation;
            
            import java.io.File;
            import java.io.FileNotFoundException;
            import java.io.FileOutputStream;
            import java.io.IOException;
            
            import org.jdom2.Attribute;
            import org.jdom2.Document;
            import org.jdom2.Element;
            import org.jdom2.output.XMLOutputter;
            
            public class JDOM_Exam1_WriteXMLFile {
                public static void main(String[] args){
                    /**step1,创建待写入到*.xml中的元素(标签、属性、标签内容)
                     * 
                     */
                    //定义节点(标签),并为标签赋值
                    Element addresslist=new Element("addresslist");
                    Element linkman=new Element("linkman");
                    
                    Element name=new Element("name");
                    name.setText("lxrm");
                    //定义节点属性,并将属性绑定到节点(标签)
                    Attribute id=new Attribute("id","001");
                    name.setAttribute(id);
                    
                    Element email=new Element("email");
                    email.setText("123@qq.com");
                    
                    /**
                     * step2,创建DOM树并且向该DOM树中添加子节点*/
                    //创建DOM树
                    Document dom=new Document(addresslist);//创建DOM树(即Document对象),并以addresslist为根节点
                    //为该DOM树添加子节点
                    addresslist.addContent(linkman);
                    linkman.addContent(name);
                    linkman.addContent(email);
                    
                    /**
                     * step3,将上面创建的DOM树写入到*.xml中*/
                    XMLOutputter outputter = new XMLOutputter();
                    outputter.setFormat(outputter.getFormat().setEncoding("GBK"));
                    String path="D:"+File.separator+"test.xml";
                    try {
                        outputter.output(dom, new FileOutputStream(path));
                    } catch (FileNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        • 程序运行结果:

          • 生成了一个D:/test.xml文件(如果该文件已经存在,则用新生成的文件替换原有文件)      

      • 示例二,读取*.xml文件中的内容
        • 待读取的*.xml文件
          <?xml version="1.0" encoding="GBK"?>
          <addresslist>
              <linkman><name id="001">lxrm</name><email>123@qq.com</email></linkman>
              <linkman><name id="002">lx</name><email>123@qq.com</email></linkman>
          
          </addresslist>
        • 编程实现:
          /**
          *@author lxrm
          *@date 2017年4月10日
          *@description:*/
          package xml.operation;
          
          import java.io.File;
          import java.io.IOException;
          import java.util.List;
          
          import org.jdom2.Document;
          import org.jdom2.Element;
          import org.jdom2.JDOMException;
          import org.jdom2.input.SAXBuilder;
          
          public class JDOM_Exam2_ReadXMLFile {
              public static void main(String[] args){
                  /**
                   * step1,创建SAXBuilder,并且使用该对象创建DOM树
                   * */
                  String file="D:"+File.separator+"test.xml";
                  SAXBuilder builder=new SAXBuilder();
                  Document dom=null;//创建DOM树
                  try {
                      dom=builder.build(file);
                  } catch (JDOMException | IOException e) {
                      // TODO Auto-generated catch block
                      e.printStackTrace();
                  }
                  
                  /**
                   * step2,通过前面创建的*.xml对应的DOM树访问树中的元素
                   * */
                  Element addresslist=dom.getRootElement();
                  List list=addresslist.getChildren("linkman");
                  for(int i=0;i<list.size();i++){
                      Element linkman=(Element) list.get(i);
                      String name=linkman.getChildText("name");
                      String id=linkman.getChild("name").getAttributeValue("id");
                      String email=linkman.getChildText("email");
                      System.out.println("编号:"+id+" 姓名:"+name+" 邮箱:"+email);
                  }
              }
          }

          程序运行结果:

          编号:001 姓名:lxrm 邮箱:123@qq.com
          编号:002 姓名:lx 邮箱:123@qq.com

5.3 DOM4J(另一种用于XML文件解析的java组件)

5.3.1概述

    • DOM和SAX解析方法都有各自的缺点,所以其他一些学者就开始研究有没有更好地XML文档解析方案,很多好的XML文档解析方法应运而生,但是水平参差不齐,后来JDOM和DOM4J凭借着自己的优良性能展露头角,得到广泛流行
    • 上面一节讲述了JDOM的用法,这节讲述另一种组件——DOM4J的用法
    • DOM4J和JDOM一样,也是在基础的XML文件解析API上发展而来的,同时拥有两种解析方法的优点
    • DOM4J是SourceForge发表的  
    • DOM4J也是开源的
    • 可以从http://sourceforge.net/projects/dom4j/files网址下载DOM4J开发包(该开发包中包含很多jar包,一般情况下只需要引入dom4j-*.jar和lib/jaxen-*-beta-*.jar这两个jar包到自己的项目即可,至于其他的jar包,则可以根据实际需求选用)
    • DOM4J得到了广泛应用,如Hibernate/Spring框架中都使用了DOM4J
    • DOM4J组件所提供的常用接口如下表,一般在自己的project中使用下面这些接口解析*.xml文件(这些接口的用法和JDOM中相应接口的用法类似)

5.3.2使用DOM4J组件提供的javaAPI操作*.xml

    • 涉及到的类(java API):
      •   
    • 编程思路:
      • 首先从http://sourceforge.net/projects/dom4j/files下载DOM4J相应开发包,并且将其集成至自己的project中
      • 其次针对项目实际需求使用DOM4j组件提供的相应java API编写程序实现相应操作
        • 实例1,xml文件的读取
          • 涉及到的类:
            • import java.io.File;
              import java.util.Iterator;
              
              import org.dom4j.Document;
              import org.dom4j.DocumentException;
              import org.dom4j.Element;
              import org.dom4j.io.SAXReader;
                
          • 编程思路:
            • /**
               * step1,创建SAXReader对象,将*.xml文档转变成DOM树
               *step2,通过step1中建立的DOM树访问树中节点内容(也即XML文件标签内容)
                       * */
                
          • 示例:
            • 问题描述:读取*.xml中的内容,并在后台输出相应内容  
              <?xml version="1.0" encoding="GBK"?>
              
              <addresslist>
                <linkman>
                  <name>lxrm</name>
                  <email>123@123.com</email>
                </linkman>
                <linkman>
                  <name>lx</name>
                  <email>123@123.com</email>
                </linkman>
                <link>
                  <name>link子节点</name>
                  <email>123@123.com</email>
                </link>
              </addresslist>

              编程实现:

              /**
              *@author lxrm
              *@date 2017年4月10日
              *@description:*/
              package xml.operation;
              
              import java.io.File;
              import java.util.Iterator;
              
              import org.dom4j.Document;
              import org.dom4j.DocumentException;
              import org.dom4j.Element;
              import org.dom4j.io.SAXReader;
              
              public class DOM4J_Exam2_ReadXMLFile {
                  public static void main(String[] args){
                      
                      /**
                       * step1,创建SAXReader对象,将*.xml文档转变成DOM树
                       * */
                      String path="D:"+File.separator+"testDOM4J.xml";
                      File file=new File(path);
                      SAXReader reader=new SAXReader();
                      Document dom=null;
                      try {
                          dom=reader.read(file);
                      } catch (DocumentException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                      }
                      
              
                      /**
                       * step2,通过step1中建立的DOM树访问树中节点内容(也即XML文件标签内容)
                       * */
                      Element root=dom.getRootElement();//根节点“addresslist”
                      Iterator it=root.elementIterator();//根节点的一级子节点(直接子节点)的集合
                      while(it.hasNext()){
                          Element linkman=(Element) it.next();
                          String name=linkman.elementText("name");
                          String email=linkman.elementText("email");
                          System.out.println("姓名:"+name+" 邮箱:"+email);
                      }
                  }
              }

              运行结果:

              姓名:lxrm 邮箱:123@123.com
              姓名:lx 邮箱:123@123.com
              姓名:link子节点 邮箱:123@123.com
        • 实例2,修改*.xml文件(或者新建*.xml文件)
          • 涉及到的类:
            • import java.io.File;
              import java.io.FileNotFoundException;
              import java.io.FileOutputStream;
              import java.io.IOException;
              import java.io.UnsupportedEncodingException;
              
              import org.dom4j.Document;
              import org.dom4j.DocumentHelper;
              import org.dom4j.Element;
              import org.dom4j.io.OutputFormat;
              import org.dom4j.io.XMLWriter;
                
          • 编程思路:  
            • /**
                       * step1,创建待写入*.xml文件的DOM树
                      * step2,将step1中创建的DOM树输出成*.xml文件
                       */
          • 示例:

            • 问题描述:希望通过java程序创建一个拥有如下内容的*.xml文件

            • 编程实现:

                      

              • /**
                *@author lxrm
                *@date 2017年4月10日
                *@description:使用SourceForge公司开发并开源的DOM4J组件来进行xml文件的解析操作
                *
                *本程序功能:新建一个*.xml文件,并且在本java程序中定义该*.xml文件的内容
                *
                **/
                package xml.operation;
                
                import java.io.File;
                import java.io.FileNotFoundException;
                import java.io.FileOutputStream;
                import java.io.IOException;
                import java.io.UnsupportedEncodingException;
                
                import org.dom4j.Document;
                import org.dom4j.DocumentHelper;
                import org.dom4j.Element;
                import org.dom4j.io.OutputFormat;
                import org.dom4j.io.XMLWriter;
                
                public class DOM4J_Exam1_WriteXMLFile {
                
                    public static void main(String[] args) {
                        
                        /**
                         * step1,创建待写入*.xml文件的DOM树
                         */ 
                        Document dom=DocumentHelper.createDocument();
                        Element addresslist=dom.addElement("addresslist");//直接在Document对象上添加根节点
                        Element linkman=addresslist.addElement("linkman");
                        Element name=linkman.addElement("name");
                        Element email=linkman.addElement("email");
                        name.setText("lxrm");
                        email.setText("123@123.com");
                        
                        /**
                         * step2,将step1中创建的DOM树输出成*.xml文件
                         *         
                         */
                        OutputFormat format=OutputFormat.createPrettyPrint();
                        format.setEncoding("GBK");
                        String file="D:"+File.separator+"testDOM4J.xml";
                        try {
                            XMLWriter writer=new XMLWriter(new FileOutputStream(file),format);
                            writer.write(dom);
                            writer.close();
                        } catch (UnsupportedEncodingException | FileNotFoundException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                
                }
                  
            • 运行结果: 

              •    

                  

    

 

学习的过程中总会得到一些心得体会,认真地将它们记录下来并分享给每一个愿意花费时间去阅读它们的人,然后意外地收获某个读者的评论,从而激发出新的感想,是一件十分令人欢快的事。如果你也在研习这方面的知识,欢迎加入到我们的队伍中来,和我们一起进步吧(^_^)
原文地址:https://www.cnblogs.com/lxrm/p/6658572.html