一、XML简介
- 全称为可扩展标记语言(Extensible Markup Language)
- XML是w3c组织发布的,允许用户自定义标签,一个标签用于描述一段数据。
- XML常见应用:XML语言出现的根本目标在于
描述现实生活中经常出现的有关系的数据
,还经常用作框架中软件配置文件
,以描述程序模块之间的关系。 XML是为了传输数据
,html是为了展示数据。
用XML语言来描述数据如下图。
二、XML语法
(1)文档声明
<?xml version="1.0" encoding="UTF-8" standalone="yes ?>
version="1.0"
:用来声明版本encoding="GB2312"
:说明文档的字符编码standalone="yes"
:说明文档是否独立
(2)元素/标签
- XML元素指的是xml文件中出现的标签,一个标签分为开始标签和结束标签。
- 一个标签中可以嵌套若干子标签。但不允许交叉嵌套。
- 格式良好的XML文档必须有且仅有一个根标签,其它标签都是这个跟标签的子孙标签。
- 由于空格和换行都作为原始内容被处理,所以使用换行和缩进等方式来让原文件中的内容清晰可读的"良好"书写习惯可能要被迫改变。
元素命名规范:一个XML元素可以包含字母、数字以及其它一些可见字符,但必须遵守下面的一些规范
①区分大小写,例如<P>
和<p>
是两个不同的标记。
②不能以数字或"_"(下划线)等标点字符开头。
③不能以XML(或XML、或Xml等)开头。
④不能包含空格
⑤名称中间不能包含冒号(:
)。
(3)属性
- 一个标签可以有多个属性,每个属性都有它自己的名称和取值,例如
<input name="text">
。 - 属性值一定要用双引号(
"
)或单引号('
)引起来。 - 定义属性必须遵循与标签相同的命名规范。
在XML技术中,标签属性所代表的信息,也可以被改成用子元素的形式来描述,例如:
<input>
<name>text</name>
<input>
(4)注释
- XML文件中注释采用:
<!--注释内容-->
- XML声明之前不能有注释,注释不能嵌套。
(5)CDATA区、特殊字符
CDATA区
在编写XML文件时,有些内容可能不想让解析引擎解析执行,而是当作原始内容处理,可以把这些内容放在CDATA区里面,对于CDATA区域内的内容,XML解析程序不会处理,而是直接原封不动的输出。
<![CDATA[
<href>
<br/>
</href>
]]>
特殊字符
特殊字符 | 替代符号 |
---|---|
& | & |
< | < |
> | > |
" | " |
’ | ' |
(5)处理指令(processing instruction)
- 处理指令PI,用来指挥解析引擎如何解析XML文档内容。
- 例如,在XML文档中可以使用
xml-stylesheet
指令,通知XML解析引擎,应用css文件显示xml文档内容。<?xml-stylesheet type="text/css" href="1.css"?>
- 处理指令必须以"
<?
“作为开头,以”?>
"作为结尾,XML声明语句就是最常见的一种处理指令。
三、XML解析
XML解析的方式
dom解析
(Document Object Model,即文档对象模型)是W3C组织推荐的处理XML的一种方式。sax解析
(Simple API for XML)不是官方标准,但它是XML社区事实上的标准,几乎所有的XML解析器都支持它。- 基于
已封装库
的XML解析开发包(Jaxp、Jdom、dom4j)。
给出需要解析的demo.xml文件和EmpList.xml文件
demo.xml
<?xml version="1.0" encoding="UTF-8"?>
<employees>
<employee id="0">
<name>Alexia</name>
<age>23</age>
<sex>Female</sex>
<weight>150</weight>
<weight><a>160</a></weight>
</employee>
<employee id="1">
<name height="178">Edward</name>
<age>24</age>
<sex>Male</sex>
</employee>
<employee id="2">
<name>wjm</name>
<age>23</age>
<sex>Female</sex>
</employee>
<employee id="3">
<name>wh</name>
<age>24</age>
<sex>Male</sex>
</employee>
</employees>
EmpList.xml
<?xml version="1.0" encoding="UTF-8"?>
<list>
<emp id="1">
<name>张三</name>
<age>34</age>
<gender>男</gender>
<salary>3000</salary>
</emp>
<emp id="2">
<name>王五</name>
<age>18</age>
<gender>女</gender>
<salary>6500</salary>
</emp>
<emp id="3">
<name>赵六</name>
<age>28</age>
<gender>男</gender>
<salary>4400</salary>
</emp>
<emp id="4">
<name>钱七</name>
<age>19</age>
<gender>男</gender>
<salary>12000</salary>
</emp>
</list>
(1)使用DOM解析XML
DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。
优点:把XML文件在内存中构造成树形结构,可以遍历和修改节点。
缺点:如果文件比较大,内存有压力,解析的实际时间会比较长。
①.DOM编程的步骤
①创建一个DocumentBuilderFactory的对象.
②创建一个DocumentBuilder对象.
③通过DocumentBuilder对象的parse(String fileName)方法解析xml文件.
②.使用Dom解析xml–>DomXml.java
package com.demo;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Dom解析Xml
*/
public class DomXml {
public static void main(String[] args) throws Exception {
// 1.[获得工厂对象]-->创建一个DocumentBuilderFactory的对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 设置由此工厂生成的解析器,忽略注释
dbf.setIgnoringComments(true);
// 忽略空格
dbf.setIgnoringElementContentWhitespace(true);
// 2.[获得DOM解析器对象]-->创建一个DocumentBuilder对象.
DocumentBuilder builder = dbf.newDocumentBuilder();
// 3.[调用DOM解析器对象解析XML文档]通过DocumentBuilder对象的parse(String fileName)方法解析xml文件.
Document doc = builder.parse("src/com/demo.xml");
// 获得根节点
Element root = doc.getDocumentElement();
System.out.println(root.getTagName());
// 根据标签名获得节点集合
NodeList nodeList = doc.getElementsByTagName("employee");
System.out.println("employees节点个数:" + nodeList.getLength());
// 遍历nodeList
for (int i = 0; i < nodeList.getLength(); i++) {
Element element = (Element) nodeList.item(i);
// 获得id属性值
String attribute = element.getAttribute("id");
System.out.println("id:" + attribute);
// 获取第一个employee
if (i == 0) {
// 获得元素下面的name文本
System.out.println("name文本值:"+ element.getElementsByTagName("name").item(0).getFirstChild().getNodeValue());
// 获得元素下面的sex文本
System.out.println("sex文本值:"+ element.getElementsByTagName("sex").item(0).getFirstChild().getNodeValue());
// 获得第一个weight里的文本值
System.out.println("weight文本值:"+ element.getElementsByTagName("weight").item(0).getFirstChild().getNodeValue());
// 获得第二个weight里的文本值
System.out.println("weight中a的文本值:"+ element.getElementsByTagName("weight").item(1).getFirstChild().getFirstChild().getNodeValue());
}
}
}
}
DOM解析效果↓
(2)使用SAX解析XML
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会对文档进行处理。
优点:解析可以立即开始,速度快,没有内存压力。
缺点:不能对节点做修改。
①.SAX解析的步骤
1.创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
2.创建解析器对象
SAXParser saxParser = spf.newSAXParser();
3.通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
4.设置读取器的事件处理器
xmlReader.setContentHandler(new BookParserHander());
5.解析XML文件
saxParser.parse(file, new SaxXml());
②.使用Sax解析xml–>SaxXml.java
package com.demo;
import java.io.File;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxXml extends DefaultHandler{
//开始解析文档时调用
@Override
public void startDocument() throws SAXException {
System.out.println("开始文档");
}
//结束解析文档时调用
@Override
public void endDocument() throws SAXException {
System.out.println("结束文档");
}
//在解析元素开始时被调用
@Override
public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
System.out.println("开始解析元素***"+qName);
}
public static void main(String[] args) throws Exception, Exception {
//1.创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
//2.创建解析器对象
SAXParser saxParser = spf.newSAXParser();
//创建File指明要解析的xml
File file = new File("src/com/demo.xml");
//3.解析XML文件
saxParser.parse(file, new SaxXml());
}
}
SAX解析效果↓
(3)使用Dom4j库解析XML
- Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来后独立开发的。与JDOM不同的是,dom4j使用接口和抽象父类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。
- Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也使用了Dom4j。
- 使用Dom4j开发,需下载Dom4j相应的jar文件。
①.使用Dom4j解析xml–>TestDom4j.java
package com.demo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;
import com.entiry.Emp;
public class TestDom4j {
public static void main(String[] args) throws Exception {
// 创建SaxReader解析器
SAXReader reader = new SAXReader();
// 指明解析的文件,获得document文档
Document doc = reader.read(new File("src/com/EmpList.xml"));
// 获得根节点
Element root = doc.getRootElement();
// 获得根节点下所有子节点
List<Element> elements = root.elements();
// 创建List<Emp>保存所有员工对象
List<Emp> list = new ArrayList<Emp>();
// 遍历子节点
for (Element element : elements) {
// 先获得节点的属性再获取值
String id = element.attribute("id").getValue();
//直接根据节点名获得节点中文本值element.elementText("name");
// 先获得节点再获得节点值
String name = element.element("name").getText();
String age = element.elementText("age");
String gender = element.elementText("gender");
String salary = element.elementText("salary");
Emp emp = new Emp(Integer.parseInt(id), name,Integer.parseInt(age), gender, Double.parseDouble(salary));
list.add(emp);
}
System.out.println(list);
}
}
dom4j解析效果↓
②.创建文档,添加节点
/**
* 添加子节点:addElement()
* 添加文本值:addText()
* 添加子节点,并设置文本addElement().addText()
* 添加属性:addAttribute(,)
*/
@Test
public void testAdd() throws Exception{
//list存放Emp对象
List<Emp> emps = new ArrayList<Emp>();
emps.add(new Emp(1,"张三",33,"男",9000.0));
emps.add(new Emp(2,"李四",18,"女",8000.0));
emps.add(new Emp(3,"王五",20,"男",10000.0));
//创建文档对象
Document doc = DocumentHelper.createDocument();
//创建根节点
Element root = doc.addElement("list");
for (Emp emp : emps) {
//向根元素中添加名为emp的子元素
Element ele = root.addElement("emp");
//为emp元素添加id属性,并设置属性值
ele.addAttribute("id", emp.getId()+"");
//添加子节点,并设置节点中的文本值
ele.addElement("name").addText(emp.getName());
ele.addElement("age").addText(emp.getAge()+"");
ele.addElement("gender").addText(emp.getGender());
ele.addElement("salary").addText(emp.getSalary()+"");
}
//通过XMLWriter生成物理文件
FileOutputStream fos = new FileOutputStream("src/com/EmpList1.xml");
XMLWriter writer = new XMLWriter();
writer.setOutputStream(fos);
//将文档写出到指定路径中
writer.write(doc);
writer.close();
}
添加节点效果↓
③.修改节点和属性
@Test
public void testUpdate() throws Exception{
SAXReader sax = new SAXReader();
Document doc = sax.read("src/com/EmpList1.xml");
//获取根节点
Element root = doc.getRootElement();
//获取下标为1的节点
Element e2 = (Element)root.elements().get(1);
//获取id属性和name节点
Attribute id =e2.attribute("id");
Element name = e2.element("name");
System.out.println("id:"+id.getValue()+" name:"+name.getText());
//修改di属性和name节点
id.setValue("222");
name.setText("李四2号");
System.out.println("id:"+id.getValue()+" name:"+name.getText());
}
修改后的效果↓