package com.mipo.xml.demo1;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jdom2.JDOMException;
import org.w3c.dom.DOMException;
import org.xml.sax.SAXException;
public class Foo {
//注意路径
private static InputStream resource = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/mipo/xml/demo1/Book.xml");
public static void main(String[] args) {
// TODO Auto-generated method stub
readWithDOM();
writeWithDOM();
}
//SAX解析XML文档*************************************************************
/*
* 用于读取和 操作XML文件的标准是文档对象模型DOM。缺点:低效的、缓慢的,消耗资源。
* 一种替代技术就是SAX,即Simple API for XML。SAX允许您在读取文档是操作它,而不必等待整个文档被存储后才采取操作。
*
* SAX是一个基于事件的 API。
* 解析器向一个事件处理程序发送事件,比如元素开始和元素结束,而事件处理器则处理该信息。
* 应用程序本身就能够处理该数据。
* 原始的文档仍然保留完好无损
*
*
* SAX 处理涉及以下步骤:
* 1、 创建一个事件处理程序。
* 2、创建 SAX 解析器。
* 3、 向解析器分配事件处理程序。
* 4、 解析文档,同时向事件
* 5、处理程序发送每个事件
*
* SAX优点:可以解析任意大小的文件;
* 适合创建自己的数据结构;
* 适合小信息子集;
* 简单、快速;
* 缺点:不能对文档做随机存取;
* 难以实现复杂的查询;
* 不能使用文档类型定义(DTD);
* 不可获取词法信息;
* SAX是只读的;
* 当前的浏览器不支持SAX;
*
*
* SAX的核心基于两个接口:
* XMLReader接口:表示分析
* 分析过程就是读取XML文档并向客户应用程序报告其内容,同时检查文档的形式合理性。
* SAX将分析器表示为XMLReader接口的实例。
* 分析器是读取文档,并在发现形式合理性错误时抛出异常。
* XMLReader读取到对应的内容后就会调用ContentHandler接口中对应的方法。
*
* ContentHandler接口:从分析器接收数据。
* 在ContentHandler接口中定义了11个方法,这些方法都是在分析器(即 XMLReader)读取文档时被回调的,且这个类必须被客户应用程序实现。
*
*
*
* 选择DOM还是SAX,取决以下因素:
* 1、DOM写XML文件更方便,SAX读XML文件更方便
* 2、对于容量比较大的文件,选择SAX
* 3、如果只有数据中的少量部分会被使用,使用SAX将该部分数据提取到应用程序中更好。
* 4、SAX实现速度通常比DOM实现速度更快。
*
*
*/
private static void readWithSAX() {
try {
//创建SAX解析器工厂实例
SAXParserFactory saxPF = SAXParserFactory.newInstance();
//根据SAX解析器工厂实例创建SAX解析器
SAXParser saxP = saxPF.newSAXParser();
//创建DefaultHandler文档处理程序,解析XML文件
saxP.parse(resource, new org.xml.sax.helpers.DefaultHandler(){
/*
* 文档事件
* 分析器开始分析新文档后,在调用ContentHandler任何方法之前,立即调用startDocument()方法。
* 在文档分析完毕后调用endDocument()方法,并且不在对这个文档报告任何内容。
* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startDocument()
*/
@Override
public void startDocument() throws SAXException {
super.startDocument();
System.out.println("###############startDocument()");
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("###############endDocument()");
}
/*
* 元素事件
* 当分析器遇到开始标志时,立即调用startElement()方法
* 当分析器遇到结束标志时调用endElement()方法。
* 如果遇到空元素标志时,调用startElement()和endElement()方法。
* 如果开始标志和结束标志不符,则分析器抛出SAXParseException.
* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
*/
@Override
public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
System.out.println("节点名:"+qName);
for (int i=0; i<attributes.getLength(); i++) {
System.out.println("属性:"+attributes.getValue(i));
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
}
/*
* 字符数据
* 分析器读取#PCDATA时,将这个文本以字符数组传递给characters()方法
*
* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
*/
@Override
public void characters(char[]ch ,int start, int length) throws SAXException {
super.characters(ch, start, length);
System.out.println("节点内容:"+new String(ch,start,length));
}
@Override
public void skippedEntity(String name) throws SAXException {
super.skippedEntity(name);
}
});
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//SAX生成XML文件
public void writeWithSAX() {
try {
SAXTransformerFactory saxTF = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
TransformerHandler th = saxTF.newTransformerHandler();;
th.setResult(new StreamResult(new File("src/com/mipo/xml/demo1/Book.xml")));
Transformer transformer = th.getTransformer();
transformer.setOutputProperty(OutputKeys.VERSION, "1.0");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
th.startDocument();
th.startElement("", "", "cars", null);
th.startElement("", "", "car", null);
th.startElement("", "", "name", null);
String text = "Audi";
th.characters(text.toCharArray(), 0, text.length());
th.endElement("", "", "name");
th.startElement("", "", "price",null);
String text1 ="480000";
th.characters(text1.toCharArray(), 0, text1.length());
th.endElement("", "", "price");
th.endElement("", "", "car");
th.endElement("", "", "cars");
th.endDocument();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//DOM解析XML文件*************************************************************
/*
* DOM即Document Object Model,也即文档对象模型。
* 基于DOM的XML解析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对对象模型的操作,实现对XML文档数据的操作。
* 通过DOM接口,应用程序可以在任何时候访问XML文档中任何一部分。
* 在DOM接口规范中,有四个基本的接口:Document,Node,NodeList,以及NamedNodeMap
*
* Document接口有两个作用:
* 1、表示XML文档本身和提供对内容、文档类型声明和其他属性的访问
* 2、它是个抽象工厂,负责生成文档中的节点:元素、文本、属性等等
* DOM是读写API,不仅可以通过分析文本文件生成DOM文档,也可以在内存中从头开始生成新的文档。
* 1、生成新Document对象的抽象工厂接口是DOMImplementation.
* 2、通过节点的ownerDocument属性,用来表明当前节点是由谁所创建的以及节点同Document之间的联系
*
* 在DOM树中,Node接口代表了树中一个节点。
* Node大致可以分为5个部分:
* 1、节点类型常量
* 2、设置与读取节点属性的方法
* 3、导航DOM树的方法
* 4、增加与删除子节点的方法
* 5、几个实用程序方法
*
* DOM用NodeList对象存放节点的子节点列表。Node接口的getChildNodes()方法返回该接口的实例。
* 实现了NamedNodeMap接口的对象中,包含了可以通过名字来访问的一组节点的集合。
* NamedNodeMap并不是从NodeList继承过来的,它所包含的节点集 中 的节点是无序的。
* NamedNodeMap表示的是一组节点和其唯一名字的一一对应关系,这个接口主要用在属性节点的表示上。
*
* Element接口是XML文档中最重要的,定义XML文档结构的是元素,而不是其他组件。
* Element接口包含了很多对元素进行操作的方法。
*
*
* 为了使用XML文件信息,必须解析文件以获得Document对象。
* Document对象是一个接口,因而不能将它直接实例化;一般情况下,应用程序会会相应使用一个工厂(工厂模式)
*
*
* Java的DOM 2 实现允许通过以下方法控制解析器的参数:
* setCoalescing():决定解析器是否要将 CDATA 节点转换为文本,以及是否 要和周围的文本节点合并。其默认值为 false。
* setExpandEntityReferences(): 确定是否要展开外部实体引用。如果为 true,外部数据将插入文档。其默认值为 true。
* setIgnoringComments():确定是否要忽略文件中的注释。其默认值为 false。
* setIgnoringElementContentWhitespace():确定是否要忽略元素内容中的空白。其默认值为 false。
* setNamespaceAware():确定解析器是否要注意名称空间信息。其默认值为 false。
* setValidating():默认情况下,解析器不验证文档。将这个参数设置为 true 可打开验证功能。
*
*
*/
private static void readWithDOM() {
try {
//创建 DocumentBuilderFactory(解析对象工厂);DocumentBuilderFactory 对象创建 DocumentBuilder
DocumentBuilderFactory docBF = DocumentBuilderFactory.newInstance();
//创建 DocumentBuilder(文档解析器对象);DocumentBuilder 执行实际的解析以创建 Document 对象
DocumentBuilder docB = docBF.newDocumentBuilder();
//解析文件以创建 Document 对象
org.w3c.dom.Document doc = docB.parse(resource);
//获得该文档对象的根元素
org.w3c.dom.Element rootElement = doc.getDocumentElement();
//获取节点名称
System.out.println("根节点名:"+rootElement.getNodeName());
//获取节点的孩子。一旦应用程序获得了根元素,它就把根元素的孩子的列表作为一个NodeList来检索
org.w3c.dom.NodeList nodes = rootElement.getChildNodes();
//遍历根节点下的孩子
for(int i=0; i<nodes.getLength(); i++) {
org.w3c.dom.Node bookNode = nodes.item(i);
//如果为空白文本节点,就跳过(元素节点,属性节点,文本节点,文档节点)
if(org.w3c.dom.Node.TEXT_NODE == bookNode.getNodeType()) {
continue;
}
System.out.println("子节点:"+bookNode.getNodeName());
//获取子节点的孩子
org.w3c.dom.NodeList records = bookNode.getChildNodes();
for(int j=0; j<records.getLength(); j++) {
org.w3c.dom.Node record = records.item(j);
//如果为空白文本节点就跳过
if(org.w3c.dom.Node.TEXT_NODE == record.getNodeType()) {
continue;
}
//获得节点的第一个孩子,并获得其文本内容值
System.out.println(record.getNodeName()+":"+record.getFirstChild().getNodeValue());
//获得节点的属性
org.w3c.dom.NamedNodeMap attributes = record.getAttributes();
if(null !=attributes && attributes.getLength()>0) {
for(int k=0; k<attributes.getLength(); k++) {
org.w3c.dom.Node attr = attributes.item(k);
//获取属性名及属性文本内容值
System.out.println(attr.getNodeName()+"::"+attr.getNodeValue() );
}
}
}
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//DOM生成XML文件**************************************************************
private static void writeWithDOM() {
try {
DocumentBuilderFactory docBF = DocumentBuilderFactory.newInstance();
DocumentBuilder docB = docBF.newDocumentBuilder();
org.w3c.dom.Document doc = docB.newDocument();
org.w3c.dom.Element rootElement = doc.createElement("students");
org.w3c.dom.Element subElement = doc.createElement("student");
org.w3c.dom.Element nameElement = doc.createElement("name");
nameElement.setTextContent("鸣人");
nameElement.setAttribute("sex", "男");
subElement.appendChild(nameElement);
org.w3c.dom.Element classElement = doc.createElement("class");
classElement.setTextContent("三年级七班");
subElement.appendChild(classElement);
org.w3c.dom.Element idElement = doc.createElement("id");
idElement.setTextContent("20050307003");
subElement.appendChild(idElement);
org.w3c.dom.Element subElement1 = doc.createElement("student");
org.w3c.dom.Element nameElement1 = doc.createElement("name");
nameElement1.setTextContent("佐助");
nameElement1.setAttribute("sex", "男");
subElement1.appendChild(nameElement1);
org.w3c.dom.Element classElement1 = doc.createElement("class");
classElement1.setTextContent("三年级七班");
subElement1.appendChild(classElement1);
org.w3c.dom.Element idElement1 = doc.createElement("id");
idElement1.setTextContent("20050307001");
subElement1.appendChild(idElement1);
rootElement.appendChild(subElement);
rootElement.appendChild(subElement1);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
//注意路径,相对路径
File file = new File("src/com/mipo/xml/demo1/studentDemo.xml");
trans.transform(new DOMSource(rootElement),new StreamResult(file));
} catch (DOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//JDOM解析XML文件
/*
* JDOM是java document object model的简称,JDOM兼顾了DOM和SAX的优点,它会提供适配器用来选择具体的XML解析器。
* JDOM是一个源代码开发的项目,它基于树型结构,利用纯Java的技术对XML文件实现解析、生成、序列化以及多种操作。
*
* 在JDOM中,XML元素就是ELement的实例,XML属性就是Attribute的实例,XML文档本身就是Document的实例。
* 因此创建JDOM对象就如同在Java语言中使用new操作符一样简单。
*
* JDOM与DOM相比,主要有一下两个优势:
* 1、JDOM仅使用具体类而不使用接口,这就在某些方面简化了API,同时也限制了其灵活性。
* 2、API使用了很多Collection类,使得熟悉这些类的Java开发人员使用起来得心应手。
*
*
* JDOM是由一下几个包组成的:
* org.jdom.* : 包含了所有的xml文档要素的java类
* org.jdom.adapters.*:包含了与dom适配的java类
* org.jdom.filter.*:包含了xml文档的过滤器类
* org.jdom.input.*:包含了读取xml文档的类
* org.jdom.output.* :包含了写入xml文档的类
* org.jdom.transform.*:包含了将jdom xml文档接口转换为其他xml文档接口
* org.jdom.xpath.*:包含了对xml文档xpath操作的类
*
*
*
*
*/
private static void readWithJDOM () {
try {
org.jdom2.input.SAXBuilder sb = new org.jdom2.input.SAXBuilder();
org.jdom2.Document doc = sb.build(resource);
org.jdom2.Element rootElement = doc.getRootElement();
System.out.println("根节点:"+rootElement.getName());
List<org.jdom2.Element> nodes = rootElement.getChildren();
for(org.jdom2.Element element:nodes) {
System.out.println("节点::"+element.getName());
for(org.jdom2.Element item:element.getChildren()) {
System.out.println(item.getName()+"::"+item.getValue());
}
}
} catch (JDOMException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//JDOM生成XML文件
/*
* 通过JDOM创建XML文件:
*
* 1、创建根元素
* 2、根据根元素创建文档
* 3、给根元素添加属性
* 4、添加元素或子元素
* 5、删除元素
* 6、将JDOM对象转换为xml文件
*
*/
private static void writeWithJDOM() {
//创建根元素
org.jdom2.Element rootElement = new org.jdom2.Element("phones");
//根据根元素创建文档
org.jdom2.Document doc = new org.jdom2.Document(rootElement);
//创建元素phone
org.jdom2.Element phone = new org.jdom2.Element("phone");
//给元素phone添加子元素name,并设置文本值
phone.addContent(new org.jdom2.Element("name").setText("iphone 7"));
//给元素phone添加子元素price,并设置文本值及属性值
phone.addContent(new org.jdom2.Element("price").setText("6888").setAttribute("type","CNY"));
//将元素phone添加到根元素中
rootElement.addContent("phone");
//org.jdom.output.XMLOutputter类负责将JDOM对象以流的形式输出。
org.jdom2.output.XMLOutputter xmlOutputter = new org.jdom2.output.XMLOutputter();
try {
//将JDOM中内容输出到指定外部文档中
xmlOutputter.output(doc, new FileWriter(new File("/XML编程/src/com/mipo/xml/demo1/Phone.xml")));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//dom4j解析XML文档
private static void readWithDom4j() {
SAXReader sr = new SAXReader();
try {
org.dom4j.Document doc = sr.read(resource);
org.dom4j.Element rootElement = doc.getRootElement();
System.out.println("根节点:"+rootElement.getName());
List nodes = rootElement.elements();
for(int i=0; i<nodes.size(); i++) {
org.dom4j.Element bookElement = (org.dom4j.Element)nodes.get(i);
List records = bookElement.elements();
for(int j=0; j<records.size(); j++) {
org.dom4j.Element item = (org.dom4j.Element)records.get(j);
System.out.println(item.getName()+"::"+item.getText());
}
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//dom4j生成XML文档
private static void writeWithDom4j() {
org.dom4j.Document doc = DocumentHelper.createDocument();
org.dom4j.Element rootElement = doc.addElement("persons");
org.dom4j.Element personElement = rootElement.addElement("person");
org.dom4j.Element nameElement = personElement.addElement("name");
nameElement.addText("苏轼");
nameElement.addAttribute("sex","男");
org.dom4j.Element productionElement = nameElement.addElement("production");
productionElement.addText("一蓑烟雨任平生");
try {
XMLWriter xmlWriter = new XMLWriter(new FileWriter(new File("/XML编程/src/com/mipo/xml/demo1/Book.xml")));
xmlWriter.write(doc);
xmlWriter.flush();
xmlWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}