组团学

XML解析

阅读 (474127)

一、XML解析技术概述

1.1、xml解析方式

XML解析方式分为两种:DOM方式和SAX方式
DOM:Document Object Model,文档对象模型。这种方式是W3C推荐的处理XML的一种方式。
SAX:Simple API for XML。这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。

image20200224111350283.png

1.2、XML解析开发技术包

JAXP:是SUN公司推出的解析标准实现。
Dom4J:是开源组织推出的解析开发包。(牛,大家都在用,包括SUN公司的一些技术的实现都在用)
JDom:是开源组织推出的解析开发包。

二、JAXP解析开发包简介

JAXP:(Java API for XML Processing)开发包是JavaSE的一部分,它由以下几个包及其子包组成:
org.w3c.dom:提供DOM方式解析XML的标准接口
org.xml.sax:提供SAX方式解析XML的标准接口
javax.xml:提供了解析XML文档的类

javax.xml.parsers包中,定义了几个工厂类。我们可以通过调用这些工厂类,得到对XML文档进行解析的DOM和SAX解析器对象
DocumentBuilderFactory
SAXParserFactory

使用JAXP进行DOM解析

javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。

获得JAXP中的DOM解析器

  • 调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。

  • 调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。

  • 调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了。

常用方法:

  • getElementsByTagName(String tagname) :根据标签名称得到标签,返回NodeList
  • createElement(String tagName) :创建标签
  • createTextNode(String data) :创建文本
  • appendChild(Node newChild) : 把文本添加到标签下面

Document是一个接口,父接口是Node

三、DOM编程

DOM方式解析XML文件

DOM解析编程

代码示例

person1.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?> <person> <p1> <name>zhangsan</name> <age>20</age> </p1> <p1> <name>lisi</name> <age>30</age> </p1> </person>

3.1、实现查找所有name元素的内容

