XML

1.什么是XML

XML的作用:处理有关系的数据,它允许用户自定义标签,一个标签用于描述一段数据;一个标签可以分为开始标签和结束标签,在开始标签和结束标签之间,又可以使用其他标签描述其他数据,以此来实现数据关系的描述。

2.XML常见应用

  • XML技术除了用于保存有关系的数据之外,它还经常用于软件配置文件,以描述程序模板之间的关系
  • 在一个软件系统中,为提高系统的灵活性,它所启动的模块通常由配置文件决定(例如一个软件在启动时,它需要启动A,B两个模块,而A,B这两个模块在启动时,又分别需要A1,A2和B1,B2模块的支持,为了准确描述这种关系,此时使用XML文件最为合适)
<soft>
    <a>
        <a1></a1>
        <a2></a2>
    </a>
    <b>
        <b1></b1>
        <b2></b2>
    </b>
</soft>

3.XML语法

1.文档声明

在编写XML文档时,需要先使用文档声明,声明XML文档的类型

固定格式为

<?xml            ?>

在空格里面写版本和编码格式<?xml和?>是固定格式,不能修改,中间连空格都不能有,要一模一样。

注意:写的时候如果想用空格将内容隔开,只能用英文空格。

标准写法:其中version代表版本,encoding代表编码,standalone代表文档是否独立(是否依赖别的文档)

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

2.元素

  • XML元素指XML文件中出现的标签

    包含标签体:<a>javaweb</a>

    不含标签体:<a></a>(简写为<a/>)

  • 一个标签中也可以嵌套若干子标签。但所有标签必须合理的嵌套,绝对不允许交叉嵌套
  • 格式良好的XML文档必须有且仅有一个根标签,其他标签都是这个根标签的子孙标签
  • 对于XMl标签中出现的所有空格和换行,XML解析程序都会当作标签内容进行处理(所以在编写XML文件时,使用换行和缩进等方式来让原文件中的内容清晰可读的“良好”书写习惯可能要被迫改变)
  • 一个XML元素可以包含字母,数字以及其他一些可见字符,但是必须遵守下面一些规范

    区分大小写

    不能以数字或“_”开头

    不能以xml(XML或Xml等开头)

    不能包含空格

    名称中间不能包含冒号(:)

3.属性

  • 一个标签可以有多个属性,每个属性都有它自己的名字和取值  
  <input name="text">
  • 属性值一定要用双引号或单引号引起来
  • 定义属性必须遵循和标签相同的命名规范
  • 在XML技术中,标签所代表的信息,也可以被改成用子元素的形式来描述
  <input>
      <name>text</name>
  </input>

4.注释

  • XML文件中的注释采用:<!--注释-->
  • XML声明之前不能有注释
  • 注释不能嵌套

5.CDATA区

  • 在编写XML文件时,有些内容可能不想让解析引擎解析执行,而是当作原始内容处理,遇到这种情况,可以把这些内容放在CDATA区里,对于CDATA区域的内容,XML解析程序不会处理,而是直接原封不动的输出
  • 语法:<![CDATA[内容]]>
  <![CDATA[
          <a>JavaWeb</a>
  ]]>

6.转义字符

  • &lt; < 小于号 
  • &gt; > 大于号 
  • &amp; & 和 
  • &apos; ' 单引号 
  • &quot; " 双引号

7.处理指令

  • 处理指令,简称PI。处理指令用来指挥解析引擎如何解析XML文档内容

  

  • 例如,在XML文档中可以使用xml-stylesheet指令,通知XML解析引擎,应用css文件现实XML文档内容。

  

  <?xml-stylesheet type="text/css" href="1.css" ?>
  • 处理指令必须以“<?”开头,以"?>"作为结尾,XML声明语句就是最常见的一种处理指令

4.XML约束

什么是XML约束:在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束

常用的约束技术:XML DTD,XML Schema

 

1.DTD

先举个例子写个book.dtd来约束book.xml

book.dtd

