• XML 的解析方式有两种方式: DOM 解析和 SAX 解析.
  • DOM 解析: 根据 XML 的层级结构, 在内存中分配一个树形结构, 把 XML 的标签, 属性和文本都封装成对象.
    • 优点: 可以实现增删改查操作
    • 弊端: 如果文件过大, 容易造成内存溢出
  • SAX 解析: 采用事件驱动, 边读边解析. 从上到下, 一行一行的解析, 解析到某一个对象, 把对象返回.
    • 优点: 可以方便的实现查询
    • 不能实现增删改操作
  • XML 解析器
    • jaxp 解析器, 由 SUN 公司提供的针对 dom 和 sax 的解析器
    • dom4j 解析器, 由 dom4j 组织提供的针对 dom 和 sax 的解析器

jaxp 解析器

  • jaxp 解析器在 JDK 的 javax.xml.parsers 包里面
  • DOM 解析使用到的类:
    • DocumentBuilder : 解析器类
    • DocumentBuildreFactory : 解析器工厂类
  • SAX 解析使用到的类:
    • SAXParser : 解析器类
    • SAXParserFactory : 解析器工厂

jaxp 解析器的 DOM 方式解析 xml 文件

  1. DocumentBuilder 解析器类

    • 该解析器类是一个抽象类, 不能 new. 此类的实例可以从 DocumentBuilderFactory.newDocumentBuilder() 方法获取.
    • 解析 xml 文档, 使用解析器类中的 parse("xml 路径");方法, 返回的是 Document 对象, 其父接口为 Node
    • Document 对象中的方法:
      • getElementsByTagName(String tagname); : 获取标签, 返回的是 NodeList 集合
      • createElement(String tagName); : 创建标签
      • createTextNode(String data); : 创建文本
      • appendChild(Node newChild); : 将文本添加到标签下面
  2. DocumentBuilderFactory 解析器工厂
    • 该解析器工厂也是一个抽象类, 不能直接 new. 以 DocumentBuilderFactory.newInstance() 获取对应的实例.
  3. 使用 jaxp 解析器实现对 xml 文档的增删改查
