目录

1、JDK提供的两种XML原生解析方式

1.1 Dom

1.1.1 Mybatis与Dom

1.2 SAX

2、Jdom/Dom4j 

2.1 Jdom

2.2 Dom4j

2.2.1 Spring与Dom4J

3、OXMapping技术


1、JDK提供的两种XML原生解析方式

参考文档:Java解析XML(4种方法)

1.1 Dom

Dom解析XML的过程是一次将整个xml文档全部加载到内存中,然后进行解析与访问。
优点:
  1、XML形成了树数据结构,直观比较容易理解,编码比较容易
  2、因为XML以树的形式保留在内存中,方便进行修改
缺点:
 1、不太适合解析大XML文件,当解析大XML文件时,对内存耗费比较大,容易造成性能问题,造成内存溢出。
下面给出用JDK DOM方式解析一个XML文件的示例:

<?xml version="1.0" encoding="utf-8" ?>
<students>
	<student stuNo="1">
		<name>张三</name>
		<nickname>张三</nickname>
		<score>85</score>
	</student>
	<student stuNo="2">
		<name>李四</name>
		<nickname>李四</nickname>
		<score>85</score>
	</student>
	<student stuNo="3">
		<name>王五</name>
		<nickname>王五</nickname>
		<score>85</score>
	</student>
</students>
package com.autocoding.xml;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
 * 
 * @Description:  JDK原生:Dom 方式解析XML
 * @author: QiaoLi
 * @date:   Jan 25, 2021 9:55:14 AM
 */
public class DomDemo {
	public static void node(NodeList list) {
		for (int i = 0; i < list.getLength(); i++) {
			Node node = list.item(i);
			NodeList childNodes = node.getChildNodes();
			for (int j = 0; j < childNodes.getLength(); j++) {
				if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE) {
					System.out.print(childNodes.item(j).getNodeName() + ":");
				System.out.println(childNodes.item(j).getFirstChild().getNodeValue());
				}
			}
			System.out.println();
		}
	}
	public static void main(String[] args) {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse("src/test/resources/students.xml");
			NodeList nodeList = document.getElementsByTagName("student");
			DomDemo.node(nodeList);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

程序运行结果:

java项目xml怎么配置 xml java_xml

1.1.1 Mybatis与Dom

Mybatis是采用Dom方式来解析XML configuration配置文件的。org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XNode) 核心方法:

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

XNode代码如下:

*    Copyright 2009-2019 the original author or authors.
package org.apache.ibatis.parsing;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.w3c.dom.CharacterData;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author Clinton Begin
 */
public class XNode {

  private final Node node;
  private final String name;
  private final String body;
  private final Properties attributes;
  private final Properties variables;
  private final XPathParser xpathParser;

  public XNode(XPathParser xpathParser, Node node, Properties variables) {
    this.xpathParser = xpathParser;
    this.node = node;
    this.name = node.getNodeName();
    this.variables = variables;
    this.attributes = parseAttributes(node);
    this.body = parseBody(node);
  }
...... 代码省略

}

1.2 SAX

SAX采用事件驱动模式解析XML文件,访问一个Element发一个事件,对应的DefaultHandler就会进行事件处理。
优点:
  1、采用事件驱动模式,对内存消耗比较小,不会有内存溢出问题
  2、只适合读取XML文件,整个文档结构在内存中并产保存,后期无法修改XML文档
缺点:
 1、需要开发自己的DefaultHandler事件处理器,编码相对于Dom来有一定的门槛
下面给出用JDK SAX 方式解析一个XML文件的示例,XML文件也上述中的students.xml相同 :

package com.autocoding.xml;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SaxDemo {

	public static void main(String[] args) throws Exception {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser saxParser = factory.newSAXParser();
		MyHandler handler = new MyHandler();
		saxParser.parse("src/test/resources/students.xml", handler);
	}
	private static class MyHandler extends DefaultHandler {
		// 遍历xml文件开始标签
		@Override
		public void startDocument() throws SAXException {
			super.startDocument();
			System.out.println("sax解析开始");
		}
		// 遍历xml文件结束标签
		@Override
		public void endDocument() throws SAXException {
			super.endDocument();
			System.out.println("sax解析结束");
		}
		@Override
		public void startElement(String uri, String localName, String qName, Attributes attributes)
				throws SAXException {
			super.startElement(uri, localName, qName, attributes);
			if (qName.equals("student")) {
				System.err.println("============开始遍历student=============");
			} else if (!qName.equals("student") && !qName.equals("students")) {
				log.info("uri:{},localName:{},qName:{}", uri, localName, qName);
			}
		}
		@Override
		public void endElement(String uri, String localName, String qName) throws SAXException {
			super.endElement(uri, localName, qName);
			if (qName.equals("student")) {
				log.info("uri:{},localName:{},qName:{}", uri, localName, qName);
				System.err.println("============结束遍历student=============");
			}
		}
		@Override
		public void characters(char[] ch, int start, int length) throws SAXException {
			super.characters(ch, start, length);
			String value = new String(ch, start, length).trim();
			if (!value.equals("")) {
				System.out.println(value);
			}
		}
	}
}

