xml 概念

XML(EXtensible Markup Language) ,可拓展标记语言

标记,指的的是标记语言,也称标签语言,可以用一系列的标签来对数据进行描述。

例如, tom

拓展,指的是用户可以自定义标签

作用

  1. XML可以作为数据传输的标准
  2. xml可以作为配置文件

xml语法

XML 声明文件的可选部分,如果存在需要放在文档的第一行,如下所示:

<?xml version="1.0" encoding="utf-8"?>

描述了XML的版本,以及XML文档所使用的编码

元素

元素,指的是xml中的标记.这种标记也被称为标签,节点

命名规范

  • 不能以数字或部分标点符号开头
  • 不能包含空格和特定的几个符号
  • 标签必须成对出现,不允许缺省结束标签
  • 根元素有且只有一个 大小写敏感
  • 允许多层嵌套但是不允许交叉嵌套
  • xml 必须包含根元素
  • 元素可以包含标签体,也可以不包含标签体
  • xml 标签对大小写敏感

xml 中第一行,文档声明部分,固定写法,不需要关闭标签

属性

基本格式

<?xml version="1.0" encoding="utf-8"?>
<root>
	<person sex="female" age='18' email='briup@briup.com'></person>
</root>

基本格式 <元素名 属性名=“属性值”>

不论是使用子标签还是属性 描述数据都是合格的

实体

在 XML 中,一些字符拥有特殊的意义,在XML文档中,是不能直接使用的。

例如,如果把字符 “<” 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C0boFtDi-1602046595202)(E:\学习\Java2020\image\image-20200909143207725.png)]

自定义实体

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sKNOmajT-1602046595204)(E:\学习\Java2020\image\image-20200909143258886.png)]

xml约束

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ItvXY8yM-1602046595206)(E:\学习\Java2020\image\image-20200909143355951.png)]

约束语法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hx3mJ3FV-1602046595208)(E:\学习\Java2020\image\image-20200909143426999.png)]

## XML解析

xml的解析方法一般有两种

DOM解析

DOM,(Document Object Model)文档对象模型,是 W3C 组织推荐的处理 XML 的一种方式。

使用DOM方式解析,要求解析器把整个XML文档装载到一个Document对象中。Document对象包含文档

元素,即根元素,根元素包含N个子元素。

根据DOM的定义,XML 文档中的每个元素都是一个节点(Node)

  • XML文档只有一个根节点
  • XML中每个元素都是一个元素节点
  • XML中每个文本都是一个文本节点
  • XML中每个属性都是一个属性节点
  • XML中每个注释都是一个注释节点
  • 使用DOM解析方式,XML文档的结构关系,在内存的对象(document)中依然存在
  • 但如果XML文档过大,那么需要把整个XML文档装载进内存,这时候会对内存空间要求比较高

SAX解析

SAX,(Simple API for XML)它不是W3C标准,但它是 XML 社区事实上的标准,因为使用率也比较高,

几乎所有的 XML 解析器都支持它。

使用SAX方式解析,每当读取一个开始标签、结束标签或者文本内容的时候,都会调用我们重写的一个

指定方法,该方法中编写当前需要完成的解析操作。直到XML文档读取结束,在整个过程中,SAX解析

方法不会在内存中保存节点的信息和关系。

  • 使用SAX解析方式,不会占用大量内存来保存XML文档数据和关系,效率高。
  • 但是在解析过程中,不会保存节点信息和关系,并且只能从前往后,顺序读取、解析。

java解析xml

JAXP (Java API for XMLProcessing),是JavaSE-API的一部分,它由javax.xml、org.w3c.dom 、 org.xml.sax 包及其子包组成

也就是说,不借助于第三方jar包,使用JDK自带的API,就可以完成对XML文档的解析

XML解析实例

jaxp中的DOM解析

需要解析class.xml

<?xml version="1.0" encoding="UTF-8"?>
<students>
<stu id="2022001">
<name>王五</name>
<age>23</age>
</stu>
<stu id="2022002">
<name>李四</name>
<age>20</age>
</stu>
</students>

实例代码

