今日关键词:

XML解析器

DOM

SAX

JAXP

DEMO4J

XPath

XML解析器

1.解析器概述

什么是解析器

  XML是保存数据的文件,XML中保存的数据也需要被程序读取然后使用。那么程序使用什么来读取XML文件中的数据呢?XML解析器!例如.properties文件的解析器是Properties类一样!

  XML不只被Java语言使用,还被C++、C#、Javascript等等语言使用,所以解析XML不是一门语言的工作!

DOM和SAX介绍

主流的XML解析有两种标准:DOM和SAX。它们是标准,是思想,不是真正的解析器,它们是跨语言的!!!

l  DOM(Document Object Model):W3C组织提供的解析XML文档的标准接口;

l  SAX(Simple API for XML):(草民)社区讨论的产物,是一种事实上的标准。

Apache的xerces组件实现了DOM和SAX,所以在我们在Java中解析XML需要使用xerces(JDK提供了)。所以我们称xerces是DOM、SAX解析器。

2.1 DOM解析原理

DOM要求解析器把整个XML文档装载到一个Document对象中。即使用DOM解析器解析XML文档的结果就是一个Document对象。

一个XML文档解析后对应一个Document对象,可以通过Document对象获取根元素,然后在通过根元素获取根元素的子元素…,这说明DOM解析方式保留了元素之间的结构关系(DOM树)!

l  优点:元素与元素之间的结构关系保留了下来;

l  缺点:如果XML文档过大,那么把整个XML文档装载进内存,可能会出现内存溢出的现象!

2.2 SAX解析原理

DOM解析后的结果是一个Document对象,而SAX解析没有结果!SAX要求在开始解析之前用户提供一个接口的实现对象,然后把接口实现对象传递给SAX解析器,然后在SAX解析器的过程中不调用实现对象的方法。

l  DOM是解析时把数据放到了Document对象中,然后用户从Document中获取需要的数据;

l  SAX要求用户参与到解析过程中来,把想要做的事情写到接口实现对象中,然后SAX在解析过程中来调用接口实现对象的方法。

你看过三国么?听说过三气周瑜么?其中二气周瑜你知道么?故事情节大致如下:

倒霉的周瑜让孙权把自己的妹妹嫁给刘备,让刘备来吴国完婚!目的是把刘备软禁在吴国,或者把刘备干掉。如果刘备不同意,那么孙权就有了打刘备,抢荆州的借口了。

孔明识破了这一计,最终让刘备与赵云去吴国。但孔明给了赵云三个锦囊:

l  到了吴国南徐开第一个锦囊;

l  在吴国住到年终开第二个锦囊;

l  回家途中被吴军阻拦开第三个锦囊。

锦囊的内容是什么呢?赵云和刘备性命如何呢?诸葛亮又是如何二气周瑜的呢?这里没有了,自己去买本《三国演义》看吧!

其中赵云就是SAX解析器,赵负责去吴国,SAX负责解析XML;

其中孔明的三个锦囊就是接口实现中的三个方法;

赵云会在特定时刻打开锦囊,依计而行,SAX解析器会在解析过程中特定时刻调用接口实现中的某一方法。

取亲之旅 ßà 被解析的XML

赵云 ßà SAX解析器

锦囊 ßà接口在三个方法(由我们完成)

赵云在取亲之旅中,会在发生特定事件时,执行特定的锦囊。例如在到达吴国南徐时,执行第一个锦囊上的妙计。

SAX解析器会在解析XML文档的过程中,在发生特定事件时,调用接口中特定的方法。例如在SAX解析到某个元素的开始标签时,输出元素名称!其中解析到开始标签就是特定的事件,而输出元素名称,就是接口中方法的实现。

接口中方法如下:

public void startDocument()[崔1] ;

public void endDocument()[崔2] ;

public void startElement(String uri, String localName, String qName,

Attributes atts)[崔3] ;

public void endElement(String uri, String localName, String qName)[崔4]

public void characters(char[] ch, int start, int length)[崔5] ;

public void ignorableWhitespace(char[] ch, int start, int length)[崔6] ;

