码迷,mamicode.com
首页 > 其他好文 > 详细

xml基础及其解析xml文档

时间:2016-06-12 02:10:20      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:

xml基础及其解析xml文档



xml基础语法


一个基本的xml构成:

<!--version指的是xml为版本,将其写死为1.0即可-->
<!--encoding 代表是文档的编码声明 通常我们使用的是utf-8 这个声明使得平台在打开xml文件时使用的utf-8进行解码-->
<?xml version="1.0" encoding="utf-8" ?>
<!--xml语法中,根节点要求是唯一的-->
<根节点>
<!--多个子节点的申明-->
    <子节点>

    </子节点>

</根节点>

注意:xml标签区分大小写,并且xml标签不能以数字开头,标签名中间不能使用空格,下面是几种错误的写法:

<2contach>
    <!--标签不能以数字开头-->
</2contach>

<contact list>
    <!--错误的标签使用方法,不能再标签中使用空格-->
</contact list>

<Contact>
    <!--标签区分大小写,并且要正确的配对,显然该标签不能配对-->
</contact>
中国特色乱码问题

首先出现乱码一定是由于编码与解码采用的标准不一样,我们能看到的中文等都属于字符,从字符变成字节的过程我们成为编码,从字节变成字符的过程我们称之为解码,对于chrome浏览器,默认使用的是utf-8编码进行解码,当然可以自己设置,但是由于我们的编写xml文件的工具不同,导致可能进行编码采用的不是utf-8,所以会出现编码与解码采用的码表是不一样的。

  • 写完xml进行保存的时候(也就是将整个xml文件保存到硬盘中,保存到硬盘中要进行编码成为二进制的10格式),实际上也就是编码过程(保存时使用utf-8)
  • 打开或者解析xml文件的时候,实际上也就是解码过程(解码时采用utf-8)

上述的两个地方应该保持一致才不会出现乱码。注意在Windows上默认的编码格式ANSI在中国的计算机平台上实际上就是GBK编码。

写xml文件的工具

  • 记事本、EditPlus等 注意保存时使用utf-8编码
  • MyEclipse 如果在MyEclipse工具开发xml文件,保存xml文件时会按照文档声明的encoding来保存xml文件
  • workbench 一个开源的可视化xml生成器

注意:在打开修改xml文件时,要注意保存时的编码格式

xml中使用的转义字符

在xml文件中内置了一些特殊的字符,这些特殊字符不能直接被浏览器原样输出,如果希望把这些字符按照浏览器的原样输出,那么就需要使用转义字符来实现。

<?xml version="1.0" encoding="utf-8" ?>
<codes>
    <code>
<!--下面的部分我希望其按照html的原样输出-->
      <!--  <p>段落</p> -->
      &lt;p$gt; 段落 &lt;/p&gt;

      <code>

<!--我们想把下面的内容都原样输出,怎么办?仍然全部采用转义字符吗?写的太复杂,又简单的方法,使用CDATA块-->
<!--CDATA块的作用:直接对包含一些特殊字符的内容统一进行原样输出,避免了一个个的进行转义-->
<!--CDATA语法如下:将需要转义的内容包起来即可-->
        <![CDATA[  
          <html>
             <head>
                 <title>这是一个xml文件</title>
             </head> 

             <body>

             </body>
             </html>
          ]]>
      </code>
    </code>
</codes>

常用的特殊字符 转义字符

<             &lt;
>             &gt;
‘‘            &quot;
&             &amp;
空格           &nbsp;
处理指令–已经过时

处理指令的作用:告诉解析器怎样去解析该xml文档,用的最多的就是下面的一个申明,但是实际上也根本不用。

<?xml-stylesheet type="text/css" href="a.css" ?>

需要提取xml的内容,可以使用xml-stylesheet指令。

<?xml version="1.0" encoding="utf-8" ?>
<!--不引用任何的css文件,此时就能提取出所有的信息,标签除外,此种情况会将所有除标签之外的内容提出出来,排列在一行,当然我们可指定css文件改变这种布局-->
<?xml-stylesheet type="text/css" href="" ?>
<codes>
    <code>
<!--下面的部分我希望其按照html的原样输出-->
      <!--  <p>段落</p> -->
      &lt;p$gt; 段落 &lt;/p&gt;

      <code>