public static void getNameText() throws Exception { /* * 1、创建一个解析器工厂 * 2、根据这个解析器工厂来创建解析器 * 3、解析xml * * 4、获取到name元素 getElementsByTagName(String tagname) * 5、获取元素具体的文本内容 getTextContent() * */ //创建解析器工厂 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); //创建解析器 DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder(); //解析xml Document document = documentBuilder.parse("src/person1.xml"); //获取name标签 NodeList list = document.getElementsByTagName("name"); //遍历nodelist for(int i=0;i<list.getLength();i++) { Node node = list.item(i); String s = node.getTextContent(); System.out.println("content: "+s); } }

3.2、查询第一个name元素里面的值

public static void getFirstName() throws Exception { /* * 1、创建解析器工厂 * 2、创建解析器 * 3、解析xml 通过parse * * 4、获取所有的name元素 * 5、直接获取第一个元素 * */ //创建解析器工厂 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); //创建解析器 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); //解析xml Document document = documentBuilder.parse("src/person1.xml"); //直接获取到第一个name元素 Node node1 = document.getElementsByTagName("name").item(1); //获取name元素里面的值 String s = node1.getTextContent(); System.out.println("first name: "+s); }

3.3、实现在第一个p1下面添加 nv

public static void addSex() throws Exception { /* * 1、创建解析器工厂 * 2、根据解析器工厂,创建解析器 * 3、使用parse方法解析xml * * 4、获取到第一个p1元素 * 5、创建sex元素 使用createElement方法创建元素 * 6、创建文本 nv 使用createTextNode方法创建文本 * 7、把文本添加到sex元素下面 使用appendChild添加 * * 8、把sex元素添加到第一个p1下面 使用appendChild添加 * * 9、回写xml * * */ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse("src/person1.xml"); //获取到第一个p1元素 Node p1 = document.getElementsByTagName("p1").item(0); //创建sex元素 Element sex1 = document.createElement("sex"); //创建文本 Text nv = document.createTextNode("nv"); //添加 sex1.appendChild(nv); //在p1下面添加sex p1.appendChild(sex1); //实现回写xml TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult("src/person1.xml")); }

更新XML文档(Transformer)

javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出,例如把xml文件应用样式表后转成一个html文档。利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中。

Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:
javax.xml.transform.dom.DOMSource类来关联要转换的document对象,
用javax.xml.transform.stream.StreamResult 对象来表示数据的目的地。

Transformer对象通过TransformerFactory获得。

3.4、实现修改sex值成nan

public static void modifySex() throws Exception { /* * 1、创建解析器工厂 * 2、根据解析器工厂,创建解析器 * 3、使用parse方法解析xml * * 4、获取到sex元素 * 5、实现修改 * 6、回写xml * */ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse("src/person1.xml"); //获取到sex元素 Node sex = document.getElementsByTagName("sex").item(0); //实现修改 sex.setTextContent("nan"); //回写xml TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult("src/person1.xml")); }

3.5、实现删除第二个p1元素下面的age元素

public static void delAge() throws Exception { /* * 1、创建解析器工厂 * 2、根据解析器工厂,创建解析器 * 3、使用parse方法解析xml * * 4、获取到第二个p1元素下面的age item(1) * 5、获取p1元素 * 6、执行删除操作 * 7、回写xml * * */ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse("src/person1.xml"); //获取要删除的age Node age2 = document.getElementsByTagName("age").item(1); //获取p1 //第一种方式 Node p1 = document.getElementsByTagName("p1").item(1); //第二种方式 // age2.getParentNode(); //执行删除操作 p1.removeChild(age2); //回写xml TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.transform(new DOMSource(document), new StreamResult("src/person1.xml")); }

3.6、实现把xml中所有的标签名称显示出来

public static void listXml() throws Exception { /* * 1、创建解析器工厂 * 2、根据解析器工厂,创建解析器 * 3、使用parse方法解析xml * * 4、使用getChildNodes()获取元素下面的子元素 * 5、使用递归操作 * * */ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse("src/person1.xml"); //写一个方法实现查找所有的标签 list1(document); } //实现递归查找元素名称 private static void list1(Node node) { //使用node.getNodeType()判断类型是元素类型,输出 //使用Node里面的ELEMENT_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 n1 = list.item(i); //使用递归 list1(n1); } }

四、SAX解析

概述

在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。

SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

SAX的事件处理方式解析XML文件

SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器

解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。

解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。

事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。

4.1、SAX解析原理

  • SAX 是事件驱动的 XML 处理方法
  • 它是基于事件驱动的
  • startElement() 回调在每次 SAX 解析器遇到元素的起始标记时被调用
  • characters() 回调为字符数据所调用
  • endElement() 为元素的结束标记所调用
  • DefaultHandler类(在 org.xml.sax.helpers 软件包中)来实现所有这些回调,并提供所有回调方法默认的空实现

4.2、SAX的事件驱动模型

image20200225161912500.png

4.3、SAX DocumentHandler示例

SAX 解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件

发生相应事件时,将调用一个回调方法

image20200224102726771.png

4.4、使用SAX方式解析XML

使用SAXParserFactory创建SAX解析工厂

​ SAXParserFactory spf = SAXParserFactory.newInstance();

通过SAX解析工厂得到解析器对象

​ SAXParser sp = spf.newSAXParser();

通过解析器对象解析xml文件

​ sp .parse("book.xml“,new XMLContentHandler());

这里的XMLContentHandler 继承 DefaultHandler

4.5、SAX代码例子

打印整个xml文档的内容

public class TestSax { public static void main(String[] args) throws Exception { //创建解析器工厂 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); //创建解析器 SAXParser saxParser = saxParserFactory.newSAXParser(); //执行parse方法 saxParser.parse("person.xml", new MyDefaultHandler()); } } class MyDefaultHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException { System.out.print("<"+qName+">"); } @Override public void characters(char[] ch, int start, int length) throws SAXException { System.out.print(new String(ch,start,length)); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.print("</ "+qName+">"); } }

获取所有的name的值

public class TestSax { public static void main(String[] args) throws Exception { //创建解析器工厂 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); //创建解析器 SAXParser saxParser = saxParserFactory.newSAXParser(); //执行parse方法 saxParser.parse("person.xml", new MyDefaultHandler1()); } } class MyDefaultHandler1 extends DefaultHandler { boolean flag = false; @Override public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException { if("name".equals(qName)) { flag = true; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if(flag == true) { System.out.println(new String(ch,start,length)); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("name".equals(qName)) { flag = false; } } }

五、DOM4J解析XML文档

5.1、概述

  • Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。

  • Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。

  • 使用Dom4j开发,需下载dom4j相应的jar文件。

  • JAXM(Java API for XML Messaging简称JAXM)是为Java平台上的应用程序定义的API,用以通过XML(以及SOAP)发送和接收消息,支持同步消息和异步消息。

5.2、Document对象

DOM4j中,获得Document对象的方式有三种:

1.读取XML文件,获得document对象
SAXReader reader = new SAXReader();
Document document = reader.read(new File(“input.xml”));

2.解析XML形式的文本,得到document对象
String text = “”;
Document document = DocumentHelper.parseText(text);

3.主动创建document对象.
Document document = DocumentHelper.createDocument();
//创建根节点
Element root = document.addElement(“members”);

5.3、节点对象(获取节点)

1.获取文档的根节点.
Element root =document.getRootElement();
2.取得某个节点的子节点.
List list = root.elements(“a”);
Element book2 = (Element)list.get(1);

Element element=node.element(“书名");

3.取得节点的文字
String text=node.getText();

5.4、节点对象(添加节点)

在age节点下添加age节点
Element age = a2.addElement(“age”);
设置文本内容
age.setText(“400”);
将文档写入XML文件
XMLWriter writer = new XMLWriter(new FileOutputStream(“src/4.xml”)
writer.write(document);
writer.close();

5.5、节点对象(在特定位置添加节点)

使用DocumentHelper
//获取a下面节点
List list = book.elements();
//创建文本和cc标签
Element cc = DocumentHelper.createElement(“cc”);
cc.setText(“测试”);
//在特定位置添加:第一个参数表示元素位置,第二个参数表示添加的元素在第一个参数表示元素之前
list.add(1, cc);

5.6、节点对象(修改、删除节点)

//获取a节点
Element a2 = (Element)root.elements(“a”).get(1);
//获取第二个a下的name
Element name2 = a2.element(“name”);
//修改name值
name2.setText(“东方不败”);
//删除节点
age2.getParent().remove(age2);

5.7、节点对象属性

获取属性值
Element a1 = (Element)root.elements(“a”).get(0);

String aa = a1.attributeValue(“aa”);

设置某节点的属性和文字.
newMemberElm.addAttribute(“name”, “sitinspring”);

设置属性的文字
Attribute attribute=root.attribute(“name”);
attribute.setText(“sitinspring”);

5.8、将文档写入XML文件

1.文档中全为英文,不设置编码,直接写入的形式

XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(“src/persons.xml”));

writer.write(document);

writer.close();

2.文档中含有中文,设置编码格式写入的形式;设置回写xml格式化方式

//设置格式化方式

OutputFormat format = OutputFormat.createPrettyPrint();
// 指定XML编码

format.setEncoding(“utf-8");

XMLWriter writer = new XMLWriter(newFileWriter(“output.xml”),format);
writer.write(document);
writer.close();

5.9、案例

使用前一定要导包

image20200226143545709.png

使用dom4j查询name元素里面的内容

public static void selectNode1() throws Exception { /* * 1、获取dom4j的解析器 * 2、执行read方法,返回document * 3、获取到name * * 获取到根节点 getRootElement * * 获取到第一个p1元素 * - element(QName qName) :获取某一个元素(第一个) * - elements(QName qName) :获取所有元素 name * - elements() :获取p1下面的所有元素 * 4、获取name里面的内容 * getText(); * */ //获取dom4j的解析器 SAXReader saxReader = new SAXReader(); //获取document Document document = saxReader.read("src/person.xml"); //获取到根节点 Element root = document.getRootElement(); //获取第一个p1 Element p1 = root.element("p1"); //获取p1下面的元素 // Element name = p1.element("name"); //获取name里面的内容 // String s = name.getText(); // System.out.println(s); //<name>东方不败</name> // <age>30</age> List<Element> list = p1.elements(); for (Element e1 : list) { String s = e1.getText(); System.out.println(s); } }

获取xml中所有name值

public static void getNames() throws Exception { /* * 1、获取dom4j的解析器 * 2、执行read方法,返回document * 3、获取根节点 * * 4、获取所有的p1 * 5、循环p1的list * 6、获取name内容 * */ SAXReader saxReader = new SAXReader(); Document document = saxReader.read("src/person.xml"); Element root = document.getRootElement(); //获取所有p1 List<Element> list = root.elements("p1"); //循环p1的list for (Element p1 : list) { //每次得到的p1,获取p1下面的name Element name1 = p1.element("name"); String s = name1.getText(); System.out.println("name: "+s); } }

在第一个p1下面添加

public static void addSex() throws Exception { /* * 1、获取dom4j的解析器 * 2、执行read方法,返回document * 3、获取根节点 * * 4、获取到第一个p1 * 5、在第一个p1下面添加 直接使用addElement添加sex * 6、向sex里面添加内容 setText("女"); * * 7、回写xml * * */ SAXReader saxReader = new SAXReader(); Document document = saxReader.read("src/person.xml"); Element root = document.getRootElement(); //获取到第一个p1 Element p1 = root.element("p1"); //向p1下面添加sex元素 Element sex = p1.addElement("sex"); //向sex里面添加内容 sex.setText("女"); //回写操作 //格式化操作 //方式一 XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("person1.xml")); xmlWriter.write(document); //方式二 OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("person1.xml"), format); xmlWriter.write(document); //关闭 xmlWriter.close(); }

之前添加 100

public static void addId() throws Exception { /* * 1、获取dom4j的解析器 * 2、执行read方法,返回document * 3、获取根节点 * * 4、获取到第一个p1 * 5、执行添加操作 * * 得到要添加的位置 * * 创建要添加的元素 * * 在p1下面执行elements方法得到p1下面的所有元素 list * * add(int index, E element) * 6、回写xml * * */ SAXReader saxReader = new SAXReader(); Document document = saxReader.read("src/person.xml"); Element root = document.getRootElement(); //获取第一个p1 Element p1 = root.element("p1"); //获取p1下面的所有元素 List<Element> list = p1.elements(); //创建id元素 Element id1 = DocumentHelper.createElement("id"); id1.setText("100"); //在特定位置添加 list.add(3, id1); //回写xml OutputFormat format = OutputFormat.createPrettyPrint(); // OutputFormat format = OutputFormat.createCompactFormat(); // format.setEncoding("utf-8"); XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/person.xml"), format); xmlWriter.write(document); xmlWriter.close(); }

**把 修改 **

public static void modifySex() throws Exception { /* * 1、获取dom4j的解析器 * 2、执行read方法,返回document * 3、获取根节点 * * 4、获取p1 * 5、获取p1下面的sex * 6、完成修改操作 * 7、回写xml * */ SAXReader saxReader = new SAXReader(); Document document = saxReader.read("person1.xml"); //获取根节点 Element root = document.getRootElement(); //获取第一个p1 Element p1 = root.element("p1"); //获取p1下面的sex Element sex = p1.element("sex"); //修改内容 sex.setText("男"); //回写xml OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/person.xml"), format); xmlWriter.write(document); xmlWriter.close(); }

**删除第一个p1下面的100 **

public static void delId() throws Exception { /* * 1、获取dom4j的解析器 * 2、执行read方法,返回document * 3、获取根节点 * * 4、获取到第一个p1 * 5、获取p1下面的id * * 6、执行删除操作 通过父节点删除 * 7、回写xml * */ SAXReader saxReader = new SAXReader(); Document document = saxReader.read("person1.xml"); //获取根节点 Element root = document.getRootElement(); //获取第一个p1 Element p1 = root.element("p1"); //获取p1下面的id Element id1 = p1.element("id"); //先获取id元素的父元素 //另外一个获取父元素的方式 Element p_id = id1.getParent(); //执行删除操作 p_id.remove(id1); //回写xml OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/person1.xml"),format); xmlWriter.write(document); xmlWriter.close(); }

获取p1上面的id属性值

public static void getValues() throws Exception { /* * 1、获取dom4j的解析器 * 2、执行read方法,返回document * 3、获取根节点 * * 4、获取到p1 element方法 * 5、获取p1上面的属性值 attributeValue("属性名称") * * */ SAXReader saxReader = new SAXReader(); Document document = saxReader.read("person.xml"); //获取根节点 Element root = document.getRootElement(); //获取p1 Element p1 = root.element("p1"); //获取p1上面的属性 String s = p1.attributeValue("id"); System.out.println(s); }

六、Dom4J配合XPath使用

XPath概述

XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言

DOM4J对XPath的支持

在DOM4J中,Node接口中的三个方法最为常用:

List selectNodes(String xpathExpression):在当前节点中查找满足XPath表达式的所有子节点;

Node selectSingleNode(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点;

String valueOf(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点的文本内容;

案例

注意:使用前要导包

image20200227090655819.png
获取xml中所有name元素的内容

public static void getNames() throws Exception { /* * 1、获取解析器 * 2、执行read方法,返回document * * 3、使用xpath获取name元素 返回list结合 * 4、遍历list * 5、根据每次遍历出来的name元素,获取name的值 * */ //获取解析器 SAXReader saxReader = new SAXReader(); //返回document Document document = saxReader.read("src/person.xml"); //获取name元素 使用xpath : //name List<Node> list = document.selectNodes("//name"); //遍历 for (Node node : list) { //获取值 String s = node.getText(); System.out.println("name: "+s); } }

获取第一个p1下面的name的内容

public static void getFirstName() throws Exception { /* * 1、获取解析器 * 2、执行read方法,返回document * * 3、使用xpath获取第一个p1下面的name元素 //p1[@id]/name * 4、得到的name元素,获取内容 * * */ //获取解析器 SAXReader saxReader = new SAXReader(); //返回document Document document = saxReader.read("src/person.xml"); //使用xpath 获取第一个p1下面的name元素 Node name1 = document.selectSingleNode("//p1[@id]/name"); //获取name元素的值 String s = name1.getText(); System.out.println("name1: "+s); }
需要 登录 才可以提问哦