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

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

再讲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文件的代码













    
        水浒传
        施耐庵
        60
    
    
        红楼梦
        曹雪芹
        75
    
    
        悲惨世界
        雨果
        30
    




   
       
           
             
                        
               
               
               
                   
                       
                           只能为男或者女
                       
                       
                           
                                                  
                       
                   
               
               
               
                   
                       
                           年龄必须在15~50岁
                       
                       
                           
                           
                       
                   
               
                             
               
                   
                       
                       
                           
                              主修科目最少为一门,最多为三门
                                                    
                       
                       
                   
                
                
             
             
                      
           
                                            
       
      


  
   
    张三  
      
    17  
     
      物理  
      数学 
     
    
   
    李四  
      
    19  
     
      英语 
     
    
   
    王二  
      
    27  
     
      化学 
     
    
   
    渣渣辉  
      
    36  
     
      物理 
     
    
   
    达摩  
      
    34  
     
      线性代数 
     
    
  
    沸羊羊
    
    34
    
      离散数学
      恋爱心理学
    
  

       @这儿是数据产生类

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 QueryBook() throws DocumentException {
	   
		Element root = this.getDocument("bookstore.xml").getRootElement(); //获取根元素
	    List listElement = root.elements("book"); //elements()方法返回的是一个集合
	    List 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节点————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 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");
	}

}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/730764.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)

保存