XML
文章目录
XML是什么
- XML (XtensibleMarkup Language) 可扩展标记语言,其实就是一套由标签(元素)构成的语言
- XML 是一种特殊的文档,可以去描述对象数据并存储对象数据
1|zzb|18965271871
例如上面中的数据是存储在普通文件中,但是这种数据并没有具体的数据描述,我们就不知道到底哪个数据是id
或者name
,但是 XML 是可以的。例如下面就是一段XML代码
<id>1</id>
<name>zzb</name>
<phone>18965271871</phone>
上图中我们就可以很清晰的看出不同的数据的含义是什么。即使我们把这个文档发送给别人,别人也能立马看的出来数据的含义。
XML 历史
XML源于标准的通用标记语言SGML,其前身GML是20世纪60年代IBM发明的,用于以独立于设备的方式描述文档。
- 1969年,IBM公司开发了一种文档描述语言,用来解决不同系统中文档格式不同的问题。这样,文档的显示和打印可能更少或更多地依赖特殊的硬件,不过这样的系统需要不同的计算机系统提供专门的软件来显示和打印文档。IBM把自己这种标识语言称作通用标记语言GenelizedMarkupLanguage,即GML)。GML是IBM许多文档系统的基础,包括Script和Bookmaster。
- 1986年国际标准化组织ISO认为IBM提出的概念很好,并发布了为生成标准化文档而定义的标记语言标准ISO8879,称为新的语言SGML
- XML是SGML的简化子集,与之兼容。
- XML最初是关注Web服务结构化文档。
- XML是通过万维网联盟W3C开发的
- 万维网联盟创建于1994年,是Web技术领域最具权威和影响力的国际中立性技术标准机构。到目前为止,W3C已发布了200多项影响深远的Web技术标准及实施指南
- W3C于1998年2月10日发布了XML 1.0。第二版于2000年10月9日出版
- 图形表示
XML特点
- 规范数据格式,存储数据,一般也可以去充当小型的数据存储仓库
- io/file 数据不规范,格式不统一,解析起来比较麻烦
- 可以作为框架或者项目的配置文件可以使程序更加灵活
- 后面我们会学到maven工具就会使用
xml
去作为配置文件 - 更多情况下作为配置文件使用 增加程序的灵活性
- xml是跨平台、跨语言的一门技术
- 基本上不管是Java还是Python或者其他语言基本都支持
xml
- 可以在网络中传输
- 在分布式系统中,A系统向B系统发送数据,就可以通过XML的方式。当然这种方式已经慢慢被淘汰,发送数据采用另外一个格式(json)去发送。
XML 语法
XML 编辑器
- 只要是文本工具都可以去编辑和撰写 xml
记事本
,word
,EditPlus
,NotePad++
…
- 也可以用idea开发工具
Vscode
,Eclipse
,IntelliJ IDEA
标签语法
-
文件后缀名必须为 .xml
- 记事本的后缀
.txt
, Java程序的后缀.java
- 记事本的后缀
-
第一行必须写xml处理指令:
<? xml version="1.0" encoding="UTF-8/GB2312/GBK" ?>
-
有且仅有一个根元素
-
开始、结束标签配对出现
<?xml version="1.0" encoding="UTF-8"?> <Student> <name></name> </Student>
-
标签命名规则
-
标签名可以重复
-
以字母、 下划线、$开
-
后可跟字母、数字、下划线、$
-
大小写敏感
-
不能使用保留字
-
没有长度限制
-
命名尽量表达出其含义
-
名字有多个单词组成,可以使用驼峰标识法,或将多个单词用
_
隔开<studentName><studentName> <student_name></student_name>
-
-
总结
- 一个XML 必须包含 头部和一对根标签(元素)
- 一对标签就包含了起始标签 结束标签
- 标签名可以重复
- 文本是写在起始标签和结束标签中间
- 属性是写在起始标签里面,属性名不可重复,但是内容可以重复
- 标签名和属性名都可以自定义,但是必须满足一定的规则
-
练习
- 描述一个学生数据
- 描述多个老师数据
- 描述多个学生和老师数据
-
<?xml version="1.0" encoding="UTF-8"?> <!-- 描述多个老师和学生的数据 --> <person> <teachers> <teacher id = "111"> <name>马老师</name> <gender>男</gender> </teacher> <teacher id = "222"> <name>李老师</name> <gender>男</gender> </teacher> </teachers> <students> <student id = "111"> <name>wangzh</name> <age>11</age> </student> <student id = "22"> <name>cuilue</name> <age>12</age> </student> </students> </person>
属性语法
- 属性只能出现在开始标签中,而且一个开始标签中可以出现多个属性,但同一开始标签中属性不能重名
- key=value配对出现
- 属性必须要有值,而且值必须用双引号或单引号引起来
注释语法
<!-- 注释不能嵌套 -->
良构xml语法
- 满足XML语法规则的XML文件
- 写一个良构的xml,统计所学课程情况(课程名、课时、授课老师)
<course id="100">
<teacher_name>Tom</teacher_name>
<course_name>JAVA</course_name>
<time_duration>32</time_duration>
</course>
实体
-
如果再xml中输出特殊符号
- < > != ‘ “ 等等之类的符号
-
特殊的符号在xml在中有特殊含义,因此需要申明实体
- & + 实体名 + ;
-
实体类型
- PCDATA:可以被解析器解析的字符字符数据
Entity | Description | Character |
---|---|---|
& lt; | "less than" | < |
& gt; | "greater than" | > |
& quot; | "quote" | " |
& apos; | "apostrophe" | ’ |
& amp; | "ampersand" | & |
CDATA: 不可以被解析器解析的字符字符数据
<![CDATA[...Anything can go here... ]]>
CDATA 有的浏览器不支持,但是 & + 实体名字 + ;
所有浏览器都支持
XML解析器
xml可以通过浏览器打开,也就是说浏览器是可以去解析XML的
DTD约束
DTD概念
- DTD定义
- Document Type Definition,文档类型定义用来对XML文档内容进行限制
- 限制 XML中可以出现的元素的名字,元素出现的顺序、元素出现的频率等
- DTD就是一套关于元素、属性和其他杂项在xml文档中使用规则的声明
DTD语法及使用
DTD引入方式
-
XML和DTD在同一文件中
<!DOCTYPE rootElement [ ... ]>
-
XML和DTD在不同文件中
<!DOCTYPE rootElement SYSTEM "path">
-
DTD放在互联网上
<!DOCTYPE rootElement PUBLIC "describe" "URL">
DTD 语法
标签限制
-
语法
<!ELEMENT 元素名称 类别>
-
空元素
标签中间不能包含任何文本或者标签
<!ELEMENT 元素名称 EMPTY> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Student [ <!ELEMENT id EMPTY> ]> <Student> <id></id> <id></id> </Student>
-
字符数据
只有 PCDATA 的元素通过圆括号中的
#PCDATA
进行声明,标签中间只能包含文本,如果包含标签报错<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Student [ <!ELEMENT id (#PCDATA)> ]> <Student> <id>HELLO!!!</id> </Student>
-
带有任何内容的元素
<!ELEMENT 元素名称 ANY> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Student [ <!ELEMENT id ANY> ]> <Student> <id> 你们所看的都只是王老师的冰山一角 <desc></desc> </id> <id>你们所看的都只是王老师的冰山一角</id> </Student>
-
带有子元素(序列)的元素
<!ELEMENT 元素名称 (子元素名称 1)> <!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.....)> <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)>
-
参考W3C文档
属性设置
-
语法
<!ATTLIST 元素名称 属性名称 属性类型 默认值>
-
将Id属性值设为唯一
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Student [ <!ELEMENT name ANY> <!ATTLIST name id ID #REQUIRED> ]> <Student> <name id="c1"></name> <name id="c2"></name> </Student>
-
参考W3C文档
Schema
- 介绍
- XML Schema 是基于 XML 的 DTD 替代者
- XML Schema 描述 XML 文档的结构。
- XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)
- 使用
XML文档解析
我们为什么需要对XML进行解析,因为当系统想要获取xml里面的数据时4,那么我们就需要利用Java代码获取
XML 文档中的数据,如图:
解析方式大致分为两类:
- JDK 自带的方式
- 掌握原理,了解解析过程
- 第三方解析方式
- 掌握
DOM4J
解析方式
- 掌握
JDK 自带的解析
SAX 解析
- 介绍
Simple API for XML Processing,一种基于事件的解析方式
-
什么是基于事件机制
事件机制 包含 事件,事件源,监听器。
例如:李四约谈客户,去了酒店,妻子王五发现了,并跟着去了。
事件 :去酒店
事件源 : 约谈客户
监听器: 妻子王五
监听动作: 跟着去了
同样的道理,基于事件的机制去解析XML,就是当解析到不同的部分会调用不同的方法,例如解析到起始标签和结束标签时就会调用不同的方法,解析到属性时也会调用不同的方法。
-
解析原理
利用解析器去读取并解析XML,并不会将整个XML,读取到内存中再去解析,而是读取一行解析一行。
不会占用内存.
- 流程图
- 代码
package com.zzb.sax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
class XmlHandler extends DefaultHandler {
/**
* 开始解析文档时,调用该方法
*/
@Override
public void startDocument() throws SAXException {
System.out.println("开始解析");
}
/**
* 解析文档结束时,调用该方法
*/
@Override
public void endDocument() throws SAXException {
System.out.println("结束解析");
}
/**
* 解析起始标签时,调用该方法
*
* <?xml version="1.0" encoding="utf-8"?>
<websites
xmlns:sina="http://www.sina.com"
xmlns:baidu="http://www.baidu.com">
<sina:website sina:blog="blog.sina.com">新浪</sina:website>
<baidu:website baidu:blog="hi.baidu.com">百度</baidu:website>
</websites>
sina:blog的uri就是前缀sina的namespace,即"http://www.sina.com"。
sina:blog 中blog就是localName。
sina:blog就是QName,
*
*
*
*
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("开始解析起始标签");
System.out.println(uri);
System.out.println(localName);
System.out.println(qName);
String value = attributes.getValue("kk");
System.out.println(value);
}
/**
* 解析结束标签,调用该方法
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
}
/**
* 解析文本时,调用该方法
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
System.out.println(new String(ch,start,length));
}
}
public class SaxApplication {
public static void main(String[] agrs) throws Exception {
// 1. 创建解析器
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
// 2. 创建事件处理器
XmlHandler xmlHandler = new XmlHandler();
// 3. 绑定事件处理器
xmlReader.setContentHandler(xmlHandler);
// 4. 解析
xmlReader.parse("src/xml-element-empty.xml");
}
}
- SAX解析优缺点
- 对xml文档边读边解析(不需要将整个文档都加载到内存)
- 对xml文档一次性顺序读取,不能随机读取
- 读到后面就忘了前面的内容,要想再次获取前面内容,必须重新读取
- 对xml文档内容是只读的
DOM解析
DOM - Document Object Model 文档对象模型,相当于树模型
-
树模型
一个树由多个节点组成,例如根节点,子节点,父节点等等。同样的一个XML文档也可以看做成一个 DOM 模型,根元素就是根节点,不同的元素就是不同的节点。
-
文档中节点类型
一个文档包含了12中节点类型,如下:
元素标签节点 Node.ELEMENT_NODE(1) 属性节点 Node.ATTRIBUTE_NODE(2) 文本节点 Node.TEXT_NODE(3) CDATA节点 Node.CDATA_SECTION_NODE(4) 实体引用名称节点 Node.ENTRY_REFERENCE_NODE(5) 实体名称节点 Node.ENTITY_NODE(6) 处理指令节点 Node.PROCESSING_INSTRUCTION_NODE(7) 注释节点 Node.COMMENT_NODE(8) 文档节点 Node.DOCUMENT_NODE(9) 文档类型节点 Node.DOCUMENT_TYPE_NODE(10) 文档片段节点 Node.DOCUMENT_FRAGMENT_NODE(11) DTD声明节点 Node.NOTATION_NODE(12)
一个节点可能包含其他多个节点
- 父节点包含子节点
-
DOM解析原理
将整个xml文档读入内存,形成驻留在内存中的树型结构,然后在进行解析。
注意跟SAX的区别
-
解析流程图
-
代码(解析)
package com.zzb.dom;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class DomApplication {
public static void main(String[] args) throws Exception {
// 1.创建解析器工厂
DocumentBuilderFactory builderFactory =
DocumentBuilderFactory.newInstance();
// 2. 创建解析器
DocumentBuilder builder =
builderFactory.newDocumentBuilder();
// 3. 解析 得到了文档
Document document = builder.parse("src/xml-element-empty.xml");
// 4. 通过文档我们可以得到第一个节点
Node node = document.getFirstChild();
// 5. 打印文档类型,和节点名字
System.out.println(node.getNodeType());
System.out.println(node.getNodeName());
System.out.println(node.getNodeValue());
String value = node.getAttributes().getNamedItem("ll").getNodeValue();
System.out.println(value);
System.out.println("----------");
// 6. 得到 所有的子节点
NodeList nodes = node.getChildNodes();
for(int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeName() + ":" + nodes.item(i).getNodeValue());
}
}
}
-
Dom解析优缺点
- 需要将整个文件加载到内存才能解析,非常消耗内存。
- 可以随机读取,不需要按照顺序读取。
- 节点可以重复读取
- 可以对文档进行新增和修改
- Dom新增文档
- 原理
- 代码
package com.zzb.dom;
import java.io.FileOutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class DomApplication {
public static void main(String[] args) throws Exception {
// 1.创建解析器工厂
DocumentBuilderFactory builderFactory =
DocumentBuilderFactory.newInstance();
// 2. 创建解析器
DocumentBuilder builder =
builderFactory.newDocumentBuilder();
// 创建文档
Document document = builder.newDocument();
// 创建节点
Element element = document.createElement("root");
Comment comment = document.createComment("这是一个注释");
Text textNode = document.createTextNode("哦,天哪");
// 添加节点,形成DOM树
element.appendChild(comment);
element.appendChild(textNode);
document.appendChild(element);
// 将DOM树转换成XML
// 创建转换工厂
TransformerFactory transformerFactory = TransformerFactory.newInstance();
// 得到转换器
Transformer transformer = transformerFactory.newTransformer();
// 设置格式
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
// 将DOM树转换成 XML内容
DOMSource xmlSource = new DOMSource(document);
// 设置目的地
StreamResult outputTarget = new StreamResult(new FileOutputStream("src/1.xml"));
// 转换 将 xmlSource 写入到 outputTarget
transformer.transform(xmlSource, outputTarget);
}
}
JAXP
经过上面的例子发现,用JDK自带的方式去解析,特别麻烦。同时程序员又是比较菜的,那我们怎么去解析呢。
Oracle 基于这个就提提供了 JAXP(Java API for XML Processing)
为java开发人员处理XML提供的统一的编程接口,其本身没有实现这套接口,而是交由第三方去实现
例如,我想自己去开发一套解析XML的程序,那么这个程序实现 JAXP 那么就可以去解析XML,同时并被JDK识别。
DOM4J
- 介绍
非 JDK 自带
Dom4j简化与 XML 的交互并且比使用 DOM 实现更快
具有性能优异、功能强大和极易使用的特点
Dom4j是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。越来越多的 Java 软件都在使用 DOM4J 来读写 XML
-
原理
跟DOM解析原理一致,只不过操作更加简化了
-
流程图
-
解析步骤
//导入jar包
//在发的资料中已经提供了(dom4j-1.6.1.jar)
//创建解析器
SAXReader reader = new SAXReader();
//获取document对象
Document document = reader.read("src/course.xml");
//获取根节点
Element element = document.getRootElement();
//获取属性
element.attribute("id");
//获取子节点
element.elements();
//获取文本
getText()
- 创建xml文档步骤
//创建Document
Document document = DocumentHelper.createDocument();
//添加注释
document.addComment("注释")
//创建根元素
Element root = document.addElement("nice");
//通过doc创建一个则会报错。
//创建属性
root.addAttribute("nice1","dd");
//格式化xml内容
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
//创建流
XMLWriter writer = new XMLWriter(new PrintWriter("src/aaa.xml"),format);
writer.write(document);
writer.flush();