Java中的xml解析 - pingdongyi/blog-2 GitHub Wiki
DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。
【优点】
- 允许应用程序对数据和结构做出更改。
- 访问是双向的,可以在任何时候在树中上下导航,获取和操作任意部分的数据。
【缺点】
- 通常需要加载整个XML文档来构造层次结构,消耗资源大。
/**
DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。
【优点】
①允许应用程序对数据和结构做出更改。
②访问是双向的,可以在任何时候在树中上下导航,获取和操作任意部分的数据。
【缺点】
①通常需要加载整个XML文档来构造层次结构,消耗资源大。* Created by bing on 2017/1/4.
*/
public class DOMXML {
public static void main(String[] args) throws Exception{
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse(new File("src/main/java/com/ibingbo/xml/books.xml"));
//get root element
Element rootElement = document.getDocumentElement();
// NodeList children = rootElement.getChildNodes();
// for (int i=0;i<children.getLength();i++) {
// Node node = children.item(i);
// if (node.getNodeType() == Node.ELEMENT_NODE) {
// Element child = (Element) node;
// System.out.println(child.getTagName());
// System.out.println(" id: "+child.getAttribute("id"));
// if (child.hasChildNodes()) {
// NodeList nodes=child.getChildNodes();
// for (int j=0;j<nodes.getLength();j++) {
// Node node1 = nodes.item(j);
// if (node1.getNodeType() == Node.ELEMENT_NODE) {
// Element element = (Element)node1;
// System.out.println(" "+element.getTagName() + ": "+element.getTextContent());
// }
// }
// }
// }
//
// }
parse(rootElement);
}
private static void parse(Element root) {
System.out.println(root.getTagName());
System.out.println(root.getTextContent());
if (root.hasAttributes()) {
NamedNodeMap map = root.getAttributes();
for (int i=0;i<map.getLength();i++) {
Node attribute = map.item(i);
if (attribute.getNodeType() == Node.ATTRIBUTE_NODE) {
System.out.println(attribute.getNodeName()+" : "+attribute.getTextContent());
}
}
}
if (root.hasChildNodes()) {
NodeList nodeList = root.getChildNodes();
for (int j=0;j<nodeList.getLength();j++) {
Node node = nodeList.item(j);
if (node.getNodeType() == Node.ELEMENT_NODE) {
parse((Element)node);
}
}
}
}
}
- SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。
选择DOM还是选择SAX? 对于需要自己编写代码来处理XML文档的开发人员来说, 选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档,而SAX采用的是事件模型。
DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。
SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag.特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。
【优势】
- 不需要等待所有数据都被处理,分析就能立即开始 。
- 只在读取数据时检查数据,不需要保存在内存中。
- 可以在某个条件得到满足时停止解析,不必解析整个文档。
- 效率和性能较高,能解析大于系统内存的文档。
【缺点】
- 需要应用程序自己负责TAG的处理逻辑(例如维护父/子关系等),文档越复杂程序就越复杂。
- 单向导航,无法定位文档层次,很难同时访问同一文档的不同部分数据,不支持XPath。
如果XML文档较大且不考虑移植性问题建议采用DOM4J;如果XML文档较小则建议采用JDOM;如果需要及时处理而不需要保存数据则考虑SAX。
/**
* SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。
选择DOM还是选择SAX? 对于需要自己编写代码来处理XML文档的开发人员来说, 选择DOM还是SAX解析模型是一个非常重要的设计决策。 DOM采用建立树形结构的方式访问XML文档,而SAX采用的是事件模型。
DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigation APIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。
SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag.特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。
【优势】
①不需要等待所有数据都被处理,分析就能立即开始。
②只在读取数据时检查数据,不需要保存在内存中。
③可以在某个条件得到满足时停止解析,不必解析整个文档。
④效率和性能较高,能解析大于系统内存的文档。
【缺点】
①需要应用程序自己负责TAG的处理逻辑(例如维护父/子关系等),文档越复杂程序就越复杂。
②单向导航,无法定位文档层次,很难同时访问同一文档的不同部分数据,不支持XPath。
如果XML文档较大且不考虑移植性问题建议采用DOM4J;如果XML文档较小则建议采用JDOM;如果需要及时处理而不需要保存数据则考虑SAX。
* Created by bing on 2017/1/4.
*/
public class SAXXML {
public static void main(String[] args) throws Exception {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setContentHandler(new BookHandler());
xmlReader.parse("src/main/java/com/ibingbo/xml/books.xml");
}
private static class BookHandler extends DefaultHandler{
boolean hasAttribute = false;
Attributes attributes = null;
@Override
public void startDocument() throws SAXException {
System.out.println("start document ...");
}
@Override
public void endDocument() throws SAXException {
System.out.println("end document ...");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println(qName);
if (attributes.getLength() > 0) {
for (int i=0;i<attributes.getLength();i++) {
System.out.println(attributes.getQName(i) + " : " + attributes.getValue(i));
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
System.out.println(new String(ch, start, length));
}
}
}
StAX把重点放在流上,StAX使应用程序能够把 XML 作为一个事件流来处理;其实SAX方式也是基于事件流的XML处理方法,但二者不同之处在于,SAX是基于观察者模式,我们需要提供事件处理程序并注册到解析器,解析器在指定事件发生时回调我们提供的程序;而StAX允许我们的程序把事件逐个”拉“出来,这样StAX就有更大的灵活性,对于我们不感兴趣的事件就没有必要将其”拉“出来处理。 StAX提供了两套API用来处理XML,分别提供了不同程度的抽象。基于指针的 API 把 XML 作为一个标记(或事件)流来处理;应用程序可以检查解析器的状态,获得解析的上一个标记的信息,然后再处理下一个标记,依此类推。这是一种低层 API,尽管效率高,但是没有提供底层 XML 结构的抽象。基于迭代器的 API 把 XML 作为一系列事件对象来处理。应用程序只需要确定解析事件的类型,将其转换成对应的具体类型,然后利用其方法获得属于该事件的信息
/**
* StAX把重点放在流上,StAX使应用程序能够把 XML 作为一个事件流来处理;其实SAX方式也是基于事件流的XML处理方法,但二者不同之处在于,SAX是基于观察者模式,我们需要提供事件处理程序并注册到解析器,解析器在指定事件发生时回调我们提供的程序;而StAX允许我们的程序把事件逐个”拉“出来,这样StAX就有更大的灵活性,对于我们不感兴趣的事件就没有必要将其”拉“出来处理。
StAX提供了两套API用来处理XML,分别提供了不同程度的抽象。基于指针的 API 把 XML 作为一个标记(或事件)流来处理;应用程序可以检查解析器的状态,获得解析的上一个标记的信息,然后再处理下一个标记,依此类推。这是一种低层 API,尽管效率高,但是没有提供底层 XML 结构的抽象。基于迭代器的 API 把 XML 作为一系列事件对象来处理。应用程序只需要确定解析事件的类型,将其转换成对应的具体类型,然后利用其方法获得属于该事件的信息
* Created by bing on 2017/1/4.
*/
public class STAXXML {
public static void main(String[] args) throws Exception {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
xmlInputFactory.setEventAllocator(new XMLEventAllocatorImpl());
// XMLStreamReader xmlStreamReader = XMLStreamReaderFactory.create("books.xml",new FileInputStream("src/main/java/com/ibingbo/xml/books.xml"),false);
//基于流、游标的读取
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new FileInputStream("src/main/java/com/ibingbo/xml/books.xml"));
//parse(xmlStreamReader);
//基于事件的读取
XMLEventReader eventReader = xmlInputFactory.createXMLEventReader(new FileInputStream("src/main/java/com/ibingbo/xml/books.xml"));
//可以封装过滤器
eventReader = xmlInputFactory.createFilteredReader(eventReader, new EventFilter() {
@Override
public boolean accept(XMLEvent event) {
return true;
}
});
parse(eventReader);
}
private static void parse(XMLEventReader eventReader) throws Exception {
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartDocument()) {
System.out.println("start document ...");
System.out.println(event.getSchemaType());
System.out.println(event.isNamespace());
} else if (event.isStartElement()) {
System.out.println(event.asStartElement().getName());
Iterator<Attribute> iterator = event.asStartElement().getAttributes();
if (null != iterator) {
while (iterator.hasNext()) {
Attribute attribute = iterator.next();
System.out.println(attribute.getName() + " : " + attribute.getValue());
}
}
} else if (event.isAttribute()) {
System.out.println(event.asCharacters().getData());
} else if (event.isCharacters()) {
System.out.println(event.asCharacters().getData());
}
}
}
private static void parse(XMLStreamReader xmlStreamReader) throws Exception {
int eventType = xmlStreamReader.getEventType();
while (xmlStreamReader.hasNext()) {
eventType = xmlStreamReader.next();
switch (eventType) {
case XMLStreamConstants.ATTRIBUTE:
break;
case XMLStreamConstants.START_DOCUMENT:
System.out.print("start document ..");
System.out.println(xmlStreamReader.getEncoding());
System.out.println(xmlStreamReader.getVersion());
System.out.println(xmlStreamReader.isStandalone());
break;
case XMLStreamConstants.START_ELEMENT:
System.out.println(xmlStreamReader.getLocalName());
int count = xmlStreamReader.getAttributeCount();
if (count > 0) {
for (int i = 0; i < count; i++) {
System.out.println(xmlStreamReader.getAttributeLocalName(i) + " : " + xmlStreamReader.getAttributeValue(i));
}
}
break;
case XMLStreamConstants.CDATA:
case XMLStreamConstants.COMMENT:
case XMLStreamConstants.CHARACTERS:
case XMLStreamConstants.SPACE:
System.out.println(xmlStreamReader.getText());
break;
default:
break;
}
}
}
}
Digester 就是一种用来把一个 XML 转化为一个与该 XML 结构类似的 JavaBean。你可以把 XML 根元素想象成一个 JavaBean, 该根元素的 attribute 就是这个 JavaBean 的各种 Field,当该根元素有其他子 tag 时,又要把这个子 tag 想象成一个个新的 XML,将其视为一个新的 JavaBean, 并作为一个 Field 加入到父 Bean 当中,然后以此类推,通过循环的方式将整个 XML 进行解析
/**
* Digester 就是一种用来把一个 XML 转化为一个与该 XML 结构类似的 JavaBean。你可以把 XML 根元素想象成一个 JavaBean, 该根元素的 attribute 就是这个 JavaBean 的各种 Field,当该根元素有其他子 tag 时,又要把这个子 tag 想象成一个个新的 XML,将其视为一个新的 JavaBean, 并作为一个 Field 加入到父 Bean 当中,然后以此类推,通过循环的方式将整个 XML 进行解析
* Created by bing on 2017/1/4.
*/
public class DigesterXML {
public static void main(String[] args) throws Exception {
File file = new File("src/main/java/com/ibingbo/xml/books.xml");
Digester digester = new Digester();
//创建Books对象
digester.addObjectCreate("books", Books.class);
//添加Books对象的一些属性
digester.addSetProperties("books");
//创建Book对象
digester.addObjectCreate("books/book", Book.class);
//添加Book对象的一些属性
digester.addSetProperties("books/book");
//设置Book对象的指定属性的值
digester.addBeanPropertySetter("books/book/title", "title");
digester.addBeanPropertySetter("books/book/author", "author");
//下一个Book对象,解析并添加到Books中,通过addBook方法
digester.addSetNext("books/book", "addBook", "com.xml.Book");
Books books = (Books) digester.parse(file);
System.out.println(books);
}
}
public class Books {
private List<Book> books = new ArrayList<>();
public List<Book> getBooks() {
return books;
}
public void setBooks(List<Book> books) {
this.books = books;
}
public void addBook(Book book) {
this.books.add(book);
}
@Override
public String toString() {
return "Books{" +
"books=" + books +
'}';
}
}
public class Book {
private String id;
private String title;
private String author;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", title='" + title + '\'' +
", author='" + author + '\'' +
'}';
}
}