Java中XML的解析与序列化使用

XML简介

XML的作用

  • 数据存储:
  • 数据库提供了更强有力的数据存储和分析能力
  • XML仅仅是存储数据
  • XML与其他数据表现形式最大的不同是它极其简单,正是这点使XML与众不同
  • 数据交换
    • 由于各个计算机所使用的操作系统、数据库不同,因此数据之间的交换向来是件头痛的事
    • 可以使用XML来交换数据
  • 数据配置:
    • 使用XML配制文件可读性强,灵活性高

解析XML

  • 目前最常用的XML解析技术
    • DOM
    • SAX
  • Sun公司提供了JAXP(JavaAPIforXML)接口来使用DOM和SAX
    • org.w3c.dom:W3C推荐的用于使用DOM解析XML文档的接口
    • org.xml.sax:用于使用SAX解析XML文档的接口
    • javax.xml.parsers:解析器工厂工具,程序员获得并配置特殊的特殊语法分析器

两种解析方式的优缺点比较

Java的xml解析器库有很多,总的来说,万变不离其宗的就是SAX和DOM解析器。

  • SAX的包是org.xml.sax
  • DOM的包是org.w3c.dom
  1. DOM
    DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而DOM被认为是基于树或基于对象的。DOM以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。
    另一方面,对于特别大的文档,解析和加载整个文档可能很慢且很耗资源,因此使用其他手段来处理这样的数据会更好。这些基于事件的模型,比如SAX。

  2. SAX
    这种处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX还比它的替代者DOM快许多。

  3. 选择DOM还是选择SAX?
    对于需要自己编写代码来处理XML文档的开发人员来说,选择DOM还是SAX解析模型是一个非常重要的设计决策。

    DOM采用建立树形结构的方式访问XML文档,而SAX采用的事件模型。

    DOM解析器把XML文档转化为一个包含其内容的树,并可以对树进行遍历。用DOM解析模型的优点是编程容易,开发人员只需要调用建树的指令,然后利用navigationAPIs访问所需的树节点来完成任务。可以很容易的添加和修改树中的元素。然而由于使用DOM解析器的时候需要处理整个XML文档,所以对性能和内存的要求比较高,尤其是遇到很大的XML文件的时候。由于它的遍历能力,DOM解析器常用于XML文档需要频繁的改变的服务中。

    SAX解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件,当发现给定的tag的时候,它可以激活一个回调方法,告诉该方法制定的标签已经找到。SAX对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。特别是当开发人员只需要处理文档中所包含的部分数据时,SAX这种扩展能力得到了更好的体现。但用SAX解析器的时候编码工作会比较困难,而且很难同时访问同一个文档中的多处不同数据。

    • DOM:
      解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用DOM接口来操作这个树结构。优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)
    • SAX:
      事件驱动。当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。优点:不用事先调入整个文档,占用资源少缺点:不是持久的;事件过后,若没保存数据,那么数据就丢了;无状态性;从事件中只能得到文本,但不知该文本属于哪个元素;使用场合:只需XML文档的少量内容,很少回头访问;一次性读取;机器内存少;注意:SAX解析器不创建任何对象。

下方的XML文件将作为我们的解析对象:

<?xml version="1.0" encoding="UTF-8"?>
<students>
	<student id="1001">
		<name>张三</name>
		<age>22</age>
		<sex></sex>
	</student>
	<student id="1002">
		<name>李四</name>
		<age>32</age>
		<sex></sex>
	</student>
</students>

XML解析方式

1.DOM解析