下面是程序运行结果:

sax解析开始
============开始遍历student=============
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:name

张三
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:nickname

张三
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:score

85
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.endElement(SaxDemo.java:52) com.autocoding.xml.SaxDemo
uri:,localName:,qName:student

============结束遍历student=============
============开始遍历student=============
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:name

李四
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:nickname

李四
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:score

85
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.endElement(SaxDemo.java:52) com.autocoding.xml.SaxDemo
uri:,localName:,qName:student

============结束遍历student=============
============开始遍历student=============
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:name

王五
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:nickname

王五
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.startElement(SaxDemo.java:44) com.autocoding.xml.SaxDemo
uri:,localName:,qName:score

85
2021-01-25 10:17:09 [INFO] com.autocoding.xml.SaxDemo$MyHandler.endElement(SaxDemo.java:52) com.autocoding.xml.SaxDemo
uri:,localName:,qName:student

============结束遍历student=============
sax解析结束

2、Jdom/Dom4j 

2.1 Jdom

为了快速开发XML应用程序,同时为了弥补JDK原生两种DOM与SAX方式在应用中的不足,Jdom出现了,它是一个开源项目。Jdom仅使用具体类而没有面向抽象编程,Jdom
API中大量使用了Collection集合框架中的类。

2.2 Dom4j

        Dom4j是Jdom的一个分支,它合并了许多超出基本XML文档的功能,并且Dom4j面向抽象进行编程,它大量使用了接口与抽象类,是一个优秀的Java XML API;
它具有性能优异、灵活性好、功能强大、易于使用的优点;开源。
       下面是一个示例代码,解析 students.xml 文件:

package com.autocoding.xml;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
 *  Dom4J 解析XML
 * @author: QiaoLi
 * @date:   Jan 25, 2021 10:36:23 AM
 */
public class Dom4JDemo {
	public static void main(String[] args) throws Exception {
		SAXReader reader = new SAXReader();
		Document document = reader.read(new File("src/test/resources/students.xml"));
		Element rootElement = document.getRootElement();
		Iterator<Element> iterator = rootElement.elementIterator();
		while (iterator.hasNext()) {
			Element stu = iterator.next();
			List<Attribute> attributes = stu.attributes();
			for (Attribute attribute : attributes) {
				System.err.println(attribute.getName()+":"+attribute.getValue());
			}
			System.out.println("======遍历子节点======");
			Iterator<Element> stuChildren = stu.elementIterator();
			while (stuChildren.hasNext()) {
				Element stuChild = stuChildren.next();
				System.out.println("节点名:" + stuChild.getName() + "---节点值:" + stuChild.getStringValue());
			}
			System.out.println();
		}
	}
}

下面是程序运行结果:

java项目xml怎么配置 xml java_java项目xml怎么配置_02

2.2.1 Spring与Dom4J

spring解析xml配置的第三方库需要的是dom4j。参考文档:spring的xml解析原理

 

3、OXMapping技术

使 用 XML API 解析是略显烦琐的,受 ORMapping 技术的启发,人们发明了 OXMapping 技术,使用 OXMapping 技术,我们可以将 XML 文件映射成一个 JavaBean 对象,也可以把一个 JavaBean 对象保存成一个 XML 文件,
这大大简化了我们的开发工作量,使得开发人员能更多的关注应用层面的东西。开源世界中涌现出很多 OXMapping 框架,包括 XStream 、 Digester 、 Castor 等。 XStream 和 Digester 把映射的过程在代码中完成,
而 Castor 则需要写一个和 Hibernate 中 cfg.xml 类似的映射配置文件。与 Digester 比起来, XStream 的主要优点就是更加小巧,使用也更加方便,不过目前使用 Digester 是“开源名牌” Apache 下的子项目,
网上可以参考的资料也比 XStream 多,好在 XStream 比较简洁,所以并不会对 XStream 造成太大影响。
         目前OXMaaping的一个流行的实现是XStream,它即是OXMapping的实现,同时实现了序列化与反序列化,可以很方便地对Java Object 与 Xml之间进行转换。
XStream是Java类库,用来将对象序列化成XML (JSON)或反序列化为对象。也就是说,使用XStream,我们可以把Java对象转换成XML,也可以将XML转换为Java对象。
        参考文档:
XStream 简介