miracle just wanna be better

xml相关

2019-07-30
miracle
xml

XML:扩展标记语言(Extensible Markup Languae)

是独立于软件和硬件的信息传输工具

  • xml可以简化数据共享
  • xml可以数据传输
  • xml可以平台变更

xml的处理指令

version:xml的版本
encoding:xml的内容编码
xml文档里包含的是xml的元素
xml元素:指的是从开始标签直到结束标签的部分,元素里可以包含其他元素,元素也可以拥有其他属性.
比如:

    <students>
		<student id="1">
			<name>张三</name>
			<age>20</age>
			<stuNo>S001</stuNo>
		</student>
		<student id="2">
			<name>李四</name>
			<age>30</age>
			<stuNo>S002</stuNo>
		</student>
	</students>
  • students,student,name,age,stuNo这些都叫元素标签,也可以叫元素节点,元素对象,
  • id是某个元素的节点的属性,也可以叫属性节点,也叫属性对象
  • 张三,20,S001等这样的数据叫做值,也可以叫做文本节点和文本对象

  • 元素节点:一般用来表达某种语义
  • 属性节点:一般用来修饰和补充元素节点
  • 文本节点:一般用来表达指定语义的值

xml需要注意的几个问题:

  1. xml元素节点,必须成对出现,且开始标签和结束标签名必须一样
  2. xml属性节点的值需要用引号括起来,可以是双引号也可以,是单引号,如果属性值本身包含双引,则需要用单引包围他
    比如:
   <student name='二"狗"子'></student>
  1. xml对大小写敏感,区分大小写
  2. xml中要求,必须有跟元素节点,并且跟节点只有一个根节点包含所有其他子节点(元素,文本,属性)
  3. 所有元素节点必须正确嵌套
  4. 实体引用:xml中有若干符号,是跟xml有冲突的,所以需要用别名代替

比如: | 实体引用 | 字符 | 说明 | | :—— |:— | :— | | < | < | 小于 | | > | > | 大于 | | & | & | 与 | | &aops; | ‘ | 单引号 | | " | “ | 双引号 |

  <name>1&lt;2</name>
  <desc>这个是一个&quot;描述&quot;文本</desc>
  1. CDATA段,段中的内容当成一个文本块来看待
    语法:
    <![CDATA[文本内容]]>
    比如:
   <desc>
	<![CDATA[
		<说明>
			CDATA段中的所有内容太都当成一个文本块来看待
			如果有类似的元素节点也不会当成xml看待
			只是普通的文本
		
		</说明>
	
	]]>
   </desc>

xml解析:

  1. SAX解析方式:(simple api for xml)是一种xml解析的替代方法,想对比DOM机械,sax解析是一种速度快,更有效的方法,因为他是逐行扫描xml文档,一边扫描,一边解析,而且相对于dom解析,sax可以在解析文档的任意时刻停止解析
    • 优点:解析可以立即开始,速度快,没有内存压力
    • 缺点:不能对节点做修改
  2. DOM解析方式:(document Object Model文档对象模型)是w3c组织推荐的处理xml的一种方式,dom解析器在解析xml文档时,会把文档中的所有元素按照其出现的层次关系,解析成一个Node对象(节点对象)
    • 优点:把xml文件在内存中构建树形结构,可以遍历和修改节点
    • 缺点:如果文件比较大,内存有压力,解析时间会比较长
  3. sax解析必须借助第三方工具dom4j,工具中提供若干jar包,jar包中提供了若干api,来解析xml,dom4j是一个非常优秀的解析xml框架,也是一个开源的框架
  4. Dom解析不需要额外第三方jar包,jdk(jre)提供了若干api操作xml

SAX api:

  • Element getRootElement(); Document类
    获取根节点,以备获取跟节点后面的节点对象
  • List elements(); Element类
    获取当前节点下的所有元素节点,返回结果是List集合
  • Attribute attribute(String attributeName); Element类
    获取当前节点的某一个属性名对应的属性对象,返回值是Attribute类的对象
  • String getValue; Attribute类
    获取当前属性对象中的属性值
  • Element element(String elementName); Element类
    获取当前元素节点下的 指定元素节点名称的 元素对象
  • String getText(); Element类
    获取当前元素节点里的文本节点的值
  • String elementText(String elementName); Element类
    获取当前元素节点下的指定元素节点名称的节点里的文本节点的值

写xml节点到xml文件:

  1. 创建文档对象