1 <!ELEMENT 书架 (书+)>
2 <!ELEMENT 书 (书名,作者,售价)>
3 <!ELEMENT 书名 (#PCDATA)>
4 <!ELEMENT 作者 (#PCDATA)>
5 <!ELEMENT 售价 (#PCDATA)>

book.xml

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE 书架 SYSTEM "book.dtd">
 3 <书架>
 4     <>
 5         <书名>java就业培训教程</书名>
 6         <作者>张孝祥</作者>
 7         <售价>39.00元</售价>
 8     </>
 9     <>
10         <书名>javaScript网页开发</书名>
11         <作者>张孝详</作者>
12         <售价>28.00元</售价>
13     </>
14 </书架>

这样就约束了book.xml的书写,也就是书架里面只能有书,书必须有书名,作者,售价,而且顺序不能改变。

2.DTD语法

  • 引用DTD约束

    当引用的文件在本地时,采用如下方式:

    <!DOCTYPE XML文档根节点 SYSTEM "DTD文件的URL">

    当引用的文件是一个公共的文件时,采用如下方法

    <!DOCTYPE XML文档根节点 PUBLIC "DTD名称" "DTD文件的URL">

  • 元素定义

    在DTD文档中使用ELEMENT声明一个XML元素,语法格式如下:

    <!ELEMENT 元素名称 元素类型>

    元素类型可以是元素内容,或类型,下面举例子

    元素类型为元素内容:<!ELEMENT 书 (书名,作者,售价)>

    元素类型为类型:<!ELEMENT 书名 (#PCDATA)>

    DTD规范定义了,EMPTY表示空元素,ANY表示元素内容为任意类型

    元素内容中可以用如下方式,描述内容的组成关系

    用逗号分隔,表示内容的出现顺序必须和声明时一致:<!ELEMENT 书 (书名,作者,售价)>

    用 | 分隔,表示任选其一,即多个只能出现一个:<!ELEMENT MYFILE (TITLE|AUTHOR|EMAIL)>

    在元素内容中也可以使用+,*,?等符号表示元素出现的次数

    +:一次或多次(书+)

    ?:0次或一次(书?)

    *:0次或多次(书*)

    也可以使用圆括号()批量设置

    <!ELEMENT MYFILE (TITLE*,AUTHOR?,EMALL)* | COMMENT>

  • 属性定义

    XML文档中的标签属性需通过ATTLIST为其设置属性

    语法格式:

    <!ATTLIST 元素名

          属性名1 属性值类型 设置说明

          属性名2 属性值类型 设置说明

          ........

    >

    属性声明举例:

    <! ATTLIST 商品

      类别 CDATA #REQUIRED (必须属性)

      颜色 CDATA #IMPLIED  (可选属性)

    >

    对于XML文件

    <商品 类别=“服装” 颜色=“黄色”></商品>

    <商品 类别=“面包”></商品>

    设置说明:

    #REQUIRED:必须设置改属性

    #IMPLIED:可以设置也可以不设置

    #FIXED:说明该属性的取值固定为一个值,在XML文件中不能为该属性设置其他值。但需要为

    该属性提供这个值

    直接使用默认值:在XML中可以设置该值也可以不设置该属性值。若没设置则使用默认值 

    常用属性值类型

    CDATA

    ENUMERATED

    ID(表示属性的设置值为一唯一值,ID属性的值只能由字母,下划线开始,不能出现空白符)

    ENTITY(实体:用于为一段内容创建一个别名,以后在XML文档中就可以使用别名引用这段内容)

      在DTD中定义实体要用<!ENTITY  >语句

      实体可分为两种类型:引用实体和参数实体

         引用实体:主要在XML文档中被应用

         语法格式:<!ENTITY 实体名称 “实体内容”>:直接转变成实体内容

         引用方法:&实体名称 

         举例:<!ENTITY copyright "l am a programmer">    &copyright  

         -------------------------------------------------------------------------------

         参数实体:被DTD文件自身使用

         语法格式:<!ENTITY % 实体名称 “实体内容”>

         引用方法:%实体名称

         举例说明:<!ENTITY % TAG_NAMES "姓名 | EMALL | 电话 | 地址">

              <!ELEMENT 个人信息 (%TAG_NAMES | 生日)>

              <!ELEMENT 客户信息 (%TAG_NAMES | 公司名)>  

5.XML编程(CRUD)

XML解析方式分为两种:dom和sax

  dom:(Document Object Model)是W3C组织推荐的解析XML的一种方式

     sax:(Simple API for XML)不是官方标准,但它是XML社区事实上的标准,几乎所有的XML解析器

  都支持它

dom和sax解析方法的区别

  1.dom解析的优点是对文档crud比较方便,缺点就是占用内存比较大(所有元素全部在内存中生成相应的对象)

  2.sax解析的优点是占用内存少,解析速度快,缺点是只适合做文档的读取,不适合做文档的crud(一层一层的解析)

XML解析开发包

  Jaxp(sun),Jdom,dom4j

Jaxp

  • 是J2SE的一部分,它由javax.xml,org.w3c.dom,org.xml.parsers包及其子包组成
  • 在javax.xml.parsers包中,定义了几个工厂类,程序员调用这些工厂类,可以得到xml文档的DOM

   或SAX的解析器,从而实现对xml文档的解析

使用Jaxp进行DOM解析:javax.xml.parsers包中的DocumentBuilderFactory用于创建DOM模式的解析器对象,DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回

例子:

        //1.创建工厂
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //2.得到dom解析器
        DocumentBuilder db = factory.newDocumentBuilder();
        //3.解析xml文档,得到代表文档的document
        Document d = db.parse("src/book.xml");

再用Junit写一些测试Demo

先贴要解析的xml源码

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE 书架 SYSTEM "book.dtd">
 3 <书架>
 4     <>
 5         <书名 name="Hello">java就业培训教程</书名>
 6         <作者>张孝祥</作者>
 7         <售价>39.00元</售价>
 8     </>
 9     <>
10         <书名 name="JavaWeb">javaScript网页开发</书名>
11         <作者>张孝详</作者>
12         <售价>28.00元</售价>
13     </>
14 </书架>

测试代码

 1     @Test
 2     public void test1() throws Exception{
 3         
 4         //创建工厂
 5         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 6         //得到dom解析器
 7         DocumentBuilder db = factory.newDocumentBuilder();
 8         //解析xml文档,得到代表文档的document
 9         Document d = db.parse("src/book.xml");
10         //获得标签名为书名的对象集合
11         NodeList nlist = d.getElementsByTagName("书名");
12         //拿到集合里面的节点对象
13         Node n1 = nlist.item(0);
14         Node n2 = nlist.item(1);
15         //得到节点的内容
16         String s1 = n1.getTextContent();
17         String s2 = n2.getTextContent();
18         System.out.println(s1);
19         System.out.println(s2);
20         
21     }

结果如下:

java就业培训教程
javaScript网页开发

测试代码二(获得所有标签的名字)

 1     @Test
 2     public void test2() throws Exception{
 3         
 4         // 创建工厂
 5         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 6         // 得到dom解析器
 7         DocumentBuilder db = factory.newDocumentBuilder();
 8         // 解析xml文档,得到代表文档的document
 9         Document d = db.parse("src/book.xml");
10         //得到根节点
11         NodeList nlist = d.getElementsByTagName("书架");
12         Node root = nlist.item(0);
13         
14         list(root);
15         
16     }    
17     
18     public void list(Node root){
19         if(root instanceof Element){
20         System.out.println(root.getNodeName());
21           
22         NodeList nlist = root.getChildNodes();
23         
24         for(int i=0; i<nlist.getLength(); i++){
25             
26             Node child = nlist.item(i);
27             list(child);
28         
29         }
30         }
31     }

Junit测试结果

1 书架
2 3 书名
4 作者
5 售价
6 7 书名
8 作者
9 售价

得到属性名的测试

 1     @Test
 2     public void test3() throws Exception{
 3         
 4         // 创建工厂
 5         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 6         // 得到dom解析器
 7         DocumentBuilder db = factory.newDocumentBuilder();
 8         // 解析xml文档,得到代表文档的document
 9         Document d = db.parse("src/book.xml");
10         
11         NodeList nlist = d.getElementsByTagName("书名");
12         
13         Node n = nlist.item(0);
14         
15         Element e = (Element) n;
16         String str = e.getAttribute("name");
17         System.out.println(str);
18     }

测试结果得到hello

上面的操作都只是查,没有对xml进行修改,如果需要对xml进行修改,我们需要把在内存中修改后的Document对象重新写入硬盘中原来的xml文件中,从而达到修改xml文件的效果。

那么我们就需要用到更新XML文档的包了

  •   javax.xml.transform包中的Teansformer类用于把代表XML文件的Document转换为某种格式后

     进行输出,可以把Document对象又重新写入一个XML文件中

  •   Transformer类通过transform方法完成转换操作,该方法接受一个源和一个目的地,我们可以

        通过javax.xml.transform.dom.DOMSource类来关联要转换的document对象,用

     javax.xml.transform.stream.StreamResult对象来表示数据的目的地

  •      Transformer对象通过TransformerFactory获得

 举例说明

  1     @Test
  2     public void test4() throws Exception{
  3         
  4         // 创建工厂
  5         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  6         // 得到dom解析器
  7         DocumentBuilder db = factory.newDocumentBuilder();
  8         // 解析xml文档,得到代表文档的document
  9         Document d = db.parse("src/book.xml");
 10         // 创建节点
 11         Element e = d.createElement("售价");
 12         e.setTextContent("100元");
 13         //把节点挂到第一本书
 14         Node node = d.getElementsByTagName("书").item(0);
 15         node.appendChild(e);
 16         //把更新后的内存写回xml文档
 17         //我们这里只是把内存中的代表xml对象的那个数据修改了,并没有把这个写进硬盘
 18         //所以原来在硬盘里面的xml文件并没有被修改,所以我们需要把修改后的对象写入
 19         //硬盘中,得到修改后的xml文件
 20         TransformerFactory tffactory = TransformerFactory.newInstance();
 21         Transformer tf = tffactory.newTransformer();
 22         tf.transform(new DOMSource(d), new StreamResult(new FileOutputStream("src/book.xml")));
 23         
 24         
 25     }
 26     
 27     @Test
 28     //向文档中指定位置插入数据
 29     public void test5() throws Exception{
 30 
 31         // 创建工厂
 32         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 33         // 得到dom解析器
 34         DocumentBuilder db = factory.newDocumentBuilder();
 35         // 解析xml文档,得到代表文档的document
 36         Document d = db.parse("src/book.xml");
 37         // 创建节点
 38         Element e = d.createElement("售价");
 39         e.setTextContent("100元");
 40         //得到参考节点
 41         Node node2 = d.getElementsByTagName("售价").item(0);
 42         //得到要插子节点的节点
 43         Node node = d.getElementsByTagName("书").item(0);
 44         //向指定位置插入节点
 45         node.insertBefore(e, node2);
 46         //把更新后的内存写回xml文档
 47         //我们这里只是把内存中的代表xml对象的那个数据修改了,并没有把这个写进硬盘
 48         //所以原来在硬盘里面的xml文件并没有被修改,所以我们需要把修改后的对象写入
 49         //硬盘中,得到修改后的xml文件
 50         TransformerFactory tffactory = TransformerFactory.newInstance();
 51         Transformer tf = tffactory.newTransformer();
 52         tf.transform(new DOMSource(d), new StreamResult(new FileOutputStream("src/book.xml")));
 53         
 54 
 55     }
 56     
 57     @Test
 58     //向指定节点添加属性
 59     public void test6() throws Exception{
 60         
 61         // 创建工厂
 62         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 63         // 得到dom解析器
 64         DocumentBuilder db = factory.newDocumentBuilder();
 65         // 解析xml文档,得到代表文档的document
 66         Document d = db.parse("src/book.xml");
 67         // 得到书名节点
 68         Element bookName = (Element) d.getElementsByTagName("书名").item(0);
 69         bookName.setAttribute("name", "修改后的名字");
 70         //更新内存
 71         TransformerFactory tffactory = TransformerFactory.newInstance();
 72         Transformer tf = tffactory.newTransformer();
 73         tf.transform(new DOMSource(d), new StreamResult(new FileOutputStream("src/book.xml")));
 74         
 75         
 76         
 77     }
 78     
 79     @Test
 80     //删除节点
 81     public void test7() throws Exception{
 82         
 83         // 创建工厂
 84         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 85         // 得到dom解析器
 86         DocumentBuilder db = factory.newDocumentBuilder();
 87         // 解析xml文档,得到代表文档的document
 88         Document d = db.parse("src/book.xml");
 89         //得到要删除的节点
 90         Element eSon = (Element) d.getElementsByTagName("售价").item(0);
 91         //得到要删除节点的父节点
 92         Element eFather = (Element) d.getElementsByTagName("书").item(0);
 93         //调用父节点的方法删除子节点
 94         eFather.removeChild(eSon);
 95         //更新内存
 96         TransformerFactory tffactory = TransformerFactory.newInstance();
 97         Transformer tf = tffactory.newTransformer();
 98         tf.transform(new DOMSource(d), new StreamResult(new FileOutputStream("src/book.xml")));
 99         
100     }
101     
102     @Test
103     //删除节点(方法二)
104     public void test8() throws Exception{
105         
106         // 创建工厂
107         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
108         // 得到dom解析器
109         DocumentBuilder db = factory.newDocumentBuilder();
110         // 解析xml文档,得到代表文档的document
111         Document d = db.parse("src/book.xml");
112         //得到要删除的节点
113         Element eSon = (Element) d.getElementsByTagName("售价").item(0);
114         eSon.getParentNode().removeChild(eSon);
115         
116         //更新内存
117         TransformerFactory tffactory = TransformerFactory.newInstance();
118         Transformer tf = tffactory.newTransformer();
119         tf.transform(new DOMSource(d), new StreamResult(new FileOutputStream("src/book.xml")));
120         
121     }
122     
123     @Test
124     //更新价格
125     public void test9() throws Exception{
126         
127         // 创建工厂
128         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
129         // 得到dom解析器
130         DocumentBuilder db = factory.newDocumentBuilder();
131         // 解析xml文档,得到代表文档的document
132         Document d = db.parse("src/book.xml");
133         //得到要修改的售价节点
134         Element e = (Element) d.getElementsByTagName("售价").item(0);
135         e.setTextContent("10000元");
136         
137         //更新内存
138         TransformerFactory tffactory = TransformerFactory.newInstance();
139         Transformer tf = tffactory.newTransformer();
140         tf.transform(new DOMSource(d), new StreamResult(new FileOutputStream("src/book.xml")));
141         
142     }

 sax解析:允许我们在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才能对文档进行操作(一层一层的解析)

  • sax解析采用的是事件处理的方式解析XML文件,利用SAX解析XML文档,涉及两个部分,解析器和处理器
  • 解析器:可以使用JAXP的API创建,创建出SAX解析器后,就可以以指定解析器去解析某个XML文档
  • 解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器
  • 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理

代码实例

package day0503;


import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;



public class Demo1{
    
    public static void main(String[] args) throws Exception{
        
        //1.创建解析工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //2.得到解析器
        SAXParser sp = factory.newSAXParser();
        //3.得到读取器
        XMLReader reader = sp.getXMLReader();
        //4.设置内容处理器
        reader.setContentHandler(new ListHandler());
        //5.读取xml文档内容
        reader.parse("src/book.xml");
    }
    
}

//内容处理器
class ListHandler implements ContentHandler{

    @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 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 attName = atts.getQName(i);
            String attValue = atts.getValue(i);
            System.out.println(attName + "=" + attValue);
            
        }
    }

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

    }

    @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 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
        
    }

}