public void processingInstruction(String target, String data)[崔7] ;

  接口的实现由我们来完成,然后我们需要把接口实现类对象“交给”SAX解析器,然后让SAX开始解析。SAX会在特定事件发生时,调用接口中的方法,完成我们交给它的任务。

l  优点:适合解析大XML文件(内存空间占用小),因为是解析一行处理一行,处理完了就不需要在保留数据了;

l  缺点:因为是解析一行处理一行,解析之后数据就丢失了,所以元素与元素之间的结构关系没有保留下来。

JAXP介绍(不重要)

我们知道有很多像xerces一样的解析器,都对DOM和SAX提供了实现,那么如果我们在项目中一开始使用了解析A,然后因为某些原因想更换成解析B,那么就需要修改项目。

JAXP(Java API for XML Processing)是由Java提供的,JAXP是对所有像xerces一样的解析的提供统一接口的API。

当我们使用JAXP完成解析工作时,还需要为JAXP指定xerces或其他解析器,当需要更换解析器时,无需修改代码,只需要修改配置即可。

  JAXP不是解析器,但使用它可以方便的切换解析器。所以在我们的程序中只会使用JAXP,而不会直接使用Xeces。

JDOM和DOM4j介绍

DOM和SAX是跨语言的XML解析准备,在Java中使用并不方便。而JDOM和DOM4j是专门为Java语言提供的解析工具!使用起来很方便,所以真实开发中使用JDOM或DOM4J比较多。

又因为DOM4J与JDOM比较结果为DOM4j完胜,所以我们这里只会对DOM4j介绍,而不会介绍JDOM。

2.DOM和SAX解析

1 DOM结构模型

DOM中的核心概念就是节点,在XML文档中的元素、属性、文本、处理指令,在DOM中都是节点!

2 JAXP之DOM解析

使用DOM解析XML的目标就是获取到Document对象,然后在从Document中获取到需要的数据。Document对象就是XML文档在内存中的样子。

  1. 获取Document三步:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();[崔8]

DocumentBuilder builder = factory.newDocumentBuilder();[崔9]

Document document = builder.parse(new File("students.xml"));[崔10]

  1. 遍历Document:

@Test

public void fun1() throws SAXException, IOException, ParserConfigurationException {

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = factory.newDocumentBuilder();

Document document = builder.parse(new File("src/students.xml"));

// 获取根元素

Element rootEle = document.getDocumentElement();

// 获取元素的所有子节点

NodeList nodeList = rootEle.getChildNodes();

// 循环遍历所有节点

for(int i = 0; i < nodeList.getLength(); i++) {

// 获取其中每个节点

Node node = nodeList.item(i);

// 判断节点的类型是否为元素

if(node.getNodeType() == Node.ELEMENT_NODE) {

// 强转成元素类型

Element stuEle = (Element) node;

// 获取元素的名称

String eleName = stuEle.getNodeName();

// 获取元素的number属性值

String number = stuEle.getAttribute("number");

// 获取名为name的子元素,因为返回值为NodeList,

// 所以需要使用item(0)方法获取第一个name子元素

// getTextContent()是获取节点的文本内容

String name = stuEle.getElementsByTagName("name").item(0).getTextContent();

String age = stuEle.getElementsByTagName("age").item(0).getTextContent();

String sex = stuEle.getElementsByTagName("sex").item(0).getTextContent();

System.out.println(eleName + ":[number=" + number + ", name=" + name + ", age=" + age + ", sex=" + sex + "]");

}

}

}

3 JAXP之SAX解析

使用SAX解析XML文档需要先给出DefualtHandler的子类,重写其中的方法。然后在使用SAX开始解析时把DefaultHandler子类对象传递给SAX解析器。

class MyContentHandler extends DefaultHandler {

public void startDocument() throws SAXException {

System.out.println("开始解析...");

}

public void endDocument() throws SAXException {

System.out.println("解析结束...");

}

public void startElement(String uri, String localName, String qName,

Attributes atts) throws SAXException {

System.out.println(qName [崔11] + "元素解析开始");

}

public void endElement(String uri, String localName, String qName)

throws SAXException {

System.out.println(qName [崔12] + "元素解析结束");

}

public void characters(char[] ch, int start, int length)

throws SAXException {

System.out.print(new String(ch, start, length)[崔13] .trim());

}

}