Document doc =DocumentHelper.CreateDocument();
获取文档对象
Document doc=new SAXReader().read("xxx.xml");
  1. 定位节点 并添加
  2. 把document对象写到xml中
  • 方式一:
XMLWriter writer=new XMLWriter();
OutPutStream os=new FileOutputStream("src/resources/new.xml");
writer.setOutputStream(os);
//把内存中的数据写入到new.xml文件中
writer.write(document);
writer.close();
  • 方式二:
OutputFormat outformat=OutputFormat.createPrettyPrint();
outformat.setEncoding("UTF-8");
OutputStream os=new FileOutputStream("bin/resource/employee.xml");
XMLWriter writer=new XMLWriter(os,outformat);
//把内存中的数据写入employee.xml中
writer.write(document);
write.close();

sax方式写入xml常用api:

  • Element addElement(String elementNodeName); Element类
    在当前元素节点里,添加一个新元素节点,节点的名字elementNodeName
  • Element addAttribute(String propertyName,String propertyValue);
    Element类在当前的节点上添加属性,属性的名称propertyName属性的值 propertyValue
  • Element addText(String text); Element类
    给当前节点添加文本节点

XPath:路径表达式

xpath是一门在xml文档中查找信息的语言,xpath可用来在xml文档中对元素或属性进行遍历

有了xpath就解决了逐层遍历

xpath是用网络路径表达式在xml文档中进行导航(快速查找)
xpath包含一个标准函数库
xpath是xslt中的主要元素
xpath是w3c标准

路径表达式:

  • 斜杠(/)作为路径的分隔符
  • 导航到同样一个节点,有相对路径和绝对路径两种绝对路径:
    必须从”/”起始,后面紧跟节点
    比如:/list/employee
    相对路径:以当前路径作为起始点
    比如: employee/name
  • ”.”表示当前节点
  • ”..”表示当前节点的父节点
  • nodename(节点名称):表示该节点的所有子节点
  • ”/” 表示跟节点
  • ”//” 表示选择任意位置的某个节点
  • ”@” 表示选择某个属性

以下面xml的文档为例:

<?xml version="1.0" encoding="utf-8" ?>
<bookstore>
	<book>
		<title lang="eng">harry potter</title>
		<price>39.9</price>
	</book>
	<book>
		<title lang="eng">learning XML</title>
		<price>59.9</price>
	</book>
</bookstore>

/bookstore 选取跟节点bookstore,这是绝对路径
bookstore/book 选取所有属于bookstore的子元素book元素相对路径
//book 选取所有book子元素,而不管他们在文档中的位置
bookstore//book 选取所有属于bookstore元素的后代的book的元素,而不管他们位于bookstore之下什么位置
//@lang 选取所有名为lang的属性

谓语:
谓语条件,就是对路径表达式的附加条件
所有的条件,都写在[]中,表示对节点的进一步筛选
/bookstore/book[1] 表示选择bookstore的第一个book子元素
/bookstore/book[last()] 表示bookstore的最后一个book子元素
/bookstore/book[last()-1] 表示bookstore的倒数第二个book子元素
/bookstore/book[position()<3] 表示选择bookstore的前两个book子元素
//title[@lang] 表示选择所有具有lang属性的title节点
//title[@lang=’eng’] 表示所有具有lang属相,且值等于eng的title节点
//bookstore/book[price] 表示选择bookstore的book子元素且被选中的book子元素必须带有price子元素
/booksstore/book[price>35.0] 表示选择bookstore的book子元素,且选中的book子元素的price的子元素值必须大于35.0
/bookstore/book[price>35.0]/title表示在上面的例子结果中选择title子元素
/bookstore/book/price[.>35.0]表示选择值大于35.0的/bookstore/book的price子元素

