XML详细讲解(在java需掌握的程度)<二>:XML解析之dom4j解析

再讲XML解析前,先问读者一个小问题:在使用setter和getter方法时,设置与获取到的属性值与我们直接在构造对象时的值是否一样?这个问题很重要,因为这儿很容出现bug。

public class Student{
     private String name;
     public Student(String name){
          name = this.name;
     }
     public void setName(String name){
          this.name = name;
     }
     public String getName(){
           return name;
     }
}      

五,XML解析

        XML解析有两种原理:SAX解析和DOM解析。①SAX解析:社区开发一套基于事件驱动的解析方式,逐行解析,性能好,但是不能重复使用数据,如果要修改,或者回头查数据,必须重新从头读取数据;②DOM解析:官方定义的一套规则,把整个xml文件读取到内存,重复使用,消耗较多的内存,可以重复使用和修改数据(原理:读到内存后形成一个Document文档,对象形成一个DOM树,对xml文件的操作实际上是对Document对象进行操作,最后再做数据同步操作),缺点是只能解析小型xml文件,文件过大会导致内存溢出。

        XML解析的方式:①jdom解析(已被淘汰);②dom4j:通过SAX读取xml,形成一个·DOM存储在内存中;③jaxb:Java API for XML Bind,负责XML文档对象的自动绑定,底层使用jaxp解析XML,是基于注解开发的;④jaxp:Java API for XML Parser,Java5.0以后提供一套SPI,负责解析XML。

<一>dom4j解析

         使用dom4j解析需要先在项目中导入dom4j的jar包(小编使用的是Eclipse),同时添加依赖(Build Path),同时这儿用junit4来做的测试。下面代码演示解析DTD和Schema两种xml文件。

         小编的项目目录参考:(emm,那个example.xml文档是之前用来练习用的,这儿没用到)

    

 

         代码逻辑:

1,定义一个测试类demoTest,这个类负责测试;

 2,定义一个与数据链接的类DAO_demo,这个类负责数据处理;

3,定义两个数据产生类,分别为Book类和Student类;

