XML文件解析

时间:2025-01-25 08:44:15

文章目录

  • 前言
  • 1、XML解析
    • 1.1、SAX
    • 1.2、DOM
    • 1.3、XPath

前言

xml文档里包含的是xml的元素,指的是从开始标签直到结束标签的部分,元素里可以包含其他元素,元素也可以拥有其他属性,比如:

<students>
	<student id="1">
		<name>yang</name>
		<age>25</age>
		<stuNo>1212</stuNo>
	</student>
</students>

students,student,name,age,stuNo等这些都叫元素标签也可以叫元素节点和元素对象。
id是某个元素的节点的属性,叫属性节点和属性对象。
yang,25,1212等这样的数据叫做值,也可以叫做文本节点和文本对象。

实体引用:xml中有若干符号,是跟xml有冲突的,所以需要用别名代替

实体引用       字符         说明
&lt;            <          小于
&gt;            >          大于
&amp;           &&aops;          '          单引号
&quot;          "          双引号

比如: 
<name>1&lt;2</name>
<desc>这个是一个&quot;描述&quot;文本</desc>

CDATA段

格式:<![CDATA][文本内容]]>
特殊标签中的实体引用被忽略,所有内容被当成一整块文本数据。

<?xml version="1.0" encoding="UTF-8"?>
<root>
<![CDATA[
	<hello> 

	<worl>	
]]>
<subRoot> </subRoot>
</root>

1、XML解析

1.1、SAX

SAX解析方式:(simple api for xml)是一种xml解析的替代方法,想对比DOM解析,sax解析是一种速度快,更有效的方法,因为他是逐行扫描xml文档,一边扫描一边解析而且相对于dom解析,sax可以在解析文档的任意时刻停止解析。

优点:解析可以立即开始,速度快,没有内存压力。
缺点:不能对节点做修改。

sax解析必须借助第三方工具dom4j,工具中提供若干jar包,jar包中提供了若干api来解析xml,dom4j是一个非常优秀的解析xml框架,也是一个开源的框架。

/**
  * 1. 用SAX解析XML,获取文档对象
  */
 @Test
 public void test01() throws DocumentException {
     SAXReader sax = new SAXReader();
     // 1. 指定XML件的位置路径
     Document document1 = sax.read("src/main/resources/");
     System.out.println(document1);
     // 2.从类路径下获取XML文件
     InputStream is = TestAnnotationClass.class.getClassLoader().getResourceAsStream("");
     Document document2 = sax.read(is);
     System.out.println(document2);
     // 结果
     // org.@18ef96 [Document: name src/main/resources/]
     // org.@769c9116 [Document: name null]
 }

 /**
  * 2. 用SAX解析XML,获取文档的根节点对象
  */
 @Test
 public void test03() throws DocumentException {
     SAXReader sax = new SAXReader();
     InputStream is = TestAnnotationClass.class.getClassLoader().getResourceAsStream("");
     Document document = sax.read(is);
     // 从文件对象中获取文档的根节点
     Element root = document.getRootElement();
     System.out.println(root);
     // 结果
     // org.@6956de9 [Element: <list attributes: []/>]
 }

 /**
  * 3. 用SAX解析XML,从根节点获取根节点下的所有的儿子元素节点
  */
 @Test
 public void test04() throws DocumentException {
     // 准备一个集合,用来存储遍历到的节点
     List<Employee> employees = new ArrayList<Employee>();
     // 获取SAX对象
     SAXReader sax = new SAXReader();
     InputStream is = TestAnnotationClass.class.getClassLoader().getResourceAsStream("");
     // 获取文档对象
     Document document = sax.read(is);
     // 获取文档的根节点对象
     Element root = document.getRootElement();
     // 获取当前节点下的所有元素节点返回List集合
     List<Element> emps_Element = root.elements();
     // 循环遍历元素
     for (Element emp : emps_Element) {
         // 获取当前节点的某一个属性名对应的属性对象,返回值是Attribute类的对象,从Attribute类的对象获取当前属性对象中的属性值
         int id = Integer.parseInt(emp.attribute("id").getValue());
         // 获取当前元素节点里的文本节点的值
         String name = emp.element("name").getText();
         // 获取当前元素节点里的文本节点的值
         int age = Integer.parseInt(emp.element("age").getText());
         // 获取当前元素节点下的指定元素节点名称的节点里的文本节点的值
         String gender = emp.elementText("gender");
         // 获取当前元素节点下的指定元素节点名称的节点里的文本节点的值
         double salary = Double.parseDouble(emp.elementText("salary"));
         // 构造函数
         Employee e = new Employee(id, name, age, gender, salary);
         // 存入集合
         employees.add(e);
     }
     System.out.println(employees);
     // 结果
     // [Employee [id=6, name=杨, age=20, gebder=男, sal=2000.0], Employee [id=7, name=杨, age=20, gebder=男,
     // sal=2000.0], Employee [id=8, name=杨, age=20, gebder=男, sal=2000.0]]
 }

 /**
  * 4. 写XML写到新的文件中 1.创建Document对象 2.添加数据 3.生成XML文件
  */
 @Test
 public void test05() throws IOException {
     // 定义一个集合
     List<Employee> emps = new ArrayList<Employee>();
     // 构造函数创建对象
     Employee emp1 = new Employee(12, "yang", 50, "男", 2000);
     Employee emp2 = new Employee(02, "c", 20, "男", 2000);
     // 将对象放入到集合中
     emps.add(emp1);
     emps.add(emp2);
     // 创建Document对象
     Document doc = DocumentHelper.createDocument();
     // 添加根节点 <List></List>
     Element root = doc.addElement("list");
     // 循环填入数据 <List><employee></employee></List>
     for (Employee emp : emps) {
         // 给根节点list下添加一个employee节点
         Element employee = root.addElement("employee");
         // 给employee节点下添加id属性,name,age,gender,salary元素节点
         employee.addAttribute("id", emp.getId() + " ");
         employee.addElement("name").addText(emp.getName());
         employee.addElement("age").addText(emp.getAge() + " ");
         employee.addElement("gender").addText(emp.getGebder());
         employee.addElement("salsay").addText(emp.getSal() + " ");
     }
     // 把内存中的Document对象中的数据写到写到指定的xml文件中
     // 方式一
     // XMLWriter writer = new XMLWriter();
     // OutputStream os = new FileOutputStream("");
     // (os);
     // (doc);
     // ();
     // 方式二
     OutputFormat outformat = OutputFormat.createPrettyPrint();
     outformat.setEncoding("UTF-8");
     OutputStream os = new FileOutputStream("src/main/resources/");
     XMLWriter writer = new XMLWriter(os, outformat);
     writer.write(doc);
     writer.close();
}	 