使用SAX解析首先需要获取工厂,再通过工厂获取解析器对象,然后使用解析对象完成解析工作:

SAXParserFactory factory = SAXParserFactory.newInstance();

SAXParser parser = factory.newSAXParser();

parser.parse(new File("src/students.xml"), new MyContentHandler());

3.DOM4J解析(崔老师版)

1 DOM4J概述

DOM4J是针对Java开发人员专门提供的XML文档解析规范,它不同与DOM,但与DOM相似。DOM4J针对Java开发人员而设计,所以对于Java开发人员来说,使用DOM4J要比使用DOM更加方便。

在DOM4J中,也有Node、Document、Element等接口,结构上与DOM中的接口比较相似。但它们是不同的类:

l  Node

  • Attribute:表示属性节点;
  • Branch:表示可以包含子元素的节点:

n  Document:表示整个文档;

n  Element:表示元素节点;

  • CharacterData:表示文本节点:

n  Text:表示文本内容;

n  CDATA:表示CDATA段内容;

n  Comment:表示注释内容。

  我们再次强调,DOM和DOM4J是不同的,DOM中的Document是org.w3c.Document,而DOM4J中的Document是org.dom4j.Document,它们是不同的类,其他Node、Element也是一样。

2 读取、保存、创建Document

使用dom4j需要导入:

l  dom4j.jar

l  jaxen.jar

  1. 读取

SAXReader reader = new SAXReader();

Document doc = reader.read("src/students.xml");

  1. 保存XML文档

// 创建格式化器,使用\t缩进,添加换行

OutputFormat format = new OutputFormat("\t", true);

// 清空数据中原有的换行

format.setTrimText(true);

// 创建XML输出流对象

XMLWriter writer = new XMLWriter(new FileWriter("src/a.xml"), format);

// 输出Document

writer.write(doc);

// 关闭流

writer.close();

  1. 创建Document

Document doc = DocumentHelper.createDocument();

3 遍历Document

public void fun1() throws DocumentException {

SAXReader reader = new SAXReader();

Document doc = reader.read("src/students.xml");

// 获取根元素

Element rootEle = doc.getRootElement();

// 获取根元素的所有子元素

List<Element> eleList = rootEle.elements();

// 遍历元素集合

for (Element stuEle : eleList) {

// 获取元素名称

String eleName = stuEle.getName();

// 获取元素的number属性值

String number = stuEle.attributeValue("number");

// 获取元素的name子元素内容

String name = stuEle.elementText("name");

// 获取元素的age子元素内容

String age = stuEle.elementText("age");

// 获取元素的sex子元素内容

String sex = stuEle.elementText("sex");

System.out.println(eleName + ": [number=" + number + ", name="

+ name + ", age=" + age + ", sex=" + sex + "]");

}

}

4 添加student元素

SAXReader reader = new SAXReader();

Document doc = reader.read("src/students.xml");

// 获取根元素<students>

Element root = doc.getRootElement();

// 为root添加名为student的子元素,并返回这个新添加的子元素

Element stuEle = root.addElement("student");

// 给元素添加属性number,值为123

stuEle.addAttribute("number", "123");

// 添加子元素name,并设置name子元素的文本内容为wangWu

stuEle.addElement("name").setText("wangWu");

stuEle.addElement("age").setText("30");

stuEle.addElement("sex").setText("male");

//////////////////

// 创建格式化器,使用\t缩进,添加换行

OutputFormat format = new OutputFormat("\t", true);

// 清空数据中原有的换行

format.setTrimText(true);

// 创建XML输出流对象

XMLWriter writer = new XMLWriter(new FileWriter("src/a.xml"), format);

// 输出Document

writer.write(doc);

// 关闭流

writer.close();

5 查询元素

SAXReader reader = new SAXReader();

Document doc = reader.read("src/students.xml");