package com.lut.day2;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Test {
	public static void main(String[] args) throws Exception {
		// 获取documentBuilderFactory
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 获取documentBuilder
		DocumentBuilder builder = factory.newDocumentBuilder();
		// 获取xmlDocument
		Document doc = builder.parse(new File("src/test.xml"));
		// 获取根节点
		Element root = doc.getDocumentElement();
		List<Student> list = new ArrayList<>();
		NodeList nodeList = root.getChildNodes();
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node node = nodeList.item(i);
			// 如果为文本节点且节点内容为空格,就进行下一次
			if (node.getNodeType() == Node.TEXT_NODE) {
				if (node.getNodeValue().trim().length() == 0) {
					continue;
				}
			}
			if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("stu")) {
				// 获取属性列表
				NamedNodeMap attributes = node.getAttributes();
				String id = "";
				String name = "";
				String age = "";
				// 循环变量拿到每一个属性
				for (int j = 0; j < attributes.getLength(); j++) {
					// 强制转换为Attr类型的对象,表示属性
					Attr attr = (Attr) attributes.item(j);
					if(attr.getName()=="id") {
						id = attr.getValue();
					}
				}
				// 获取子节点列表
				NodeList nodeList2 = node.getChildNodes();
				for(int j=0;j<nodeList2.getLength();j++) {
					Node node2 = nodeList2.item(i);
					// 如果为文本节点且节点内容为空格,就进行下一次
					if (node2.getNodeType() == Node.TEXT_NODE) {
						if (node2.getNodeValue().trim().length() == 0) {
							continue;
						}
					}
					// 如果为name标签
					if (node2.getNodeType()==Node.ELEMENT_NODE && node2.getNodeName().equals("name")) {
						// 获取他的唯一一个Text子节点
						Node text = node2.getChildNodes().item(0);
						name  = text.getNodeValue();
					}
					// 如果为age标签
					if (node2.getNodeType()==Node.ELEMENT_NODE && node2.getNodeName().equals("age")) {
						// 获取他的唯一一个Text子节点
						Node text = node2.getChildNodes().item(0);
						age  = text.getNodeValue();
					}
					
				}
				
				list.add(new Student(id, name, age));
			}
		}
		
		System.out.println(list);
	}
}

class Student {
	String id;
	String name;
	String age;

	public Student(String id, String name, String age) {
		this.id = id;
		this.age = age;
		this.name = name;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
	}
	

}

Sax解析