通配符:

  • *表示匹配任何子元素
  • @ 表示匹配任何属性
  • node() 表示匹配任何类型节点
  • //* 选择文档中的所有元素节点
  • // 表示选择所有第二层的元素节点
  • /bookstore/* 表示选择bookstore的所有子元素节点
  • //title[@*] 表示选择所有带有属性的title元素

要想使用xpath必须引入第三方的jar包
jaxen-xx-xx.jar

使用xpath的api

List SelectNodes(String xpath);
根据xpath的参数获取xpath指定节点的信息

例子

xpath用法

Employee.java

public class Employee {
	private int id;
	private String name;
	private int age;
	private String gender;
	private double salary;
	
	public Employee(){}
	public Employee(int id, String name, int age, String gender, double salary) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.gender = gender;
		this.salary = salary;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + ", salary=" + salary
				+ "]";
	}
	
	
}

Employee.xml

<?xml version="1.0" encoding="UTF-8"?>
<list>
	<employee id="1">
		<name>张三</name>
		<age>20</age>
		<gender></gender>
		<salary>5000</salary>
	</employee>
	<employee id="2">
		<name>李四</name>
		<age>21</age>
		<gender></gender>
		<salary>5200</salary>
	</employee>
	<employee id="3">
		<name>王五</name>
		<age>20</age>
		<gender></gender>
		<salary>50000</salary>
	</employee>
	<employee id="4">
		<name>赵六</name>
		<age>20</age>
		<gender></gender>
		<salary>10000</salary>
	</employee>
	<employee id="5">
		<name>田七</name>
		<age>20</age>
		<gender></gender>
		<salary>20000</salary>
	</employee>
</list>

Demo2.java

/**
 * 此类现实xpath用法
 * @author PC
 *
 */
public class Demo2 {
	@Test
	public void  test1()throws Exception{
		SAXReader reader=new SAXReader();
		//通过Demo的Class所在位置来定位到employee.xml
		InputStream is=Demo2.class.getClassLoader().getResourceAsStream("resources/employee.xml");
		Document doc=reader.read(is);
		//xpath用法
		List<Element> emps=doc.selectNodes("/list/employee[@id='3']");
		for(Element emp:emps){
			System.out.println("name="+emp.elementText("name"));
		}
		
	}
}
public class Demo1 {
	/**
	 * 获取文件的路径为相对路径
	 * 且当前路径是项目的根目录
	 * @param fileName
	 * @return
	 * @throws Exception 
	 */
	private Document readXML1(String fileName) throws Exception{
		Document doc=null;
		//创建一个SAXReader解析器
		SAXReader xmlReader=new SAXReader();
		doc=xmlReader.read(fileName);

		return doc;
	}
	/**
	 * 文件是从类路径中获取的
	 * @param fileName
	 * @return
	 * @throws Exception 
	 */
	private Document readXML2(String fileName) throws Exception{
		Document doc=null;
		//创建一个SAXReader解析器
		SAXReader xmlReader=new SAXReader();
		//从类路径中获取文件路径
		InputStream is=Demo1.class.getClassLoader().getResourceAsStream(fileName);
		doc=xmlReader.read(is);
		
		return doc;		
	}
	