<!--我们想把下面的内容都原样输出,怎么办?仍然全部采用转义字符吗?写的太复杂,又简单的方法,使用CDATA块-->
<!--CDATA块的作用:直接对包含一些特殊字符的内容统一进行原样输出,避免了一个个的进行转义-->
<!--CDATA语法如下:将需要转义的内容包起来即可-->
        <![CDATA[  
          <html>
             <head>
                 <title>这是一个xml文件</title>
             </head> 

             <body>

             </body>
             </html>
          ]]>
      </code>
    </code>
</codes>

我们引入css文件,改变默认抽取出来排放的规则。

<?xml version="1.0" encoding="utf-8" ?>
<!--不引用任何的css文件,此时就能提取出所有的信息,标签除外,此种情况会将所有除标签之外的内容提出出来,排列在一行,当然我们可指定css文件改变这种布局-->
<?xml-stylesheet type="text/css" href="a.css" ?>
<contactlist>
    <contect id="001">
        <name>张三</name>
        <telephone>120</telephone>
    </contect>

    <contect id="002">
        <name>李四</name>
        <telephone>110</telephone>
    </contect>
</contactlist>

a.css

/*这种控制方式就相当于在html中一样的写法,xml也可以作为网页的布局功能,但是根本不推荐这么去做,早期想要使用xml去取代html,但是html5出现之后,不用xml去替代*/
contect{
    font-size:20px;
    font-color:red;
    width:100px;
    height:100px;
    display:block;
    margin-top:40px;
    background-color:green;
}

上面的功能在xml中已经不再使用,但是xml仍然保留了这种功能,一般不会使用时,不要去刻意使用,如果要用到再去学就行了。

xml的两个重要的功能

下面两个作用在Java Web的开发中普遍使用

  • 作为一个小型的数据库来保存数据,这相当于数据载体
  • 作为软件的配置文件
xml注释

<!--注释的内容-->

xml解析–Java应用程序读取xml文件的内容


xml文件除了给开发者看,但是更多的时候是使用程序去读取xml的内容,此时我们称为xml的解析。

xml解析原理

关于xml解析原理我们使用下面的xml代码进行使用和解析。

<?xml version="1.0" encoding="utf-8" ?>
<contactlist>
    <contact id="001">
        <name>张三</name>
        <telephone>15338607192</telephone>
        <age>20</age>
        <email>zhangsan@qq.com</email>
        <qq>13101900</qq>
    </contact>

     <contact id="002">
        <name>李四</name>
        <telephone>15338607193</telephone>
        <age>20</age>
        <email>lisi@qq.com</email>
        <qq>13101901</qq>
    </contact>

    <contact id="003">
        <name>王五</name>
        <telephone>15338607194</telephone>
        <age>21</age>
        <email>wangwu@qq.com</email>
        <qq>13101902</qq>
    </contact>
</contactlist>

xml解析器在解析xml文档时,把xml文件的各个部分封装成对象,通过这些对象去操作xml文档,这个过程叫做DOM编程。解析的方式有且只有两种(从原理的角度上讲):

  • DOM解析原理:xml解析器一次性将整个xml文档加载进内存,然后在内存中构建一棵Document对象树,通过Document对象可以得到树上的节点对象,通过节点对象就可以操作整个xml文档的内容。

在读取xml文档之后,会在内存中形成一棵DOM树,xml文件中的标签作为DOM树的节点,并且xml文档的根节点作为DOM树的根节点,所有的标签构成了一棵具有层次的树。节点存在一些信息:如节点名称、节点类型(标签节点、属性节点、文本节点、注释节点)。DOM解析是面向对象的编程。具体我们在使用时不用Node对象,而是使用其子类的三个对象。下面显示了DOM面向编程过程中常用的对象。

xml文档 —————-> Document对象 代表整个xml文档
节点 —————>Node对象 父类
标签节点 —————> Element对象 子类
属性节点 —————> Attribute对象 子类
文本节点 —————>Text对象 子类

那么我们怎么拿到这些对象信息呢?使用Document对象,它代表的是一个完整的xml文档,从而使得整个xml文档可以被读进去。

  • SAX解析原理
xml解析工具

工具是某种原理之下具体的实现方式,基于上面的两种解析方式,出现了很多的工具,大致分为下面几个:

  • DOM解析工具

    • JAXP(Oracle官方的工具) 没人用,难用
    • JDOM(非官方的民间组织开发的工具) 也较为难用
    • DOM4J(JDOM组织出来一批人开发的) 最为流行,最好用 三个框架(SSH)默认都使用的是DOM4J去读取xml内容
    • 其它解析工具,不入流,不讨论
  • SAX解析工具

    • Sax解析工具 (Oracle官方提供的解析工具)

