一、xml的解析的简介
* xml是标记型文档* js使用dom解析标记型文档?
- 根据html的层级结构,在内存中分配一个树形结构,把html的标签,属性和文本都封装成对象
- document对象、element对象、属性对象、文本对象、Node节点对象
* xml的解析方式(技术):dom 和 sax
*** dom解析和sax解析区别:
** dom方式解析
* 根据xml的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象
* 缺点:如果文件过大,造成内存溢出
* 优点:很方便实现增删改操作
** sax方式解析
* 采用事件驱动,边读边解析
- 从上到下,一行一行的解析,解析到某一个对象,返回对象名称
* 缺点:不能实现增删改操作
* 优点:如果文件过大,不会造成内存溢出,方便实现查询操作
* 想要解析xml,首先需要解析器
** 不同的公司和组织提供了 针对dom和sax方式的解析器,通过api方式提供
*** sun公司提供了针对dom和sax解析器 jaxp
*** dom4j组织,针对dom和sax解析器 dom4j(*** 实际开发中****)
*** jdom组织,针对dom和sax解析器 jdom
二、jaxp
** jaxp是javase的一部分** jaxp解析器在jdk的javax.xml.parsers包里面
** 四个类:分别是针对dom和sax解析使用的类
*** dom:
DocumentBuilder : 解析器类
- 这个类是一个抽象类,不能new,
此类的实例可以从 DocumentBuilderFactory.newDocumentBuilder() 方法获取
- xml parse("xml路径") 方法,可以解析xml,返回是 Document 整个文档
- 返回的document是一个接口,父接口是Node,如果在document里面找不到想要的方法,到Node里面去找
- Document接口
getElementsByTagName(String tagname)
-- 这个方法可以得到标签
-- 返回集合 NodeList
createElement(String tagName)
-- 创建标签
createTextNode(String data)
-- 创建文本
appendChild(Node newChild)
-- 把文本添加到标签下面
removeChild(Node oldChild)
-- 删除节点
getParentNode()
-- 获取父节点
NodeList list接口
- getLength() 得到集合的长度- item(int index)下标取到具体的值
for(int i=0;i<list.getLength();i++) {
list.item(i); //返回Node接口
}
Node接口
- 得到标签里面的内容
DocumentBuilderFactory: 解析器工厂
- 这个类也是一个抽象类,不能new
newInstance() 获取 DocumentBuilderFactory 的实例。
三、使用jaxp实现查询操作
*** 查询xml中所有的name元素的值
* 步骤
//查询所有name元素的值
/*
* 1、创建解析器工厂
DocumentBuilderFactory.newInstance();
* 2、根据解析器工厂创建解析器
builderFactory.newDocumentBuilder();
* 3、解析xml返回document
* Document document = builder.parse("src/Person.xml");
* 4、得到所有的name元素
使用document.getElementsByTagName("name");
* 5、返回集合,遍历集合,得到每一个name元素
- 遍历 getLength() item()
- 得到元素里面值 使用 getTextContent()
* */
DocumentBuilderFactory dbf= DocumentBuilderFactory.newInstance(); DocumentBuilder db=dbf.newDocumentBuilder(); Document d=db.parse("src/Person.xml"); NodeList nl=d.getElementsByTagName("name"); for(int i=0;i<nl.getLength();i++){ Node n=nl.item(i); System.out.println(n.getTextContent()); }
四、使用jaxp添加节点
*** 在第student下面(末尾)添加 <sex>男</sex>**步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
* 4、得到所有student
使用item方法下标得到
* 5、创建sex标签 createElement
* 6、创建文本 createTextNode
* 7、把文本添加到sex下面 appendChild
* 8、把sex添加到第一个p1下面 appendChild
* 9、回写xml
* */
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); Document document = builder.parse("src/Person.xml"); NodeList nodeList = document.getElementsByTagName("student"); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); Node node2 = document.createElement("sex"); Node node3 = document.createTextNode("男"); node2.appendChild(node3); node.appendChild(node2); } TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult("src/Person.xml"));
回写xml需要用到Transformer抽象类,该类需要通过TransformerFactory类的newTransformer() 方法来获取。
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
用于回写的方法:
transform(Source xmlSource, Result outputTarget)
参数:Source xmlSource:要转换的xml输入 (该类的参数为Node接口)
outputTarget:转换 xmlSource 的 Result (该类的参数写入的路径)
五、使用jaxp修改节点
*** 修改第一个p1下面的sex内容是nan** 步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* 4、得到sex item方法
* 5、修改sex里面的值
*** setTextContent方法
*
* 6、回写xml
* */
六、使用jaxp删除节点
*** 删除<sex>nan</sex>节点** 步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* 4、获取sex元素
* 5、获取sex的父节点 使用getParentNode方法
* 6、删除使用父节点删除 removeChild方法
*
* 7、回写xml
* */
七、使用jaxp遍历节点
** 把xml中的所有元素名称打印出来** 步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* ====使用递归实现=====
* 4、得到根节点
* 5、得到根节点子节点
* 6、得到根节点子节点的子节点
* */
public static void main(String[] args) throws Exception { DocumentBuilderFactory builderFactory = DocumentBuilderFactory .newInstance(); DocumentBuilder builder = builderFactory.newDocumentBuilder(); Document document = builder.parse("src/Person.xml"); list(document); } private static void list(Node node) { //判断是元素类型时才打印 if (node.getNodeType() == Node.ELEMENT_NODE) { System.out.println(node.getNodeName()); } //得到该节点的子节点集合 NodeList list = node.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { //得到每一个子节点 Node node1 = list.item(i); //递归调用 list(node1); } }
八、sax解析的原理
* 根据xml的层级结构在内存中分配一个树形结构** 把xml中标签,属性,文本封装成对象
* sax方式:事件驱动,边读边解析
* 在javax.xml.parsers包里面
** SAXParser
此类的实例可以从 SAXParserFactory.newSAXParser() 方法获得
- parse(File f, DefaultHandler dh)
* 两个参数
** 第一个参数:xml的路径
** 事件处理器
** SAXParserFactory
实例 newInstance() 方法得到
* sax执行过程
* 当解析到开始标签时候,自动执行startElement方法
startElement(String uri, String localName, String qName, Attributes attributes)
* 当解析到文本时候,自动执行characters方法
characters(char[] ch, int start, int length)
* 当解析到结束标签时候,自动执行endElement方法
endElement(String uri, String localName, String qName)
九、使用jaxp的sax方式解析xml
** 打印出整个文档
*** 执行parse方法,第一个参数xml路径,第二个参数是 事件处理器
*** 创建一个类,继承事件处理器的类,
***重写里面的三个方法
* 获取到所有的name元素的值
** 定义一个成员变量 flag= false
** 判断开始方法是否是name元素,如果是name元素,把flag值设置成true
** 如果flag值是true,在characters方法里面打印内容
** 当执行到结束方法时候,把flag值设置成false
* 获取第一个name元素的值
** 定义一个成员变量 idx=1
** 在结束方法时候,idx+1 idx++
** 想要打印出第一个name元素的值,
- 在characters方法里面判断,
-- 判断flag=true 并且 idx==1,在打印内容
public class SaxDemo { public static void main(String[] args) throws Exception { SAXParserFactory parserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = parserFactory.newSAXParser(); MyDefault dh = new MyDefault(); saxParser.parse("src/Person.xml", dh); } } // 创建一个类,继承事件处理器的类 // 重写里面的三个方法 class MyDefault extends DefaultHandler { // 定义一个成员变量 boo= false boolean boo = false; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // 判断开始方法是否是name元素,如果是name元素,把boo值设置成true if (qName.equals("name")) { boo = true; System.out.print("<" + qName + ">"); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // 当执行到结束方法时候,把flag值设置成false if (qName.equals("name")) { boo = false; System.out.println("</" + qName + ">"); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { // 如果flag值是true,在characters方法里面打印内容 if (boo) { System.out.print(new String(ch, start, length)); } } }
十、schema约束
dtd语法: <!ELEMENT 元素名称 约束>
** schema符合xml的语法,xml语句
** 一个xml中可以有多个schema,多个schema使用名称空间区分(类似于java包名)
** dtd里面有PCDATA类型,但是在schema里面可以支持更多的数据类型
*** 比如 年龄 只能是整数,在schema可以直接定义一个整数类型
*** schema语法更加复杂,schema目前不能替代dtd
十一、schema的快速入门
* 创建一个schema文件 后缀名是 .xsd
** 根节点 <schema>
** 在schema文件里面
** 属性 xmlns="http://www.w3.org/2001/XMLSchema"
- 表示当前xml文件是一个约束文件
** targetNamespace="http://www.example.org/1"
- 使用schema约束文件,直接通过这个地址引入约束文件
** elementFormDefault="qualified"
步骤
(1)看xml中有多少个元素
<element>
(2)看简单元素和复杂元素
* 如果复杂元素
<complexType>
<sequence>
子元素
</sequence>
</complexType>
(3)简单元素,写在复杂元素的里面
<element name="person">
<complexType>
<sequence>
<element name="name" type="string"></element>
<element name="age" type="int"></element>
</sequence>
</complexType>
</element>
(4)在被约束文件里面引入约束文件
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.itcast.cn/20151111"
xsi:schemaLocation="http://www.example.org/1 1.xsd" >
** xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-- 表示xml是一个被约束文件
** xmlns="http://www.itcast.cn/20151111"
-- 是约束文档里面 targetNamespace
** xsi:schemaLocation="http://www.itcast.cn/20151111 1.xsd">
-- targetNamespace 空格 约束文档的地址路径
* <sequence>:表示元素的出现的顺序
<all>: 元素只能出现一次
<choice>:元素只能出现其中的一个
maxOccurs="unbounded": 表示元素的出现的次数
<any></any>:表示任意元素
* 可以约束属性
* 写在复杂元素里面
***写在 </complexType>之前
--
<attribute name="id1" type="int" use="required"></attribute>
- name: 属性名称
- type:属性类型 int string
- use:属性是否必须出现 required
* 复杂的schema约束
* 引入多个schema文件,可以给每个起一个别名
<?xml version="1.0" encoding="UTF-8"?> <!-- 数据文件 引用多个Schema --> <company xmlns = "http://www.example.org/company" xmlns:dept="http://www.example.org/department" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/company company.xsd http://www.example.org/department department.xsd" > <employee age="30"> <!-- 部门名称 --> <dept:name>人力资源部</dept:name> <!-- 员工名称 --> <name>王晓晓</name>
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/company" elementFormDefault="qualified"> <element name="company"> <complexType> <sequence> <element name="employee"> <complexType> <sequence> <!-- 引用任何一个元素 --> <any></any> <!-- 员工名称 --> <element name="name"></element> </sequence> <!-- 为employee元素添加属性 --> <attribute name="age" type="int"></attribute> </complexType> </element> </sequence> </complexType> </element> </schema>
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/department" elementFormDefault="qualified"> <!-- 部门名称 --> <element name="name" type="string"></element> </schema>