/*

* selectSingNode()方法的参数是XPath

* XPath是在XML文档中查找的一门表达式语言

* “//”表示查找整个XML文档

* student表示查找名为student的元素

* []表示条件

* @number表示number属性

* @number='ITCAST_1001'表示条件为number属性等于ITCAST_1001

*

* selectSingNode()方法在查找到多个满足XPath的元素时,只返回第一个。

*/

Element stuEle1 = (Element)doc.selectSingleNode("//student[@number='ITCAST_1001']");

// 把元素转换成字符串

System.out.println(stuEle1.asXML());

// 查找name子元素内容为liSi的student元素

Element stuEle2 = (Element) doc.selectSingleNode("//student[name='liSi']");

System.out.println(stuEle2.asXML());

6 修改元素

SAXReader reader = new SAXReader();

Document doc = reader.read("src/students.xml");

// 查找元素

Element stuEle = (Element)doc.selectSingleNode("//student[@number='ITCAST_1001']");

// 修改student元素的name子元素内容为“张三”

stuEle.element("name").setText("张三");

//////////////////

// 创建格式化器,使用\t缩进,添加换行

OutputFormat format = new OutputFormat("\t", true);

// 清空数据中原有的换行

format.setTrimText(true);

// 创建XML输出流对象

XMLWriter writer = new XMLWriter(new FileWriter("src/a.xml"), format);

// 输出Document

writer.write(doc);

// 关闭流

writer.close();

7 删除学生元素

SAXReader reader = new SAXReader();

Document doc = reader.read("src/students.xml");

// 查找元素

Element stuEle = (Element)doc.selectSingleNode("//student[@number='ITCAST_1001']");

// 获取父元素来删除元素

stuEle.getParent().remove(stuEle);

//////////////////

// 创建格式化器,使用\t缩进,添加换行

OutputFormat format = new OutputFormat("\t", true);

// 清空数据中原有的换行

format.setTrimText(true);

// 创建XML输出流对象

XMLWriter writer = new XMLWriter(new FileWriter("src/a.xml"), format);

// 输出Document

writer.write(doc);

// 关闭流

writer.close();

8 dom4j API介绍

Node方法:

l  String asXML():把当前节点转换成字符串,如果当前Node是Document,那么就会把整个XML文档返回;

l  String getName():获取当前节点名字;Document的名字就是绑定的XML文档的路径;Element的名字就是元素名称;Attribute的名字就是属性名;

l  Document getDocument():返回当前节点所在的Document对象;

l  short getNodeType():获取当前节点的类型;

l  String getNodeTypeName():获取当前节点的类型名称,例如当前节点是Document的话,那么该方法返回Document;

l  String getStringValue():获取当前节点的子孙节点中所有文本内容连接成的字符串;

l  String getText():获取当前节点的文本内容。如果当前节点是Text等文本节点,那么本方法返回文本内容;例如当前节点是Element,那么当前节点的内容不是子元素,而是纯文本内容,那么返回文本内容,否则返回空字符串;

l  void setDocument(Document doc):给当前节点设置文档元素;

l  void setParent(Element parent):给当前节点设置父元素;

l  void setText(String text):给当前节点设置文本内容;

Branch方法:

l  void add(Element e):添加子元素;

l  void add(Node node):添加子节点;

l  void add(Comment comment):添加注释;

l  Element addElement(String eleName):通过名字添加子元素,返回值为子元素对象;

l  void clearContent():清空所有子内容;

l  List content():获取所有子内容,与获取所有子元素的区别是,<name>liSi</name>元素没有子元素,但有子内容;

l  Element elementById(String id):如果元素有名为“ID”的属性,那么可以使用这个方法来查找;

l  int indexOf(Node node):查找子节点在子节点列表中的下标位置;

l  Node node(int index):通过下标获取子节点;

l  int nodeCount():获取子节点的个数;

l  Iterator nodeIterator():获取子节点列表的迭代器对象;

l  boolean remove(Node node):移除指定子节点;

l  boolean remove(Commont commont):移除指定注释;