DOM4J使用


DOM4J是基于DOM解析原理实现的xml文档解析工具,不包含在我们官方的JDK中,所以我们在使用的时候很关键的一点就是导包,导包,并且将其源码实现关联,以方便我们查看源代码,另外还有需要注意的是:使用第三方工具千万不能导错包,导包时要注意看清楚

contact.xml

<?xml version="1.0" encoding="utf-8" ?>
<!--在整个xml文档中只能有一个根元素 在该xml文档中是contactlist -->
<contactlist>
    <contact id="001">
        <name>张三</name>
        <telephone>15338607192</telephone>
        <age>20</age>
        <email>zhangsan@qq.com</email>
        <qq>13101900</qq>
    </contact>

     <contact id="002">
        <name>李四</name>
        <telephone>15338607193</telephone>
        <age>20</age>
        <email>lisi@qq.com</email>
        <qq>13101901</qq>
    </contact>

    <contact id="003">
        <name>王五</name>
        <telephone>15338607194</telephone>
        <age>21</age>
        <email>wangwu@qq.com</email>
        <qq>13101902</qq>
    </contact>
</contactlist>
DOM4J中核心API

  • Element getRootElement(); //得到根标签
    • List element = rootElement.elements();
    • rootElement.element(“指定标签名称”); //只能返回指定名称的第一个标签
    • rootElement.elementIterator(“执行名称”); //指定名称的所有标签
    • rootElement.elementIterator();
  • Iterator nodeIterator(); //得到一个节点的迭代器


  • Element.attributesValue(“属性名”); //获取当前的属性值

  • Element.attribute(“属性名”); //获取当前的属性对象
  • Element.attributes(); //返回List对象
  • Element.attributeIterator(); //返回一个迭代器
  • Attribute.getName(); //拿到属性名
  • Attribute.getValue(); //拿到属性值

  • Element.getText(); //获取当前指定标签下的文本内容
  • Element.elementText(“标签名”);//获取指定标签的文本内容
将xml文档从磁盘读进内存,形成Document对象

testParseXml.java

package com.jpzhutech.xml;

import java.io.File;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.junit.Test;

public class ParseXml {
    @Test
    public void testParseXml(){
        SAXReader reader = new SAXReader();  //创建一个xml文档的解析器
        try {
            Document document = reader.read(new File("./src/contact.xml"));  //读取xml文档,并且返回Document对象
            System.out.println(document);  //输出为:org.dom4j.tree.DefaultDocument@2e3fe12e [Document: name file:///G:/Java/source/xml/./src/contact.xml]
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }
}
读取所有的标签节点

将磁盘中的xml文档读进内存形成Document对象之后,此时我们就可以读取其中的标签、属性、文本等的内容了。
* 拿到所有的标签节点(Element) 使用nodeIterator方法进行循环迭代就能一层层的取出其中的标签节点

readXmlContext.java

package com.jpzhutech.xml;

import java.io.File;
import java.util.Iterator;
import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;

public class readXmlContext {
    //主要目的用于得到节点的信息
    @Test
    public void test1(){
        SAXReader reader = new SAXReader();  //获取reader用于将xml读进内存形成Document对象
        try {
            Document document = reader.read(new File("./src/contact.xml")); //其中.代表的是整个项目的根目录
            Iterator<Node> nodeIterator = document.nodeIterator(); //得到节点的迭代器,返回的是所有的子节点对象只包含直接的子节点,不包含孙子节点甚至更为以下的节点
            while(nodeIterator.hasNext()){  
                Node node = nodeIterator.next();
                String name = node.getName();
                System.out.println(name);

                //继续取出下面的子节点,一定要明白,只有标签才有子节点,其它的比如属性、文本等都没有子节点

                if(node instanceof Element){ //判断是否为节点,这样才能继续向下读取子节点
                    Element element = (Element) node;   //如果节点为标签节点,将其进行强制类型转换为标签节点
                    Iterator<Node> nodeIterator2 = element.nodeIterator();
                    while(nodeIterator2.hasNext()){
                        Node next = nodeIterator2.next();
                        String name2 = next.getName();
                        System.out.println(name2);

                        if(next instanceof Element){
                            Element element2 = (Element)next;
                            Iterator<Node> nodeIterator3 = element2.nodeIterator();
                            while(nodeIterator3.hasNext()){
                                Node next2 = nodeIterator3.next();
                                String name3 = next2.getName();
                                System.out.println(name3);
                            }
                        }
                    }

                }
            }
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }  
    }
}

稍微对上面的方法进行了改造,在获取其中的根标签时使用了getRootElement(),而不是把根标签当做一个普通的标签

package com.jpzhutech.xml;

import java.io.File;
import java.util.Iterator;

import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;

public class readXmlContext {
    //主要目的用于得到节点的信息
    @Test
    public void test1(){
        SAXReader reader = new SAXReader();  //获取reader用于将xml读进内存形成Document对象
        try {
            Document document = reader.read(new File("./src/contact.xml")); //其中.代表的是整个项目的根目录
            Iterator<Node> nodeIterator = document.nodeIterator(); //得到节点的迭代器,返回的是所有的子节点对象只包含直接的子节点,不包含孙子节点甚至更为以下的节点
            while(nodeIterator.hasNext()){  
                Node node = nodeIterator.next();
                String name = node.getName();
                System.out.println(name);

                //继续取出下面的子节点,一定要明白,只有标签才有子节点,其它的比如属性、文本等都没有子节点

                if(node instanceof Element){ //判断是否为节点,这样才能继续向下读取子节点
                    Element element = (Element) node;   //如果节点为标签节点,将其进行强制类型转换为标签节点
                    Iterator<Node> nodeIterator2 = element.nodeIterator();
                    while(nodeIterator2.hasNext()){
                        Node next = nodeIterator2.next();
                        String name2 = next.getName();
                        System.out.println(name2);

                        if(next instanceof Element){
                            Element element2 = (Element)next;
                            Iterator<Node> nodeIterator3 = element2.nodeIterator();
                            while(nodeIterator3.hasNext()){
                                Node next2 = nodeIterator3.next();
                                String name3 = next2.getName();
                                System.out.println(name3);
                            }
                        }
                    }

                }
            }
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }  
    }