使用SAX解析封装对象

 1 package day0503;
 2 
 3 import java.io.IOException;
 4 import java.util.ArrayList;
 5 import java.util.List;
 6 
 7 import javax.xml.parsers.ParserConfigurationException;
 8 import javax.xml.parsers.SAXParser;
 9 import javax.xml.parsers.SAXParserFactory;
10 
11 import org.xml.sax.Attributes;
12 import org.xml.sax.SAXException;
13 import org.xml.sax.XMLReader;
14 import org.xml.sax.helpers.DefaultHandler;
15 
16 public class Demo3 {
17 
18     public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
19         // TODO Auto-generated method stub
20 
21         //1.创建解析工厂
22         SAXParserFactory factory = SAXParserFactory.newInstance();
23         //2.得到解析器
24         SAXParser sp = factory.newSAXParser();
25         //3.得到读取器
26         XMLReader reader = sp.getXMLReader();
27         //4.设置内容处理器
28         BeanListHandler handle = new BeanListHandler();
29         reader.setContentHandler(handle);
30         //5.读取xml文档内容
31         reader.parse("src/book.xml");
32         
33         List<Book> list = handle.getList();
34         System.out.println(list);
35     }
36 
37 }
38 
39 //把xml文档中的每一本书封装到一个book对象,并把多个book对象放在一个list集合中返回
40 class BeanListHandler extends DefaultHandler{
41 
42     private List list = new ArrayList();
43     private String currentTag;
44     private Book book;
45     
46     @Override
47     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
48 
49         currentTag = qName;
50         if("书".equals(qName)){
51             book = new Book();
52             
53         }
54         
55     }
56     
57     @Override
58     public void characters(char[] ch, int start, int length) throws SAXException {
59         
60         if("书名".equals(currentTag)){
61             String name = new String(ch,start,length);
62             book.setName(name);
63         }
64         if("作者".equals(currentTag)){
65             String author = new String(ch,start,length);
66             book.setAuthor(author);
67         }
68         if("价格".equals(currentTag)){
69             String price = new String(ch,start,length);
70             book.setPrice(price);
71         }
72         
73     }
74 
75     @Override
76     public void endElement(String uri, String localName, String qName) throws SAXException {
77         
78         currentTag = null;
79         if("书".equals(qName)){
80             list.add(book);
81             book = null;
82         }
83         
84     }
85     
86     public List<Book> getList() {
87         return list;
88     }
89 
90 }