开始解析:

		try {
            //		1.获得文档解析工厂
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            //		2.获得文档解析器
			DocumentBuilder builder = factory.newDocumentBuilder();
            //		3.解析XML文档,获得XML文档树
			Document doc = builder.parse("student.xml");
            //		4.获取文档的根结点
			Element root = doc.getDocumentElement();
            
            //		获取所有名称为student的结点元素,返回一个含有所有学生的列表
			NodeList students = root.getElementsByTagName("student");
            //		遍历列表
			for (int i = 0; i < students.getLength(); i++) {
                //		获得列表中的一个学生元素
				Node student = students.item(i);
                //		获得学生的id属性元素
				Node id = student.getAttributes().getNamedItem("id");
                //		获得属性元素的文本内容
				System.out.println("学生id属性为: " + id.getTextContent());
                //		获得一个学生元素的内部子节点,返回所有结点的列表
				NodeList childNodes = student.getChildNodes();
                //		遍历这个列表
				for (int j = 0; j < childNodes.getLength(); j++) {
                    //		获得列表中的一个元素
					Node item = childNodes.item(j);
                    //		获得元素的文本内容
					String content = item.getNodeName();
					if ("name".equals(content)) {
						System.out.println("学生姓名为:" + item.getTextContent());
						continue;
					}
					if ("age".equals(content)) {
						System.out.println("学生年龄为:" + item.getTextContent());
						continue;
					}
					if ("sex".equals(content)) {
						System.out.println("学生性别为:" + item.getTextContent());
						continue;
					}
				}
			}
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

2.SAX解析

开始解析:

public class SaxParse {
	public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
//		1.SAX解析器工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
//		2.使用SAX解析器工厂,创建解析器
		SAXParser parser = factory.newSAXParser();
//		3.创建事件处理对象
		MyHandler handler = new MyHandler();
//		4.使用parse解析XML文档

		parser.parse("student.xml", handler);

		List<Student> list = handler.getStudentList();
		System.out.println(list);
	}
}

class MyHandler extends DefaultHandler {
	private List<Student> list = new ArrayList<>();
	private Student s = null;
	/*
	 * 0:其他标签 1:name标签 2:age标签 3:sex标签
	 */
	private State state = State.NONE;


	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
//		如果遇到不是name,age,sex的标签,跳过解析
		if (state != State.NONE) {
			String str = new String(ch, start, length);
			System.out.println("获取对象 -> " + str);
			switch (state) {
			case NAME:
				s.setName(str);
				break;
			case AGE:
				s.setAge(Integer.parseInt(str));
				break;
			case SEX:
				s.setSex(str);
				break;
			default:
				break;
			}
			state = State.NONE;
		}
	}

	/**
	 * 此发再SAX解析器开始解析XML文档时触发
	 * 
	 * @throws SAXException
	 */
	@Override
	public void startDocument() throws SAXException {
		System.out.println("开始文档解析");
	}

    
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if ("student".equals(qName)) {
			s = new Student();
		}
		if (s != null) {
			switch (qName) {
			case "name":
				state = State.NAME;
				break;
			case "age":
				state = State.AGE;
				break;
			case "sex":
				state = State.SEX;
				break;
			default:
				break;
			}
		}
		System.out.println("开始标签 -> " + qName);
		if (attributes.getLength() > 0) {
			for (int i = 0; i < attributes.getLength(); i++) {
				String id = attributes.getValue("id");
				s.setId(Integer.parseInt(id));
				System.out.println("获取属性 -> " + attributes.getQName(i) + " = " + attributes.getValue(i));
			}
		}
	}


	@Override
	public void endDocument() throws SAXException {
		System.out.println("结束文档解析");
	}


	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		System.out.println("结束标签 -> " + qName);
		if ("student".equals(qName)) {
			list.add(s);
			s = null;
		}
	}


	public List<Student> getStudentList() {
		return list;
	}
}

enum State {
	/**
	 * 未匹配到nage,age,sex结点
	 */
	NONE(0),
	/**
	 * 解析到name结点
	 */
	NAME(1),
	/**
	 * 解析到age结点
	 */
	AGE(2),
	/**
	 * 解析到SEX结点
	 */
	SEX(3);

	private int state;

	private State(int state) {
		this.state = state;
	}

	public int getState() {
		return state;
	}
}

3.DOM4J解析:

dom4j是一个Java的XML API,是jdom的升级品,用来读写XML文件的。dom4j是一个十分优秀的JavaXML API,具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在IBM developerWorks上面还可以找到一篇文章,对主流的Java XML API进行的性能、功能和易用性的评测,所以可以知道dom4j无论在哪个方面都是非常出色的。如今可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这已经是必须使用的jar包, Hibernate也用它来读写配置文件。