4,在·src目录下建一个sources目录(为了将资源与源代码分开,实际上在电脑目录下查看,资源和java源代码任然是在一个根目录下),用来放bookstore.xml,bookstore.dtd,student.xml,student.xsd文件,

         @这儿是xml文件的代码

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT bookstore (book+)>
<!ELEMENT book (name,author,price)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!--注意只有一种数据类型:字符串-->
<!ELEMENT price (#PCDATA)>
<!--注意id必须以字母开头  -->
<!ATTLIST book id ID #REQUIRED>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE bookstore SYSTEM "bookstore.dtd">
<!-- 如果价格写成double型,那么就要注意数据的转换了,否则要报错!!!  -->
<bookstore>
    <book id="a1">
        <name>水浒传</name>
        <author>施耐庵</author>
        <price>60</price>
    </book>
    <book id="a2">
        <name>红楼梦</name>
        <author>曹雪芹</author>
        <price>75</price>
    </book>
    <book id="a3">
        <name>悲惨世界</name>
        <author>雨果</author>
        <price>30</price>
    </book>
</bookstore>

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.yby.org/students" 
xmlns:tns="http://www.yby.org/students" 
elementFormDefault="qualified">
<element name="students">
   <complexType>
       <sequence>
           <element name="student" minOccurs="1" maxOccurs="unbounded">
             <complexType>
               <sequence>         
               <element name="name" type="string" minOccurs="1" maxOccurs="1"/>
               
               <element name="sex">
                   <simpleType>
                       <annotation>
                           <documentation>只能为男或者女</documentation>
                       </annotation>
                       <restriction base="string">
                           <enumeration value="男"/>
                           <enumeration value="女"/>                       
                       </restriction>
                   </simpleType>
               </element>
               
               <element name="age" minOccurs="1" maxOccurs="1">
                   <simpleType>
                       <annotation>
                           <documentation>年龄必须在15~50岁</documentation>
                       </annotation>
                       <restriction base="int">
                           <minInclusive value="15"/>
                           <maxInclusive value="50"/>
                       </restriction>
                   </simpleType>
               </element>
                             
               <element name="subjects" minOccurs="1" maxOccurs="1">
                   <complexType>
                       <sequence>
                       <element name="subject" minOccurs="1" maxOccurs="3" type="string">
                           <annotation>
                              <documentation>主修科目最少为一门,最多为三门</documentation>
                           </annotation>                         
                       </element>
                       </sequence>
                   </complexType>
               </element> 
                
             </sequence>
             <!--注意属性约束的位置 -->
           <attribute name="id" type="int" use="required"/>           
           </complexType>
          </element>                                  
       </sequence>
   </complexType>   
</element>
</schema>
<?xml version="1.0" encoding="UTF-8"?>
<students xmlns="http://www.yby.org/students" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.yby.org/students student.xsd ">  
  <student id="1"> 
    <name>张三</name>  
    <sex>男</sex>  
    <age>17</age>  
    <subjects> 
      <subject>物理</subject>  
      <subject>数学</subject> 
    </subjects> 
  </student>  
  <student id="2"> 
    <name>李四</name>  
    <sex>男</sex>  
    <age>19</age>  
    <subjects> 
      <subject>英语</subject> 
    </subjects> 
  </student>  
  <student id="3"> 
    <name>王二</name>  
    <sex>男</sex>  
    <age>27</age>  
    <subjects> 
      <subject>化学</subject> 
    </subjects> 
  </student>  
  <student id="4"> 
    <name>渣渣辉</name>  
    <sex>男</sex>  
    <age>36</age>  
    <subjects> 
      <subject>物理</subject> 
    </subjects> 
  </student>  
  <student id="5"> 
    <name>达摩</name>  
    <sex>男</sex>  
    <age>34</age>  
    <subjects> 
      <subject>线性代数</subject> 
    </subjects> 
  </student>  
  <student id="6">
    <name>沸羊羊</name>
    <sex>男</sex>
    <age>34</age>
    <subjects>
      <subject>离散数学</subject>
      <subject>恋爱心理学</subject>
    </subjects>
  </student>
</students>

       @这儿是数据产生类

public class Book {
     private String name;
     private String author;
     private int price;  //注意数据类型转换
     private String id; //由于DTD约束中id只能为字符串
     
    public Book() {
    	
    }
    @Override
	public String toString() {
		return "Book [name=" + name + ", author=" + author + ", price=" + price + ", id=" + id + "]";
	}
	public Book(String name,String author,int price,String id) {
    	name = this.name;
    	author = this.author;
    	price = this.price;
    	id = this.id;
    	
    }
     
	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 int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}    
}
public class Student {
	private String id;
	private String name;
	private String sex;
	private String age;
	private String subject1;
	private String subject2;
	private String subject3;
	
	public Student() {
		
	}
	public Student(String id,String name,String sex,String age,String subject1) {
		id = this.id;
	    name = this.name;
	    sex = this.sex;
	    age = this.age;
	    subject1 = this.subject1;
	}
	public Student(String id,String name,String sex,String age,String subject1,String subject2) {
		id = this.id;
	    name = this.name;
	    sex = this.sex;
	    age = this.age;
	    subject1 = this.subject1;
	    subject2 = this.subject2;	    
	}
	public Student(String id,String name,String sex,String age,String subject1,String subject2,String subject3) {
		id = this.id;
	    name = this.name;
	    sex = this.sex;
	    age = this.age;
	    subject1 = this.subject1;
	    subject2 = this.subject2;	
	    subject3 = this.subject3;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	public String getSubject1() {
		return subject1;
	}
	public void setSubject1(String subject1) {
		this.subject1 = subject1;
	}
	public String getSubject2() {
		return subject2;
	}
	public void setSubject2(String subject2) {
		this.subject2 = subject2;
	}
	public String getSubject3() {
		return subject3;
	}
	public void setSubject3(String subject3) {
		this.subject3 = subject3;
	}      
}