// 示例:
// xml 文件
<?xml version="1.0" encoding="gbk"?>
<person>
<p1>
<name>zhangsan</name>
<age>20</age>
</p1>
<p1>
<name>lisi</name>
<age>32</age>
</p1>
</person> // 查询: 查询 xml 文件中所有的 name 元素的值
/*
* 思路:
* 1. 创建解析器工厂
* 2. 根据解析器工厂创建解析器
* 3. 解析 xml 返回 document, 需要导包, org.w3c.dom.Document
* 4. 使用 document 对象中的 getElementsByTagName() 方法, 获取 NodeList 集合
* 5. 遍历集合, 获取每一个 name 对应的值
*/ public class TestJaxp { public static void main(String[] args){ // 1. 创建解析器工厂
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); // 2. 根据解析器工厂创建解析器
DocumentBuilder builder = builderFactory.newDocumentBuilder(); // 3. 解析 xml 文档
Document document = builder.parser("src/person.xml"); // 4. 得到 name 元素
NodeList list = document.getElementsByTagName("name"); // 5. 遍历集合, 得到每一个 name 元素, NodeList 接口位于 org.w3c.dom 包下
for(int i=0; i<list.getLength(); i++){
Node name1 = list.item(i); // 得到 name 元素里面的值
String s = name1.getTextContent();
System.out.println("name:"+s);
} }
} // 添加: 在第一个 p1 下面添加 <sex>male</sex>
/*
* 思路:
* 1. 创建解析器工厂
* 2. 根据解析器工厂创建解析器
* 3. 解析 xml 文档返回 document
* 4. 获取第一个 p1 元素
* 5. 创建 sex 标签, createElement
* 6. 创建文本 "male", createTextNode
* 7. 把文本添加到 sex 下面, appendChild()
* 8. 把 sex 添加到第一个 p1 下面
*
*
* 9. 回写 xml 文档(将内存中的数据写入到硬盘中)
* 9.1 创建 TransformerFactory 工厂
* 9.2 创建 Transformer 类
* 9.3 回写
*/ public class TestJaxp{
public static void main(String[] args){ // 1. 创建解析器工厂
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); // 2. 创建解析器
DocumentBuilder builder = builderFactory.newDocumentBuilder(); // 3. 解析 xml 文档
Document document = builder.parse("src/person.xml"); // 4. 获取所有 p1 元素
NodeList list = document.getElementsByTagName("p1"); // 5. 获取第一个 p1 元素
Node p1 = list.item(0); // 6. 创建 sex 标签
Element sex1 = document.createElement("sex"); // 7. 创建 "male" 文本
TextNode text1 = document.createTextNode("male"); // 8. 将文本添加到 sex 标签下, 没有返回值
sex1.appendChild(text1); // 9. 将 sex 标签添加到 p1 下面
p1.appendChild(sex1); // 10. 回写 xml
// 创建 TransformerFactory 工厂
TransformerFactory transformerFactory = TransformerFactory.newInstance();
// 得到 Transformer 类
Transformer transformer = transformerFactory.newTransformer();
// 回写
// transform(Source xmlSource, Result outputTarget);
// Source 是接口, DOMSource 是其中的一个实现类.
// Result 也是接口, StreamResult 是其中的一个实现类
transformer.transform(new DOMSource(document), new StreamResult("src/person.xml"));
}
} // 升级版, 把获取 document 对象封装成方法,
// 只要对 xml 文档进行增删改操作, 都需要回写 xml , 因此回写 xml 也封装成一个方法 public class JaxpUtils{ // 返回 document 对象
public static Document getDocument(String path){ // 有异常需要 try/catch
try{
// 1. 创建解析器工厂
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); // 2. 根据解析器工厂创建解析器
DocumentBuilder builder = builderFactory.newDocumentBuilder(); // 3. 解析 xml 文档,获取 document 对象
Document document = builder.parser(path); // 4. 将结果返回
return document; } catch (Exception e){
e.printStackTrace();
} // 如果出现异常, 返回 null
return null;
} // 回写 xml 操作
public static void xmlTransform(Document document, String path){ try{
// 1. 创建 TransformerFactory 工厂
TransformerFactory transformerFactory = TransformerFactor.newInstance(); // 2. 得到 Transformer 类
Transformer transformer = transformerFactory.newTransformer(); // 3. 使用 transform 方法进行回写
transformer.transform(new DOMSource(document), new StreamResult(path));
} catch(Exception e){
e.printStackTrace();
}
}
} // 删除: 删除 p1 下面的 <sex>male</sex> public void remSex(){
// 1. 获取 document 对象
Document document = JaxpUtils.getDocument("src/person.xml"); // 2. 获取 sex 标签
NodeList list = document.getElementsByTagName("sex")
Node sex1 = list.item(0); // 3. 使用 sex 的父节点并删除 sex,
// 获取父节点, 使用 getParentNode 方法
sex1.getParentNode.removeChild(sex1); // 4. 回写 xml
JaxpUtils.xmlTransform(document,"src/person.xml");
} // 使用 jaxp 遍历节点, 也就是把 xml 中的所有元素名称打印出来
/*
* 思路: 使用递归实现遍历
* 1. 得到根节点
* 2. 得到根节点的子节点
* 3. 得到根节点的子节点的子节点
*/ public static void listElement(String path) throws Exception{ // 1. 获取 document 对象
Document document = JaxpUtils.getDocument("src/person.xml"); // 2. 编写一个方法实现遍历
list2(document);
} // 因为 Node 是 Document 的父接口
// list(Document document) 升级为 list(Node node)
public static void list2(Node node){ // 判断是否是元素, 如果是, 就输出
// 如果不判断, 会把空格和换行当成内容也打印出来
if(node.getNodeType() == Node.ELEMENT_NODE){
System.out.println(node.getNodeName);
} // 得到第一层子节点
NodeList list = node.getChildNodes(); // 遍历 list
for(int i=0; i<list.getLength(); i++){
// 得到每一个节点
Node node2 = list.item(i); // 递归
list2(node2);
}
}