Dom4j解析XML

使用Dom4j开发,需要下载dom4j相应的jar文件

使用说明:https://dom4j.github.io/

实例代码(有乱码问题)

 1 package day0506;
 2 
 3 import java.io.File;
 4 import java.io.FileWriter;
 5 import java.io.IOException;
 6 
 7 import org.dom4j.Document;
 8 import org.dom4j.DocumentException;
 9 import org.dom4j.Element;
10 import org.dom4j.io.SAXReader;
11 import org.dom4j.io.XMLWriter;
12 import org.junit.Test;
13 
14 public class Demo1111 {
15     
16     @Test
17     public void test1() throws DocumentException{
18         
19         SAXReader reader = new SAXReader();
20         Document document = reader.read(new File("src/book.xml"));
21         Element root = document.getRootElement();
22         Element book = root.elements("书").get(1);
23         String value = book.element("书名").getText();
24         System.out.println(value);
25         
26     }
27     
28     @Test
29     public void test2() throws DocumentException, IOException{
30         
31         SAXReader reader = new SAXReader();
32         Document document = reader.read(new File("src/book.xml"));
33         Element book = document.getRootElement().element("书");
34         book.addElement("售价").setText("209元");
35         //更新内存
36          XMLWriter writer = new XMLWriter(new FileWriter("src/book.xml"));
37          writer.write( document );
38          writer.close();
39          //乱码
40     }
41     
42 }