    @Test
    public void test2(){
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(new File("./src/contact.xml"));
            Element rootElement = document.getRootElement();  //得到根标签,因为整个xml文档有且只有一个根标签
            //System.out.println(rootElement);

            //拿根节点下面的子节点(根标签下面的子标签)
            getChildNodes(rootElement);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }

    public void getChildNodes(Element element){
        System.out.println(element.getName());
        Iterator<Node> nodeIterator = element.nodeIterator();
        while(nodeIterator.hasNext()){
            Node next = nodeIterator.next();
            String name = next.getName();
            System.out.println(name);

            if(next instanceof Element){
                Element element2 = (Element)next;
                getChildNodes(element2);  //递归的将所有的节点读出来
            }

        }
    }
}
package com.jpzhutech.xml;

import java.io.File;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;

public class readXmlContext {
    //主要目的用于得到节点的信息
    @Test
    public void test1(){
        SAXReader reader = new SAXReader();  //获取reader用于将xml读进内存形成Document对象
        try {
            Document document = reader.read(new File("./src/contact.xml")); //其中.代表的是整个项目的根目录
            Iterator<Node> nodeIterator = document.nodeIterator(); //得到节点的迭代器,返回的是所有的子节点对象只包含直接的子节点,不包含孙子节点甚至更为以下的节点
            while(nodeIterator.hasNext()){  
                Node node = nodeIterator.next();
                String name = node.getName();
                System.out.println(name);

                //继续取出下面的子节点,一定要明白,只有标签才有子节点,其它的比如属性、文本等都没有子节点

                if(node instanceof Element){ //判断是否为节点,这样才能继续向下读取子节点
                    Element element = (Element) node;   //如果节点为标签节点,将其进行强制类型转换为标签节点
                    Iterator<Node> nodeIterator2 = element.nodeIterator();
                    while(nodeIterator2.hasNext()){
                        Node next = nodeIterator2.next();
                        String name2 = next.getName();
                        System.out.println(name2);

                        if(next instanceof Element){
                            Element element2 = (Element)next;
                            Iterator<Node> nodeIterator3 = element2.nodeIterator();
                            while(nodeIterator3.hasNext()){
                                Node next2 = nodeIterator3.next();
                                String name3 = next2.getName();
                                System.out.println(name3);
                            }
                        }
                    }

                }
            }
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }  
    }

    @Test
    public void test2(){
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(new File("./src/contact.xml"));
            Element rootElement = document.getRootElement();  //得到根标签,因为整个xml文档有且只有一个根标签
            //System.out.println(rootElement);

            //拿根节点下面的子节点(根标签下面的子标签)
            getChildNodes(rootElement);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }

    public void getChildNodes(Element element){
        System.out.println(element.getName());
        Iterator<Node> nodeIterator = element.nodeIterator();
        while(nodeIterator.hasNext()){
            Node next = nodeIterator.next();
            String name = next.getName();
            System.out.println(name);

            if(next instanceof Element){
                Element element2 = (Element)next;
                getChildNodes(element2);  //递归的将所有的节点读出来
            }

        }
    }

    @Test
    public void test3(){
        SAXReader reader = new SAXReader();
        Document document;
        try {
            document = reader.read(new File("./src/contact.xml"));

            /*// 1. 得到根标签
            Element rootElement = document.getRootElement();

            //得到标签名称
            String name = rootElement.getName();
            System.out.println(name);
            */
            /*//2. 得到根标签的子标签
            Element element = rootElement.element("contact");  //得到当前标签下面指定名称的第一个子标签
            System.out.println(element.getName());*/


            /*//3. 拿到跟标签下面所有的子标签
            Iterator<Element> elementIterator = rootElement.elementIterator("contact");
            while(elementIterator.hasNext()){
                Element next = elementIterator.next();
                String name2 = next.getName();
                System.out.println(name2);
            }*/

            /*//4. 使用另外的迭代器方法
            Iterator<Element> elementIterator2 = rootElement.elementIterator();
            while(elementIterator2.hasNext()){
                Element next = elementIterator2.next();
                String name2 = next.getName();
                System.out.println(name2);
            }*/

            /*//使用list集合来存放所有的成员
            List<Element> elements = rootElement.elements();*/

            /*
            //遍历list的第一种方式,使用迭代器
            Iterator<Element> iterator = elements.iterator();
            while(iterator.hasNext()){
                Element next = iterator.next();
                System.out.println(next.getName());
            }*/

            /*
            //遍历list的第二种方式,使用for循环
            for(int i = 0 ; i < elements.size(); i++){
                Element element = elements.get(i);
                System.out.println(element.getName());
            }
            */

            /*
            //遍历list的第三种方式,增强for循环
            for(Element element : elements){
                System.out.println(element.getName());
            }
            */

            //拿到某一个指定标签的孙子标签
            Element element = document.getRootElement().element("contact").element("name");  //只能一个个的获取,目前还没有很好的方法解决
            System.out.println(element.getName())s;
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }  //将xml文档转换成一个Document对象



    }
}

在输出中出现了很多的null,这是为什么呢?在后面获取文本标签时会说明原因。

读取所有的属性节点

@Test
    public void test4(){
        //得到属性标签以及属性值
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(new File("./src/contact.xml"));

            //首先我想读取contact标签下面的id=001属性,想要获取属性就要先获得属性所在的标签对象
            Element element = document.getRootElement().element("contact");  //得到属性所在的标签对象

            /*//得到属性对象,得到指定名称的属性值
            String attributeValue = element.attributeValue("id");
            System.out.println(attributeValue);*/

            /*//得到属性对象,得到该标签下所有的属性并获得其属性值
            List<Attribute> attributes = element.attributes();
            ListIterator<Attribute> listIterator = attributes.listIterator();
            while(listIterator.hasNext()){
                Attribute next = listIterator.next();
                System.out.println(next.getName());
                String value = next.getValue();
                System.out.println(value);
            }*/

            /*//使用迭代器获取指定标签下的所有的属性值
            Iterator<Attribute> attributeIterator = element.attributeIterator();
            while(attributeIterator.hasNext()){
                Attribute next = attributeIterator.next();
                String name = next.getName();
                String value = next.getValue();
                System.out.println(name+"="+value);
            }*/

            /*//仍然是返回指定的属性
            Attribute attribute = element.attribute("name");
            String name = attribute.getName();
            String value = attribute.getValue();
            System.out.println(name + "=" + value);*/



        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }
读取所有的文本节点

@Test
    public void test5(){
        //获取文本内容,想要拿到文本首先要拿到标签
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read("./src/contact.xml");

            /*//首先获取标签
            Element element = document.getRootElement().element("contact").element("name");

            //拿到指定文本内容
            String text = element.getText();
            System.out.println(text);*/

            String elementText = document.getRootElement().element("contact").elementText("telephone");
            System.out.println(elementText);
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
    }
解决上面提出的问题

实际上在xml文档中空格、换行都是算xml文档的内容,不能忽略掉,也就是说在读取的时候,如果空格、换行出现了,那么我们应该将其中的内容读出。

xml基础及其解析xml文档

标签:

原文地址:http://blog.csdn.net/jpzhu16/article/details/51638376

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!