	@Test
	public void test1(){
		try {
			Document doc=this.readXML1("bin/resources/employee.xml");
			System.out.println(doc);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Test
	public void test2(){
		try {
			Document doc=this.readXML2("resources/employee.xml");
			System.out.println(doc);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 获取跟节点
	 */
	@Test
	public void test3(){
		try {
			Document doc=this.readXML2("resources/employee.xml");
//			System.out.println(doc);
			//从doc对象中取出根节点
			Element root=doc.getRootElement();
			System.out.println(root.getName());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/**
	 * 根据根节点,获取根节点下所有儿子的元素节点
	 */
	@Test
	public void test4(){

		List<Employee> emps=new ArrayList<Employee>();
		
		try {
			Document doc=this.readXML2("resources/employee.xml");
//			System.out.println(doc);
			//从doc对象中取出根节点
			Element root=doc.getRootElement();
//			System.out.println(root.getName());
			//获取根节点下的所有儿子的元素节点
			List<Element> employees=root.elements();
			
			
			for(Element employee:employees){
				//属性id
				int  id=Integer.parseInt(employee.attributeValue("id"));
				//获取name
				String name=employee.elementText("name");
				//获取age
				int age=Integer.parseInt(employee.element("age").getText());
				//获取性别
				String gender=employee.elementText("gender");
				//获取薪水
				double salary=Double.parseDouble(employee.elementText("salary"));
				Employee emp=new Employee(id,name,age,gender,salary);
				emps.add(emp);
				
				
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(emps);
	}
	/**
	 * 根据跟节点
	 * 获取根节点下的所有的儿子节点
	 * 用迭代器实现的
	 */
	@Test
	public void test5(){

		List<Employee> emps=new ArrayList<Employee>();
		
		try {
			Document doc=this.readXML2("resources/employee.xml");
//			System.out.println(doc);
			//从doc对象中取出根节点
			Element root=doc.getRootElement();
//			System.out.println(root.getName());
			//获取根节点下的所有儿子的元素节点
			Iterator<Element>  employees=root.elementIterator();
			while(employees.hasNext()){
				Element employee=employees.next();
				//属性id
				int  id=Integer.parseInt(employee.attributeValue("id"));
				//获取name
				String name=employee.elementText("name");
				//获取age
				int age=Integer.parseInt(employee.element("age").getText());
				//获取性别
				String gender=employee.elementText("gender");
				//获取薪水
				double salary=Double.parseDouble(employee.elementText("salary"));
				Employee emp=new Employee(id,name,age,gender,salary);
				emps.add(emp);
				
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(emps);
	}
	/**
	 * 写xml
	 * 1.创建Document
	 * 2.添加数据
	 * 3.生成xml
	 * @throws Exception 
	 */
	@Test
	public void test6() throws Exception{
		List<Employee> emps=new ArrayList<Employee>();
		//构建要添加的Employee的数据
		Employee emp1=new Employee(6,"aa",20,"男",2000);
		Employee emp2=new Employee(7,"bb",20,"男",2000);
		Employee emp3=new Employee(8,"cc",20,"男",2000);
		Employee emp4=new Employee(9,"dd",20,"男",2000);
		Employee emp5=new Employee(10,"ee",20,"男",2000);
		Employee emp6=new Employee(11,"ff",20,"男",2000);
		emps.add(emp1);
		emps.add(emp2);
		emps.add(emp3);
		emps.add(emp4);
		emps.add(emp5);
		emps.add(emp6);
		//1.创建Document对象
		Document doc=DocumentHelper.createDocument();
		//2.添加根节点
		Element root = doc.addElement("list");
		//3.循环添入数据
		for(Employee emp:emps){
			//给根节点下添加了一个Employee节点
			Element employee=root.addElement("employee");
			//给Employee节点添加信息
			employee.addAttribute("id",emp.getId()+" ");
			employee.addElement("name").addText(emp.getName());
			employee.addElement("age").addText(emp.getAge()+" ");
			employee.addElement("gender").addText(emp.getGender());
			employee.addElement("salary").addText(emp.getSalary()+" ");
			
		}
		//把内存中构建完的xml文档写入xml
		XMLWriter writer=new XMLWriter();
		OutputStream os=new FileOutputStream("src/resources/newemployee.xml");
		writer.setOutputStream(os);
		writer.write(doc);
		writer.close();
		
		
	}
	/**
	 * 写xml
	 * 1.创建Document
	 * 2.添加数据
	 * 3.生成xml
	 * @throws Exception 
	 */
	@Test
	public void test7() throws Exception{
		List<Employee> emps=new ArrayList<Employee>();
		//构建要添加的Employee的数据
		Employee emp1=new Employee(6,"aa",20,"男",2000);
		Employee emp2=new Employee(7,"bb",20,"男",2000);
		Employee emp3=new Employee(8,"cc",20,"男",2000);
		Employee emp4=new Employee(9,"dd",20,"男",2000);
		Employee emp5=new Employee(10,"ee",20,"男",2000);
		Employee emp6=new Employee(11,"ff",20,"男",2000);
		emps.add(emp1);
		emps.add(emp2);
		emps.add(emp3);
		emps.add(emp4);
		emps.add(emp5);
		emps.add(emp6);
		//1.创建Document对象
		Document doc=this.readXML2("resources/employee.xml");
		//2.添加根节点
		Element root = doc.getRootElement();
		//3.循环添入数据
		for(Employee emp:emps){
			//给根节点下添加了一个Employee节点
			Element employee=root.addElement("employee");
			//给Employee节点添加信息
			employee.addAttribute("id",emp.getId()+"");
			employee.addElement("name").addText(emp.getName()+"");
			employee.addElement("age").addText(emp.getAge()+"");
			employee.addElement("gender").addText(emp.getGender()+"");
			employee.addElement("salary").addText(emp.getSalary()+"");
			
		}
		//把内存中构建完的xml文档写入xml
		XMLWriter writer=new XMLWriter();
		OutputStream os=new FileOutputStream("src/resources/employee.xml");
		writer.setOutputStream(os);
		writer.write(doc);
		writer.close();
		
		
	}
	
	
}

上一篇 jdk1.8新特性

Comments

Content