JAXP中的SAX解析的步骤:

  • 获取SAXParserFactory工厂类对象, SAXParserFactory.newInstance()
  • 使用工厂对象,创建出SAX解析器, saxParserFactory.newSAXParser()
  • 调用解析器的 parse() 解析xml文件,然后重写DefaultHandler类中的方法,进行事件处理 saxParser.parse(filePath, new DefaultHandler(){…}
package com.briup.demo;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class Test {
public static void main(String[] args) {
Test dom = new Test();
String filePath = "src/com/briup/demo/class.xml";
dom.saxParse(filePath);
}
public void saxParse(String filePath) {
//获取SAXParserFactory工厂类对象
SAXParserFactory saxParserFactory =
SAXParserFactory.newInstance();
try {
//使用工厂对象,创建出SAX解析器
SAXParser saxParser =
saxParserFactory.newSAXParser();
//解析xml文件,重写DefaultHandler类中的方法,进行事件处理
saxParser.parse(filePath, new DefaultHandler() {
//当解析器解析到xml文档开头的时候,调用该方法
@Override
public void startDocument() throws SAXException {
System.out.println("开始解析xml文档");
}
//当解析器解析到xml文档结束的时候,调用该方法
@Override
public void endDocument() throws SAXException {
System.out.println();
System.out.println("结束解析xml文件");
}
/**
* 当解析器解析到一个开始标签的时候,调用该方法
* @param uri 命名空间
* @param localName 本地名称(不带前缀)
* @param qName 限定的名称(带有前缀)
* @param attributes 该节点上的属性列表
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String
qName, Attributes attributes)
throws SAXException {
System.out.println("节点:"+qName+"解析开始");
if(attributes.getLength()>0) {
System.out.print(" 属性列表:");
for(int i=0;i<attributes.getLength();i++) {
String attrName = attributes.getQName(i);
String attrValue = attributes.getValue(i);
System.out.print(attrName+"="+attrValue+" ");
}
System.out.println();
}
}
/**
* 当解析器解析到一个结束标签的时候,调用该方法
* @param uri 命名空间
* @param localName 本地名称(不带前缀)
* @param qName 限定的名称(带有前缀)
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String
qName) throws SAXException {
System.out.println("节点:"+qName+"解析结束");
}
//当解析器解析到文件值的时候,调用该方法
@Override
public void characters(char[] ch, int start, int length) throwSAXException {
String str = new String(ch,start,length);
if(!"".equals(str.trim())) {
System.out.println("文本节点:"+str);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}

案例

package com.briup.demo;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class Test {
public static void main(String[] args) {
Test dom = new Test();
String filePath = "src/com/briup/demo/class.xml";
dom.saxParse(filePath);
}
public void saxParse(String filePath) {
//获取SAXParserFactory工厂类对象
SAXParserFactory saxParserFactory =
SAXParserFactory.newInstance();
try {
//使用工厂对象,创建出SAX解析器
SAXParser saxParser =
saxParserFactory.newSAXParser();
//解析xml文件,重写DefaultHandler类中的方法,进行事件处理
saxParser.parse(filePath, new DefaultHandler() {
@Override
public void startDocument() throws SAXException {
System.out.println("<?xml version='1.0' encoding='utf-8'?
>");
}
@Override
public void startElement(String uri, String localName, String
qName,
Attributes atts) throws SAXException {
StringBuilder sb = new StringBuilder();
sb.append("<").append(qName);
for(int i = 0; i < atts.getLength(); i++) {
sb.append(" ");
sb.append(atts.getQName(i));
sb.append("=");
sb.append("'");
sb.append(atts.getValue(i));
sb.append("'");
}
sb.append(">");
System.out.print(sb.toString());
}
@Override
public void endElement(String uri, String localName, String
qName)
throws SAXException {
System.out.print("</" + qName + ">");
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.print(new String(ch, start, length));
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}

Dom4j解析

需要导入dom4j的依赖

案例

public class Test {
public static void main(String[] args) {
Test test = new Test();
String filePath = "src/com/briup/demo/class.xml";
try {
Document document = test.parse(new File(filePath));
test.handler1(document);
} catch (Exception e) {
e.printStackTrace();
}
}
public Document parse(File file) throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(file);
return document;
}
public void handler1(Document document) {
Element root = document.getRootElement();
System.out.println("-----获取根节点下面所有的子节点(儿子节点)-----");
// 获取根节点下面所有的子节点(儿子节点)
for (Iterator<Element> it = root.elementIterator(); it.hasNext();) {
Element element = it.next();
System.out.println(element.getName());
}
System.out.println("-----获取根节点下面指定名称的子节点(儿子节点)-----");
// 获取根节点下面指定名称的子节点(儿子节点)
for (Iterator<Element> it = root.elementIterator("stu"); it.hasNext();)
{
Element element = it.next();
System.out.println(element.getName());
}
System.out.println("-----获取根节点中的所有属性-----");
// 获取根节点中的所有属性
for (Iterator<Attribute> it = root.attributeIterator(); it.hasNext();) {
Attribute attribute = it.next();
System.out.println(attribute.getName()+"="+attribute.getValue());
}
}
}
//运行结果:
-----获取根节点下面所有的子节点(儿子节点)-----
stu
stu
teacher
-----获取根节点下面指定名称的子节点(儿子节点)-----
stu
stu
-----获取根节点中的所有属性-----
sid=1
sname=briup
  1. dom4j提供了两个方法支持XPath搜索 List selectNodes(String expr); Node selectSingleNode(String expr);
  2. Xpath表达式的几种写法
    第一种形式: /AAA/BBB/CCC:表示层级结构,表示AAA下面BBB下面的所有CCC
    第二种形式: //BBB:选择文档中所有的BBB元素
    第三种形式: /AAA/BBB/:选择目录下的所有元素 //:选择所有的元素 //AAA[1]/BBB:选择第一个AAA下的BBB元素
    第四种形式: //AAA/BBB[1]:选择所有AAA的第一个BBB元素 //AAA/BBB[last()]:选择所有AAA的最后一个BBB元素
    第五种形式: //@id:选择所有的id属性 //BBB[@id]:选择具有id属性的BBB元素
    第六种形式: //BBB[@id=‘b1’] :选择含有属性id并且其值为b1的BBB元素

使用DOM4j创建一个xml文档

public class Test {
public static void main(String[] args) {
Test test = new Test();
try {
test.createXML(test.createDocument());
} catch (Exception e) {
e.printStackTrace();
}
}
public Document parse(File file) throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(file);
return document;
}
@SuppressWarnings("all")
public Document createDocument() {
Document document = DocumentHelper.createDocument();
Element root = document.addElement("root");
Element author1 = root.addElement("author")
.addAttribute("name", "briup1")
.addAttribute("location", "上海")
.addText("hello");
Element author2 = root.addElement("author")
.addAttribute("name", "briup2")
.addAttribute("location", "北京")
.addText("world");
return document;
}
public void createXML(Document document) {
try {
FileWriter out = new FileWriter("src/com/briup/demo/my.xml");
document.write(out);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}