l  boolean remove(Element e):移除指定子元素;

l  void setContent(List content) :设置子节点内容;

Document方法:

l  Element getRootElement():获取根元素;

l  void setRootElement():设置根元素;

l  String getXmlEncoding():获取XML文档的编码;

l  void setXmlEncoding():设置XML文档的编码;

Element方法:

l  void add(Attribute attr):添加属性节点;

l  void add(CDATA cdata):添加CDATA段节点;

l  void add(Text Text):添加Text节点;

l  Element addAttribute(String name, String value):添加属性,返回值为当前元素本身;

l  Element addCDATA(String cdata):添加CDATA段节点;

l  Element addComment(String comment):添加属性节点;

l  Element addText(String text):添加Text节点;

l  void appendAttributes(Element e):把参数元素e的所有属性添加到当前元素中;

l  Attribute attribute(int index):获取指定下标位置上的属性对象;

l  Attribute attribute(String name):通过指定属性名称获取属性对象;

l  int attributeCount():获取属性个数;

l  Iterator attributeIterator():获取当前元素属性集合的迭代器;

l  List attributes():获取当前元素的属性集合;

l  String attributeValue(String name):获取当前元素指定名称的属性值;

l  Element createCopy():clone当前元素对象,但不会copy父元素。也就是说新元素没有父元素,但有子元素;

l  Element element(String name):获取当前元素第一个名称为name的子元素;

l  Iterator elementIterator():获取当前元素的子元素集合的迭代器;

l  Iterator elementIterator(String name):获取当前元素中指定名称的子元素集合的迭代器;

l  List elements():获取当前元素子元素集合;

l  List elements(String name):获取当前元素指定名称的子元素集合;

l  String elementText(String name):获取当前元素指定名称的第一个元素文件内容;

l  String elementTextTrime(String name):同上,只是去除了无用空白;

l  boolean isTextOnly():当前元素是否为纯文本内容元素;

l  boolean remove(Attribute attr):移除属性;

l  boolean remove(CDATA cdata):移除CDATA;

l  boolean remove(Text text):移除Text。

DocumentHelper静态方法介绍:

l  static Document createDocument():创建Dcoument对象;

l  static Element createElement(String name):创建指定名称的元素对象;

l  static Attribute createAttrbute(Element owner, String name, String value):创建属性对象;

l  static Text createText(String text):创建属性对象;

l  static Document parseText(String text):通过给定的字符串生成Document对象;


[崔1]开始解析时调用该方法

[崔2]结束解析时调用该方法

[崔3]遇到元素的开始标签时调用该方法

[崔4]遇到元素结束标签时调用该方法

[崔5]遇到文本内容时调用该方法

[崔6]遇到元素与元素之间的空白时调用该方法

[崔7]遇到处理指令时调用该方法

[崔8]获取工厂

[崔9]获取解析器

[崔10]解析XML文档,得到Document对象

[崔11]元素名称

[崔12]元素名称

[崔13]当前文本内容

5.Xpath

XPath实际上就是一种更快的查找XML元素的方式。详情见文档。