特征:

  1. JDOM的一种智能分支,它合并了许多超出基本XML文档表示的功能。
  2. 2、它使用接口和抽象基本类方法。
  3. 具有性能优异、灵活性好、功能强大和极端易用的特点。
  4. 是一个开放源码的文件
		try {
            //		创建解析器
			SAXReader reader = new SAXReader();
            //		解析xml文件
			Document document = reader.read("student.xml");
            //		获得根结点
			Element root = document.getRootElement();
            //		获得根结点的子节点
			List<Element> students = root.elements();
            //		迭代
			for (Iterator<Element> it = students.iterator(); it.hasNext();) {
				Element student = it.next();
				System.out.println("学生id属性:" + student.attribute("id").getText());
                //		获得子节点
				List<Element> childNodes = student.elements();
				for (Iterator<Element> itt = childNodes.iterator(); itt.hasNext();) {
					Element child = itt.next();
                    //		获得结点名和对应结点的文本内容
					System.out.println(child.getName() + " : " + child.getText());
				}
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}

XML文档的序列化及反序列化

Xstream是一种OXMapping 技术,是用来处理XML文件序列化的框架,在将JavaBean序列化,或将XML文件反序列化的时候,不需要其它辅助类和映射文件,使得XML序列化不再繁索。Xstream也可以将JavaBean序列化成Json或反序列化,使用非常方便。使用前需要到官方下载指定的jar包.

序列化:

		try (FileOutputStream oos = new FileOutputStream("students.xml");) {
			Student[] ss = new Student[] { 
					new Student("张三", 22, "男"),
					new Student("李四", 32, "男"), 
			};
			XStream xStream = new XStream();
			//	起别名
			xStream.alias("所有学生", Student[].class);
			xStream.alias("学生", Student.class);
			xStream.aliasField("姓名", Student.class, "name");
			xStream.aliasField("年龄", Student.class, "age");
			xStream.aliasField("性别", Student.class, "sex");
			xStream.toXML(ss, oos);
		} catch (IOException e) {
			e.printStackTrace();
		}

输出students.xml文件:

<所有学生>
  <学生>
    <姓名>张三</姓名>
    <年龄>22</年龄>
    <性别>男</性别>
  </学生>
  <学生>
    <姓名>李四</姓名>
    <年龄>32</年龄>
    <性别>男</性别>
  </学生>
</所有学生>

反序列化:

		try (FileInputStream fis = new FileInputStream("src/test/students.xml")) {
			XStream xStream = new XStream();
			xStream.alias("所有学生", Student[].class);
			xStream.alias("学生", Student.class);
			xStream.aliasField("姓名", Student.class, "name");
			xStream.aliasField("年龄", Student.class, "age");
			xStream.aliasField("性别", Student.class, "sex");
			Student[] students = (Student[])xStream.fromXML(fis);
			System.out.println(Arrays.toString(students));
		} catch (IOException e) {
			e.printStackTrace();
		}
JavaXML序列化是将Java对象转换为XML格式的过程。XML序列化可以用于数据持久化、数据传输等场景。Java提供了多种方式来实现XML序列化,包括JAXB、XStream、Dom4j等。 JAXB是Java Architecture for XML Binding的缩写,是Java SE 6及以上版本自带的一种XML数据绑定技术。JAXB通过注解或XML配置文件来描述Java类与XML之间的映射关系,从而实现Java对象到XML序列化和反序列化。以下是一个使用JAXB进行XML序列化的示例代码: ```java // 定义一个Java类 @XmlRootElement public class Person { private String name; private int age; private String address; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } // 序列化Java对象到XML public static void serializeToXml(Person person, String xmlFilePath) throws JAXBException { JAXBContext context = JAXBContext.newInstance(Person.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(person, new File(xmlFilePath)); } // 反序列化XMLJava对象 public static Person deserializeFromXml(String xmlFilePath) throws JAXBException { JAXBContext context = JAXBContext.newInstance(Person.class); Unmarshaller unmarshaller = context.createUnmarshaller(); return (Person) unmarshaller.unmarshal(new File(xmlFilePath)); } ``` 使用JAXB进行XML序列化需要注意以下几点: 1. Java类需要使用@XmlRootElement注解标注为根元素。 2. Java类的属性需要使用@XmlAttribute或@XmlElement注解标注为XML属性或元素。 3. 序列化时需要创建JAXBContext和Marshaller,反序列化时需要创建JAXBContext和Unmarshaller。 4. 序列化时可以设置Marshaller的属性,如是否格式化输出。 除了JAXB外,XStream和Dom4j也是常用的XML序列化工具。XStream是一款简单易用的XML序列化框架,通过注解或代码配置来完成Java类与XML之间的映射关系。Dom4j是一款基于JavaXML解析和生成,可以快速方便地操作XML文档。无论使用哪种工具,XML序列化都是Java开发常用的技术之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值