为什么会出现乱码呢?那是因为java的io流默认的字符编码和xml的字符编码不一致,那我们就需要使用

可以指定字符编码io流了

我们查一下api就可以知道可以使用:OutputStreamWriter(OutputStream out, CharsetEncoder enc)

创建一个使用给定字符集编码器的OutputStreamWriter。这样问题就被解决了

 解决乱码的方案就是设置一个编码转换器

1 OutputFormat format = OutputFormat.createPrettyPrint();
2 format.setEncoding("UTF-8");
3 XMLWriter writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream("src/book.xml"), "UTF-8"), format);
4 writer.write(document);
5 writer.close();

使用XPath提取xml文档数据

XPath使用很方便,要使用的时候查官方文档就行,而且官方文档有中文版的

下面给出实例代码:

public class Demo2 {
    
    @Test
    public void test1() throws DocumentException{
        
        SAXReader reader = new SAXReader();
        Document document = reader.read(new File("src/book.xml"));
        
        String s = document.selectSingleNode("//作者").getText();
        System.out.println(s);
    }
    
}
View Code

使用XPath可以非常方便的提取到想要的节点。

XML Schema

XML Schema也是一种用于定义和描述XML文档结构与内容的模式语言,其出现是为了克服DTD的局限性

XML Schema VS DTD:

  • XML Schema符合XML语法结构。
  • DOM,SAX等XML API很容易解析出XML Schema文档中的内容。                 
  • XML Schema对名称空间支持得非常好
  • XML Schema比XML DTD支持更多得数据类型,并支持用户自定义新的数据类型。
  • XML Schema定义约束能力非常强大,可以对XML实例文档作出细致得语义限制
  • XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织得标准,它正逐步取代DTD

 XML Schema约束快速入门

  •  XMLSchema文件自身就是一个XML文件,但它得扩展名通常为xsd。
  • 一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档
  • 和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根节点的名称为Schema
  • 编写一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,在XML Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后XML文件就可以通过这个URI(即名称空间)来告诉解析引擎,XML文档中编写的元素来自哪里,被谁约束。

 使用教程:http://www.w3school.com.cn/schema/index.asp

原文地址:https://www.cnblogs.com/Vamps0911/p/10778405.html