    @这儿是数据处理类:代码里详细讲解了开头的那个问题以及bug的解决思路,在阅读代码之前希望读者可以先看看导入包的各个类和方法,对理解代码的逻辑有很大帮助!!

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

//import org.junit.Test;

public class DAO_demo {
	 //dom4j解析
	//注意抛异常
	public Document getDocument(String document) throws DocumentException {
		//第一步:获取xml文件输入流(硬盘————>内存)
		InputStream input = this.getClass().getClassLoader().getResourceAsStream(document);
		//第二步:获取SAX解析对象
		SAXReader reader = new SAXReader();
		//第三步:获取Document对象(不能直接获取到Document对象————单例设计模式)
		Document doc = reader.read(input);
		
		return doc;
	}
	
	
	//查询信息————bookstore.xml(DTD约束) && student.xml(schema约束) 的查询方法一样
	public List<Book> QueryBook() throws DocumentException {
	   
		Element root = this.getDocument("bookstore.xml").getRootElement(); //获取根元素
	    List<Element> listElement = root.elements("book"); //elements()方法返回的是一个集合
	    List<Book> listBook = new ArrayList<>();
	    
	    for(Element bookEL : listElement) {
	    		    	
	    	String name = bookEL.elementText("name");
	    	String author = bookEL.elementText("author");
	    	int price =Integer.parseInt(bookEL.elementText("price"));
	    	
	    	//id是属性,获取方式不同于获取元素
	    	Attribute arr = bookEL.attribute("id");//获取属性对象
	    	String id = arr.getValue(); //获取属性值
	    	
	    	/* //当用下面的代码替换59~64的代码时,listBoook将是一个null对象
	    	 * // name author price id 都获得了值但为什么listBook是一个null??
	    	 *    System.out.println(name);
	    	 *    Book book = new Book(name,author,price,id);
	    	 *    listBook.add(book);	 
	    	 * 原因是:没有设置属性值,因此获取不到book对象的值,所以如果采用上面的方式实例book对象
	    	 * 就必须用get()方法去获取相应的属性值
	    	 *    
	    	 **/
	    	Book book = new Book();
	    	book.setName(name);
	    	book.setAuthor(author);
	    	book.setPrice(price);
	    	book.setId(id);
	    	listBook.add(book);	 	    	
	    }	
	    
	    return listBook;
	}
	
	//添加信息—————student.xml(schema约束),向bookstore.xml(DTD约束)也是差不多一样的
	public void SaveStudent(Student stu) throws DocumentException,IOException{
		
		//Student stu = new Student("4","渣渣辉","男","26","物理");
		//为什么stu不为null (输出为 : Student@7de26db8 ) ,但是却获取不到属性值???		
	    //System.out.println(stu.getId());
		
		Document doc = this.getDocument("student.xml");
		Element root = doc.getRootElement();
		
		// 这儿有个小问题:addAttribute(String QName,String args)
		// 这个方法的参数全是字符串(所以把id,sex在Student类中都用String类型,String转int是比较方便地)
		//根据上面的bug分析知道,要获取属性值,必须先设置属性值,否则就是一个null对象
		
		Element element = root.addElement("student").addAttribute("id", stu.getId());
		element.addElement("name").setText(stu.getName());
		element.addElement("sex").setText(stu.getSex());
		element.addElement("age").setText(stu.getAge());;
		element.addElement("subjects").addElement("subject").setText(stu.getSubject1());
		
		if(stu.getSubject2() != null) {
			
			/*    如果这儿这样写  : element.addElement("subjects").addElement("subject").setText(stu.getSubject2());
			 * 会导致在xml文件中写出的格式是是下面那样
			 *            <subjects>
             *                <subject>离散数学</subject>
             *            </subjects>
             *            <subjects>
             *                <subject>恋爱心理学</subject>
             *            </subjects>
             *    解决办法:先获取subjects节点————element.element("subjects"),然后在该节点下添加subject元素           
			 */
			element.element("subjects").addElement("subject").setText(stu.getSubject2());
			
		}
		if(stu.getSubject3() != null) {
			element.element("subjects").addElement("subject").setText(stu.getSubject3());
		}
		
		//同步数据
		/*
		 * 这儿有两种方式去同步数据
		 * 第一种:无格式同步
		 *    OutputStream out = new FileOutputStream("sources/student.xml");
		 *    XMLWriter writer = new XMLWriter(out);
		 *    writer.write(doc);
		 *    writer.close();
		 * 第二种:格式化同步,这种方式同步的数据很美观(这儿用的是此种方式)
		 */
		OutputStream out = new FileOutputStream("sources/student.xml");
		OutputFormat format = OutputFormat.createPrettyPrint();
		XMLWriter writer = new XMLWriter(out,format);
		writer.write(doc);
		writer.close(); //使用完流后后一定要关闭流,否则非正常关闭流会导致数据丢失!!!!
		
	}
	