1.2、DOM

DOM解析方式:(document Object Model文档对象模型),是w3c组织推荐的处理xml的一种方式,dom解析器在解析xml文档时,会把文档中的所有元素按照其出现的层次关系解析成一个Node对象(节点对象)。

优点:把xml文件在内存中构建树形结构,可以遍历和修改节点。
缺点:如果文件比较大,内存有压力,解析时间会比较长。

Dom解析不需要额外第三方jar包,jdk(jre)提供了若干api操作xml。

1.3、XPath

路径表达式,Xpath是一门在XML文档中查找信息的语言。Xpath可以用来在xml文档中对元素和属性进行遍历。由于我们单纯使用dom定位节点时,大部分时间需要一层一层的处理,有了xpath就解决了逐层遍历。他可以根据路径,属性,甚至是条件进行节点检索。

路径表达式

- 斜杠(/)作为路径的分隔符

- 导航到同样一个节点,有相对路径和绝对路径两种
	绝对路径:必须从"/"起始,后面紧跟节点,比如:/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>
  1. /bookstore 选取跟节点bookstore,这是绝对路径。
  2. bookstore/book 选取所有属于bookstore的子元素book元素,这是相对路径。
  3. //book 选取所有book子元素,而不管他们在文档中的位置。
  4. bookstore//book 选取所有属于bookstore元素的后代的,book的元素而不管他们位于bookstore之下什么位置。
  5. //@lang 选取所有名为lang的属性

谓语

谓语条件,就是对路径表达式的附加条件,所有的条件都写在[]中,表示对节点的进一步筛选,比如

  1. /bookstore/book[1] 表示选择bookstore的第一个book子元素。
  2. /bookstore/book[last()] 表示bookstore的最后一个book子元素。
  3. /bookstore/book[last()-1] 表示bookstore的倒数第二个book子元素。
  4. /bookstore/book[position()< 3] 表示选择bookstore的前两个book子元素。
  5. //title[@lang] 表示选择所有具有lang属性的title节点。
  6. //title[@lang=‘eng’] 表示所有具有lang属相且值等于eng的title节点。
  7. //bookstore/book[price] 表示选择bookstore的book子元素且被选中的book子元素必须带有price子元素。
  8. /booksstore/book[price>35.0] 表示选择bookstore的book子元素,且选中的book子元素的price的子元素值必须大于35.0。
  9. /bookstore/book[price>35.0]/title 表示在上面的例子结果中选择title子元素。
  10. /bookstore/book/price[.>35.0] 表示选择值大于35.0的/bookstore/book的price子元素。

通配符

  1. “*” 表示匹配任何元素节点。
  2. @ 表示匹配任何属性值。
  3. node() 表示匹配任何类型的节点。
  4. //* 选择文档中的所有元素节点。
  5. /* /* 表示选择所有第二层的元素节点。
  6. /bookstore/* 表示选择bookstore的所有元素子节点。
  7. //title[@*] 表示选择所有带有属性的title元素