主要内容
学习目标
知识点 | 要求 |
---|---|
XML介绍 | 掌握 |
DTD | 掌握 |
XSD | 掌握 |
DOM解析 | 掌握 |
SAX解析 | 掌握 |
XML(Extensible Markup Language)可扩展标记语言。严格区分大小写。
XML是用来传输和存储数据的。
XML 多用在框架的配置文件中。
XML 大多平台都支持,所以可以实现跨平台数据传输。
HTML 是用来显示数据的。
<元素名 属性名=”属性值”>文本内容元素名>
前后元素名相同, 元素名自定义。
每个元素可以有0到多个属性,属性名自定义。
文本内容表示文字。
支持嵌套结构。
结束时元素名前有 /。
XML的语法和HTML语法是差不多的,但是比HTML要求更加严格。
1. 元素正确嵌套
2. XML文件的第一行必须是xml声明
3. 只能有一个根节点
4. 严格区分大小写
5. 结束标签必须包含/
6. 属性值必须被""包围起来
7. XML认为换行标记也属于文本节点
8.
注释。有的非官方资料认为这是注释节点。
要显示的字符
]]>
项目根路径下创建product.xml并存储下面信息。
根节点叫做products,里面包含3个product元素。每个元素里面又包含下面的元素及文本内容
id | 名称(name) | 单价(price) | 颜色(color) | 尺寸(size) | 库存(num) |
---|---|---|---|---|---|
P001 | 蜘蛛王皮鞋 | 268 | 黑色 | 42 | 500 |
P002 | ThinkPad x240 | 5678 | 黑色 | 12 | 50 |
P003 | WD移动硬盘 | 568 | 蓝色 | 5 | 1000 |
<products>
<product>
<id>P001id>
<name>蜘蛛王皮鞋name>
<price>268price>
<color>黑色color>
<size>42size>
<num>500num>
product>
products>
DTD(Document Type Definition)文档类型定义。
即约束XML文件中可以包含哪些元素、哪些属性、及元素个数和元素之间的关系和元素的顺序。
在包含DTD的XML文件中,如果XML内容不满足DTD要求,会提示错误。
DTD的三种分类:
1. 内部DTD
2. 外部DTD
3. 公共DTD
直接在XML中编写DTD内容。不推荐。
内容可以是其他标签,也可以是#PCDATA文本内容。
定义属性
内容控制可取值:
1. #REQUIRED 必须有这个属性
2. #IMPLIED 可以有也可以没有
3. #FIXED “内容” 必须取固定值
(name,age,score) 表示顺序必须是先name,后age,然后score
student+ 表示student至少出现一次。括号内容的元素名都可以跟下面符号
1. ?表示子元素出现0次到1次 (最多出现一次)
2. + 表示子元素至少出现一次 (至少出现一次 )
3. *表示子元素可以出现0到多次 (任意)
DOCTYPE students[
<!ELEMENT students (student*)>
<!ELEMENT student (name, age, sex)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ATTLIST student id CDATA #REQUIRED>
<!ATTLIST name class CDATA #FIXED "qwe">
<!ATTLIST age test CDATA #IMPLIED>
]>
<students>
<student id="aa">
<name class="qwe">张三name>
<age test="aaa">18age>
<sex>男sex>
student>
students>
外部DTD是我们自己编写的DTD文件。通过引入方式引入DTD。
在外部创建一个xxx.dtd文件,文件内容和内部dtd [ ] 中的内容相同。
DOCTYPE students SYSTEM "aa.dtd">
<students>
<student id="aa" >
<name class="qwe">张三name>
<age test="aaa">18age>
<sex>男sex>
student>
students>
公共DTD是一些开源组织编写的DTD,并且已经发布到互联网中。
公共DTD语法:
代码示例:
DTD是较简单的语法检查机制。整体语法较简单,功能较单一。
当需要对XML文件结构更新时,需要修改整个DTD文件,不够灵活。
XSD(XML Schema Definition )XML模式定义。
属于DTD的升级版。完美的解决了DTD使用时不易扩展问题,并且提供了更强大功能。
新建xxx.xsd。
所有需要的元素、属性都需要被定义。
<aa:schema xmlns:aa="http://www.w3.org/2001/XMLSchema">
<aa:element name="students">
<aa:complexType>
<aa:sequence>
<aa:element ref="student" maxOccurs="2"/>
aa:sequence>
aa:complexType>
aa:element>
<aa:element name="student">
<aa:complexType>
<aa:sequence>
<aa:element name="name" type="aa:string"/>
<aa:element name="age" type="aa:int"/>
<aa:element name="sex" type="aa:boolean"/>
aa:sequence>
<aa:attribute name="id" use="optional" fixed="aa"/>
aa:complexType>
aa:element>
aa:schema>
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="s.xsd">
<student id="aa">
<name>name>
<age>11age>
<sex>falsesex>
student>
students>
在Java中提供了两种XML解析方式:DOM、SAX。
Document Object Model 文档对象模型。把XML文件一次性加载到内存中,并转换为树状模型。然后一个节点一个节点的解析,这种解析方式效率较高,但是比较消耗内存,适用于小型XML文档。
SAX(Simple API for XML)解析:是基于事件的解析,它是为了解决DOM解析的资源耗费而出现的。SAX在解析一份XML文档时,会依次出发文档开始、元素开始、元素结束、文档结束等事件,应用程序通过监听解析过程中所触发的事件即可获取XML文档的内容。该方式不需要事先调入整个文档,优势是占用资源少,内存消耗小,一般在解析数据量较大的文档是采用该方式。
DOM解析所有API都是org.w3c包中。
使用DOM操作XML按照标准树状结构一层一层解析。
解析器是基于工厂设计模式的。当获取到文档对象后每个元素都是一个节点,然后操作节点对象。
在DOM解析时,每个换行符都是一个文本节点,所以一定要过滤掉换行。
以上面的students作为xml进行解析。
已知XML文件就三层结构,所以直接使用循环进行解析。如果XML文档结构比较深,此处需要使用递归。
public class TestDOM {
public static void main(String[] args) throws Exception {
parse();
}
//使用DOM解析XML
public static void parse() throws ParserConfigurationException, IOException, SAXException {
//1.获取document构建 工厂对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//2.根据文档构建工厂获取文档构建对象
/*
* 将xml变为document
* 手动的创建document
* */
DocumentBuilder db = dbf.newDocumentBuilder();
//3.使用文档构建对象, 将xml解析为document对象
Document document = db.parse(new File("stu.xml"));
//4.根据标签名获取根标签
NodeList rootList = document.getElementsByTagName("students");
//5.xml中仅会存在一个根标签, 获取这个根标签
Node root = rootList.item(0);
System.out.println("根节点名称: " + root.getNodeName());
//6.获取标签所有的直接子节点
NodeList childNodes = root.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
//7.获取每一个子节点
/*
* getNodeType(): 结点类型, 常量
* 1: 标签结点
* 2: 属性结点
* 3: 文本结点
* */
Node item = childNodes.item(i);
if (item.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(" 子节点名称: " + item.getNodeName());
//8.获取该结点的所有子节点
NodeList childNodes1 = item.getChildNodes();
for (int j = 0; j < childNodes1.getLength(); j++) {
Node item1 = childNodes1.item(j);
if (item1.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(" 子节点名称: " + item1.getNodeName() + " : " + item1.getTextContent());
}
}
}
}
}
}
DOM生成XML时主要是创建节点。然后把节点添加到上层节点。
public class TestDOM {
public static void main(String[] args) throws Exception {
transform();
}
//先构建文档, 再将文档变为xml
public static void transform() throws ParserConfigurationException, TransformerException, FileNotFoundException {
//1.获取文档构建器工厂对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//2.构建器工厂对象 获取 构建器对象
DocumentBuilder db = dbf.newDocumentBuilder();
//3.创建文档对象
Document document = db.newDocument();
//4.创建teachers标签
Element teachers = document.createElement("teachers");
//5.创建teacher标签
Element teacher = document.createElement("teacher");
teacher.setAttribute("id", "tea"); //设置属性
//6.创建name标签
Element name = document.createElement("name");
name.setAttribute("class", "na"); //设置属性
name.setTextContent("zs");
//7.创建age标签
Element age = document.createElement("age");
age.setTextContent("18");
//8.创建sex标签
Element sex = document.createElement("sex");
sex.setTextContent("男");
//9.设置标签之间的关系
/* 添加teacher的子标签 */
teacher.appendChild(name);
teacher.appendChild(age);
teacher.appendChild(sex);
/* 添加teachers的子标签 */
teachers.appendChild(teacher);
/* 添加文档的子标签 */
document.appendChild(teachers);
/* 设置为独立的xml */
document.setXmlStandalone(true);
//10.将document对象变为xml
//10.1 创建转换器工厂对象
TransformerFactory tff = TransformerFactory.newInstance();
//10.1 根据转换器工厂对象 获取 转换器
Transformer tf = tff.newTransformer();
tf.setOutputProperty(OutputKeys.INDENT, "yes");
tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
//10.3 将document转化为xml 通过流输出到指定的位置
/*
* 参数1: 指定document源
* 参数2: 输出的位置
* */
tf.transform(new DOMSource(document), new StreamResult(new FileOutputStream("teacher.xml")));
}
}
SAX解析是基于事件模型完成的。所有的API都在org.xml中。
SAX解析时也会识别换行为文本节点,这个坑一定躲避。
public class TestSAX {
public static void main(String[] args) throws Exception {
parse();
}
public static void parse() throws Exception {
//1.SAX解析器工厂对象
SAXParserFactory spf = SAXParserFactory.newInstance();
//2.基于工厂对象获取解析器对象
SAXParser sp = spf.newSAXParser();
//3.使用解析器解析xml
sp.parse(new File("java_day13/teacher.xml"), new MyHandler());
}
public class MyHandler extends DefaultHandler {
String name = null;
@Override
public void startDocument() throws SAXException {
System.out.println("文档开始解析");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("开始解析, 标签名: " + qName);
name = qName;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String s = new String(ch, start, length);
System.out.println(s);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("解析结束, 标签名: " + qName);
}
@Override
public void endDocument() throws SAXException {
System.out.println("文档解析结束");
}
}
}
SAX 生成XML 和手写XML比较相似。
也是在调用5个操作方法。
public class TestSAX {
public static void main(String[] args) throws Exception {
parse();
}
public void transfom() throws TransformerConfigurationException, FileNotFoundException, SAXException {
//1.创建转换器工厂
SAXTransformerFactory stff = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
//2.根据工厂获取转换器
/*
* 传输
* 创建xml
* */
TransformerHandler th = stff.newTransformerHandler();
Transformer transformer = th.getTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
th.setResult(new StreamResult(new FileOutputStream("stu.xml")));
th.startElement(null, null, "students", null);
AttributesImpl attributes = new AttributesImpl();
attributes.addAttribute(null, null, "id", null, "aa");
th.startElement(null, null, "student", attributes);
th.startElement(null, null, "name", null);
char[] chars = "zs".toCharArray();
th.characters(chars, 0, chars.length);
th.endElement(null, null, "name");
th.startElement(null, null, "age", null);
char[] chars1 = "19".toCharArray();
th.characters(chars1, 0, chars1.length);
th.endElement(null, null, "age");
th.startElement(null, null, "sex", null);
char[] chars2 = "男".toCharArray();
th.characters(chars2, 0, chars2.length);
th.endElement(null, null, "sex");
th.endElement(null, null, "student");
th.endElement(null, null, "students");
th.endDocument();
}
}
使用SAX | DOM 解析xml, 将解析xml的代码封装到一个方法中, 调用该方法返回一个对象(将xml解析的内容创建对象. 设置属性值, 返回对象)
<phone id="iph">
<name>lsname>
<price>1999price>
<color>黑色color>
phone>
解析后:
phone对象 属性值 name ls price 1999 color 黑色