jaxp 解析器的 SAX 方式解析 xml 文件

  1. SAX 方式解析 xml 文档, 只能实现对文档的查询操作,不能实现增删改操作.
  2. SAXParser 解析器
    • 该解析器的实例通过 SAXParserFactory.newSAXParser() 方法获得
    • 解析 xml 文档, 使用解析器类中的 parse(String uri, DefaultHandler dh);方法, 返回值为 void
    • String uri : xml 文档的路径
    • DefaultHandler dh: 事件处理器, 相当于在 parse() 方法上绑定了一个事件
  3. SAXParserFactory 解析器工厂
    • 通过 newInstance() 方法获得
  4. 使用 jaxp 的 SAX 方式解析 xml 文档
// DefaultHandler 说明
// 1. DefaultHandler 中有三个方法: startElement, characters, endElement
// 2. 当解析到开始标签时, 自动执行 startElement 方法,
// 3. 当解析到文本内容时, 自动执行 characters 方法
// 4. 当解析到标签结束时, 自动执行 endElement 方法 // 示例:
// xml 文件 <?xml version="1.0" encoding="gbk"?>
<person>
<p1>
<name>zhangsan</name>
<age>20</age>
</p1>
<p1>
<name>lisi</name>
<age>32</age>
</p1>
</person> // 需求一: 打印 xml 文档中所有元素
/*
* 思路:
* 1. 创建解析器工厂
* 2. 创建解析器
* 3. 执行 parse 方法
*
* 4. 自己创建一个类, 继承 DefaultHandler
* 5. 重写类里面的三个方法
* / public class TestJaxp{
public static void main(String[] args){ // 1. 创建解析器工厂
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); // 2. 创建解析器
SAXParser saxParser = saxParserFactory.newSAXParser(); // 3. 执行 parse 方法, 并传入自定义的事件处理器
saxParser.parse("src/person.xml", new MyDefault2());
}
} // 打印整个文档的事件处理器 class MyDefault2 extends DefaultHandler{ // 重写 startElement
public void startElement(String uri, String localName, String qname,
Attributes attributes) throws SAXException{
System.out.print("<"+qName+"/>"); // qName 表示的是标签名, 此处输出的是开始标签
} // 重写 characters 方法
public void characters(char[] ch, int start, int length) throws SAXException{
System.out.print(new String(ch,start,length)); // 打印元素中的文本
} // 重写 endElement 方法
public void endElement(String uri, String localName, String qName) throws SAXException{
System.out.print("</"+qName+">"); // qName 表示的是标签名, 此处输出的是结束标签
}
} // 获取所有的 name 元素的值, 事件处理器 class MyDefault3 extends DefaultHandler{ // 定义变量
boolean flag = false; // 重写 startElement
public void startElement(String uri, String localName, String qname,
Attributes attributes) throws SAXException{
// 判断 qName 是否是 name 元素
if("name".equals(qName)){
flag = true;
}
} // 重写 characters 方法
public void characters(char[] ch, int start, int length) throws SAXException{
// 如果 flag 值是 true 的时候, 表示解析到的是 name 元素
if(flag){
System.out.println(new String(ch,start,length));
}
} // 重写 endElement 方法
public void endElement(String uri, String localName, String qName) throws SAXException{ // 重置 flag 标记, 表示 name 元素读取结束
if("name".equals(qName)){
flag = false;
}
}
} // 获取第一个 name 元素中的值 class MyDefault3 extends DefaultHandler{ // 定义变量
boolean flag = false;
int count=1; // 重写 startElement
public void startElement(String uri, String localName, String qname,
Attributes attributes) throws SAXException{
// 判断 qName 是否是 name 元素
if("name".equals(qName)){
flag = true;
}
} // 重写 characters 方法
public void characters(char[] ch, int start, int length) throws SAXException{
// 如果 flag 值是 true 的时候, 表示解析到的是 name 元素
if(flag && count == 1){
System.out.println(new String(ch,start,length));
}
} // 重写 endElement 方法
public void endElement(String uri, String localName, String qName) throws SAXException{ // 重置 flag 标记, 表示 name 元素读取结束
if("name".equals(qName)){
flag = false;
count++;
}
}
}

参考资料:

XML 解析之 jaxp 解析器的更多相关文章

  1. dom技术解析xml下jaxp解析器详细代码

    1.使用jaxp实现查询操作 person.xml <?xml version="1.0" encoding="UTF-8" standalone=&qu ...

  2. xml解析方式之JAXP解析入门

    XML解析 1 引入 xml文件除了给开发者看,更多的情况使用[程序读取xml文件]的内容.这叫做xml解析 2 XML解析方式(原理不同) DOM解析 SAX解析 3 XML解析工具 DOM解析原理 ...

  3. java 之 xml 之解析工具jaxp

    一.jaxp的api查看 *jaxp是javase一部分 *jaxp解析器在jdk的javax.xml.parsers包里面 *共四个类:分别针对dom和sax解析使用的类 *dom解析类: Docu ...

  4. XML解析之JAXP

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  5. xml文件解析(使用解析器)

    一.Xml解析,解析xml并封装到list中的javabean中 OM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在 ...

  6. XML解析之JAXP案例详解

    根据一个CRUD的案例,对JAXP解析xml技术,进行详细的解释: 首先,已知一个xml文件中的数据如下: <?xml version="1.0" encoding=&quo ...

  7. javaweb学习总结十三(dom4j方式对XML文档进行解析以及Xpath的使用)

    一:dom4j方式介绍 对于xml的解析总共有三种 1:jaxp方式,是sun公司开发的,分为sax方式和dom方式 2:jdom方式,后来其中部分人员参与开发dom4j 3:dom4j方式,是现在企 ...

  8. Android XML文档解析(一)——SAX解析

    ---------------------------------------------------------------------------------------------------- ...

  9. xml常用四种解析方式优缺点的分析×××××

    xml常用四种解析方式优缺点的分析 博客分类: xml   最近用得到xml的解析方式,于是就翻了翻自己的笔记同时从网上查找了资料,自己在前人的基础上总结了下,贴出来大家分享下. 首先介绍一下xml语 ...

随机推荐

  1. 测试-一个unity的编译bug,初始化器

    .net C#下测试: public class Class1 { public bool toggle1 = true; public bool toggle2; } 一个结构类Class1,对里面 ...

  2. Atitit php序列化 php的serialize序列化和json序列化

    Atitit php序列化 php的serialize序列化和json序列化 PHP 对不同类型的数据用不同的字母进行标示,Yahoo 开发网站提供的Using Serialized PHP with ...

  3. Atitit.ati dwr的原理and设计 attilax 总结 java php 版本

    Atitit.ati dwr的原理and设计 attilax 总结 java php 版本 1. dwr的优点相对于ajax来说..1 2. DWR工作原理1 3. Dwr的架构2 4. 自定义dwr ...

  4. ORACLE的显式游标与隐式游标

    1)查询返回单行记录时→隐式游标: 2)查询返回多行记录并逐行进行处理时→显式游标 显式游标例子: DECLARE CURSOR CUR_EMP IS SELECT * FROM EMP; ROW_E ...

  5. [转]C++11 标准新特性:Defaulted 和 Deleted 函数

    http://www.ibm.com/developerworks/cn/aix/library/1212_lufang_c11new/

  6. vim插件管理器的安装和配置-windows

    # vim插件管理器的安装和配置-windows ### 前言------------------------------ vim做一框功能强大的编辑器,扩展功能令人称奇,插件机制非常灵活- 本篇推荐 ...

  7. RxBinding -- 官网说明

    RxBinding -- 官网说明 新建 模板 小书匠 作用 组件 平台绑定 support-v4 绑定 appcompact-v7 绑定 design 库绑定 recyclerview-v7 绑定 ...

  8. busybox中的inittab解析

    init进程是由内核启动的第一个(也是唯一一个)用户进程(进程ID为1),是所有进程的祖先.然后init进程根据配置文件决定启动哪些程序,init是后续所有进程的发起者. 用busybox制作的文件系 ...

  9. java.lang.NoSuchMethodError: org.apache.spark.util.ThreadUtils$.newDae

    -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1. ...

  10. 微信小程序5 - 数据驱动界面

    微信小程序不可以使用js直接控制界面元素.而是通过改变 this.data中的属性,同步到界面 这个问题可以克服,带来的就是和H5不一样的编码方式.JS中更多的是改变数据的逻辑,而不是获取某个View ...