	/*    在上面添加信息中,会发现一个问题,如果我们添加的信息不符合约束,但也能被添加到文件中
	 * 因此在添加信息之前我们应该先对所添加的信息进行验证,检查所添加信息是否符合约束,验证两个问题
	 *         一,验证xml文件是否使用了约束,如果没有则报错
	 *         二,验证xml文件的元素是否符合约束,不符合则报错
	 *    有两种验证方法,下面分别演示(DTD约束与Schema约束的验证差不多,这儿演示后者)
	 *         validation_1()  手动加载xml约束
	 *         validation_2()  使用URL来读取xml文件,会自动去加载对应的约束
	 */
	public void validation_1(String xml,String xsd) throws SAXException, DocumentException {
		InputStream in = this.getClass().getClassLoader().getResourceAsStream(xml);
		SAXReader reader = new SAXReader();
		reader.setEntityResolver(new EntityResolver() {
			@Override
			public InputSource resolveEntity(String arg0, String arg1) throws SAXException, IOException {
				InputStream xsdStream = this.getClass().getClassLoader().getResourceAsStream(xsd);
				InputSource source = new InputSource(xsdStream);				
				return source;
			}			
		});
		reader.setValidation(true); //开启验证
		
		//schema约束必须加上下面的这行代码,而且固定的,如果是dtd约束则不用加下面的这行代码
		reader.setFeature("http://apache.org/xml/features/validation/schema", true); 
		
		Document doc = reader.read(in);		
	}
	
	public void validation_2(String xml) throws SAXException, DocumentException {
		URL xmlURL = this.getClass().getClassLoader().getResource(xml);
		SAXReader reader = new SAXReader();
		reader.setValidation(true);
		
		//schema约束必须加上下面的这行代码,而且固定的,如果是dtd约束则不用加下面的这行代码
	    reader.setFeature("http://apache.org/xml/features/validation/schema", true); 
	    
	    Document doc = reader.read(xmlURL);
	    
	}

}

       

         @这儿是测试类:有关java测试类的使用下期再讲

import static org.junit.Assert.*;

import java.io.IOException;
import java.util.List;

import org.dom4j.DocumentException;
import org.junit.Test;
import org.xml.sax.SAXException;

public class demoTest {
    
    DAO_demo demoTest;
    
    //查询bookstore.xml的信息
	@Test
	public void testQueryBook() throws DocumentException {
		demoTest = new DAO_demo();
		List<Book> list = demoTest.QueryBook();
		
		for(Book book:list) {
			System.out.println(book.toString());
		}
	}
	
	//向student.xml中添加信息
	@Test
	public void testSaveStudent() throws DocumentException, IOException{
		
		/*如果采用以下方式就会为null,同时会报错———— “不能向XML文件写null”
		 *   Student stu = new Student("4","渣渣辉","男","36","物理");
		 *   demoTest = new DAO_demo();
		 *   demoTest.SaveStudent(stu);
		 *   原因:没有设置属性值,虽然new的student对象中有值,但是那些值便不是属性值,他们是有缺别的 
		 */
		
		Student stu = new Student();
		//必须设置属性的值,否则为null
		stu.setId("4");
		stu.setName("渣渣辉");
		stu.setSex("男");
		stu.setAge("36");
		stu.setSubject1("物理");
		demoTest = new DAO_demo();
		demoTest.SaveStudent(stu);
	}
	
	//使用xml验证对添加信息进行验证
	@Test
	public void testValidation() throws DocumentException, IOException, SAXException {
		Student stu = new Student();
		//必须设置属性的值,否则为null
		stu.setId("6");
		stu.setName("沸羊羊");
		stu.setSex("男");
		stu.setAge("34");
		stu.setSubject1("离散数学");
		stu.setSubject2("恋爱心理学");
		demoTest = new DAO_demo();
		demoTest.SaveStudent(stu);
		//demoTest.validation_1("student.xml", "student.xsd");
		demoTest.validation_2("student.xml");
	}

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Avalon712

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值