JavaScripts学习日记——DOM SAX JAXP DEMO4J XPath的更多相关文章

  1. JavaScripts学习日记——DOM

    DOM Document Object Model 文档对象模型  整合js和html css.控制html文档行为.DOM就是把页面当中所有内容全部封装成对象.HTML文档中万物皆对象.1.对象的分 ...

  2. JAVA与DOM解析器提高(DOM/SAX/JDOM/DOM4j/XPath) 学习笔记二

    要求 必备知识 JAVA基础知识.XML基础知识. 开发环境 MyEclipse10 资料下载 源码下载   sax.dom是两种对xml文档进行解析的方法(没有具体实现,只是接口),所以只有它们是无 ...

  3. Java解析XML汇总(DOM/SAX/JDOM/DOM4j/XPath)

    [目录] 一.[基础知识——扫盲] 二.[DOM.SAX.JDOM.DOM4j简单使用介绍] 三.[性能测试] 四.[对比] 五.[小插曲XPath] 六.[补充] 关键字:Java解析xml.解析x ...

  4. JavaScripts学习日记——BOM

    IE 3.0 和 Netscape Navigator 3.0 提供了一种特性 - BOM(浏览器对象模型),可以对浏览器窗口进行访问和操作.使用 BOM,开发者可以移动窗口.改变状态栏中的文本以及执 ...

  5. JavaScripts学习日记——ECMAscript

    1.Function对象 Function是一个很特殊的对象,特殊在该对象就像java中的方法一样,可以运行,可以传参数. 三种定义function对象的方法: 1.function fun1(a,b ...

  6. JavaScripts学习日记——XML DTD Schema

    今日关键词: XML DTD Schema 1.XML 1 XML的概述 1.1 什么是XML XML全称为Extensible Markup Language,意思是可扩展的标记语言.XML语法上和 ...

  7. XML概念定义以及如何定义xml文件编写约束条件java解析xml DTD XML Schema JAXP java xml解析 dom4j 解析 xpath dom sax

    本文主要涉及:xml概念描述,xml的约束文件,dtd,xsd文件的定义使用,如何在xml中引用xsd文件,如何使用java解析xml,解析xml方式dom sax,dom4j解析xml文件 XML来 ...

  8. SAX,DOM,JAXP,JDOM,DOM4J比较

    dom,sax,jdom,dom4j的技术特点: 1: DOMDOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准.DOM 是以层次结构组织的节点或信息片断的集合.这个层次结构允许 ...

  9. java解析xml的方式DOM,SAX,DOM4J,JDOM,StAX

    1)DOM(JAXP Crimson解析器)DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找 特定信息. ...

随机推荐

  1. 关于Adobe Flash 11.3 引起的火狐使用问题

    Adobe Flash 更新到11.3之后,为火狐引入Flash沙盒安全模式,但同时,又造成了部分兼容性问题,导致 Windows vista及 Windows 7上部分火狐崩溃,并致使一些使用Fla ...

  2. Delphi 做ActiveX的详细过程

    1.新建 如下图 点击OK 依然点击OK 出现了如上图的节面,就像窗体一样. 然后 你就想干什么干什么. 这个做好之后, 这个是我设计的窗体. 然后 就添加 外部可以调用的接口了. 如果你不想让外部调 ...

  3. 你好,C++(30)“大事化小,小事化了”5.4.3 工资程序成长记:函数

    5.4.3 工资程序成长记:函数 自从上次小陈“程序员”的工资程序得到老板的夸奖,口头许诺给他涨工资以后,老板再也没有找过他,涨工资的事自然也就没有下文了.这天,老板又突然召他去办公室.这下可把小陈高 ...

  4. dede 日期的所有格式

    [field:pubdate function=strftime('%d',@me)/] 日 [field:pubdate function=strftime('%d日',@me)/] - [fiel ...

  5. Linux(CentOS)搭建SVN服务器全攻略

    虽然在windows上搭建SVN很简单,但是效能却不高,这当然是和linux相比了.然而在linux上搭建SVN却非常繁琐,所以今天这篇文章就来一步一步教您如何在Centos上搭建SVN 安装#yum ...

  6. HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用 php

    参考来源:http://qq398705749.iteye.com/blog/963818 php中HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用 1.REMOTE_ADD ...

  7. SQLServer备忘

        1,创建主键有三种方式,尤其注意联合主键: (1) (2) (3)   2,修改主键的方式       2,创建外键应该也有三种方式:

  8. Android隐藏标题栏

    打开程序,在onCreate()方法中添加如下代码: protected void onCreate(Bundle savedInstanceState) { super.onCreate(saved ...

  9. ~/.bashrc的常用alias设置

    centos6.5系统中,alias定义在/etc/bashrc,分别写在/etc/profile.d/*.sh中,可以在此目录添加my.sh, alias attrib='chmod'alias c ...

  10. 【转】 Android ListView与Button的显示----不错不错

    原文网址:http://blog.csdn.net/zy987654zy/article/details/39225819 在开发中有时候会碰见一些很简单的问题,但是当初没想通的时候 死都搞不定. 我 ...