认识XML
XML是一种标记性语言,使用XML可以方便的实现数据交换、系统配置、内容管理等功能。XML与HTML类似,最大不同是HTML中的元素都是固定的,且以显示为主,而XML语言中的标记都是由用户自定义的,主要以数据保存为主。
XML和HTML的比较:
NO. | 比较内容 | HTML | XML |
1 | 可扩展性 | 不具有扩展性 | 是无标记语言,可定义新的标记语言 |
2 | 侧重点 | 侧重于如何显示信息 | 侧重于如何结构化地描述信息 |
3 | 语法要求 | 不要求标记的嵌套、配对等,不要求标记之间具有一定的顺序 | 严格要求嵌套、配对,遵循统一的循序结构要求 |
4 | 可读性及可维护性 | 难于阅读、维护 | 结构清晰、便于维护、阅读 |
5 | 数据和显示的关系 | 内容描述与显示方式融合在一起 | 内容描述与显示方式相分离 |
6 | 保值性 | 不具有保值性 | 具有保值性 |
下面给出XML文件的简单范例:
<?xml version="1.0" encoding="GBK"?>
<addresslist>
<linkman>
<name>小王</name>
<email>xaiowang@163.com</email>
</linkman>
<linkman>
<name>阿樱</name>
<email>aying@163.com</email>
</linkman>
</addresslist>
由上例可见XML文件由前导区和数据区两部分组成。前导区包括下面三个属性(
顺序不能错):
- version: 表示使用的XML版本,现在是1.0。
- encoding: 页面中使用的文字编码,如果有中文,一般指定GBK编码格式。
- standalone: 此XML文件是否是独立运行,如果需要进行显示可以使用CSS或XSL控制。
XML中使用的是自定义的元素,同时也可以定义属性,属性的内容必须使用“”括起来。
注意:如果不需要显示可以使用属性,需要显示出来则使用元素。
XML的解析
本文仅着重介绍XML作为数据存储应用,因此对于显示部分不做过多介绍。了解了XML的基本介绍后,下面介绍如果解析XML文件和如何生成自定义的XML文件。
W3C定义了SAX和DOM两种解析方式,如下图所示:
SAX可以快速扫描一个大型的XML文档,当它找到查询标准时就会立即停止,然后再处理之。DOM是把XML全部加载到内存中建立一棵树之后再进行处理。所以DOM不适合处理大型的XML。
同理,DOM的弱项就是SAX的强项,SAX不必把全部的xml都加载到内存中。但是SAX的缺点也很明显,它只能对文件顺序解析一遍,不支持对文件的随意存取。SAX也仅仅能够读取文件的内容,并不能修改内容。DOM可以随意修改文件树,从而修改了xml文件。
SAX解析器和DOM解析器的区别:
No. | 区别 | SAX | DOM |
1 | 操作 | 依序读入文件并产生相应的事件,可以处理任何大小的XML文件 | 在内存中建立文件树,不适于处理大型的XML文件 |
2 | 访问限制 | 只能对文件按顺序剖析一遍,不支持对文件的随意存取 | 可以随意存取文件树的任何部分,没有次数限制 |
3 | 修改 | 只能读取XML文件内容,而不能修改 | 可以随意修改文件树,从而修改了XML文件 |
4 | 复杂度 | 开发商比较复杂,需要自己来制作事件处理器 | 易于理解,易于开发 |
5 | 对象模型 | 对工作人员更灵活,可以用SAX建立自己的XML对象模型 | 已经在DOM基础之上建立文件树 |
在DOM解析中有以下4个核心的操作接口。
- Document: 代表整个XML文档,表示整棵DOM树的根,提供了对文档中的数据进行访问和操作的入口。
- Node: 代表DOM树中的一个节点。
- NodeList: 表示一个节点的集合,用于表示有顺序关系的一组节点。
- NamedNodeMap: 表示一组节点和其唯一名称对应的一一对应关系。
除以上4个核心接口外,如果一个程序需要进行DOM解析读操作,则需要按照如下步骤进行:
下面解析上面提到的xml文件,代码如下:
public static void main(String args[]) throws Exception { // 取得DocumentBuilderFactory类的对象 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance() ; // 取得DocumentBuilder类的对象 DocumentBuilder build = factory.newDocumentBuilder(); Document doc = null; try { doc = build.parse(new File("D:" + File.separator + "dom_parse.xml")) ; } catch (Exception e) { e.printStackTrace(); } // 得到所有的linkman节点 NodeList nl = doc.getElementsByTagName("linkman") ; for(int x=0;x<nl.getLength();x++){ Element e = (Element) nl.item(x) ; // 取出每一个元素 System.out.println("姓名:" + e.getElementsByTagName("name").item(0).getFirstChild().getNodeValue()) ; System.out.println("邮箱:" + e.getElementsByTagName("email").item(0).getFirstChild().getNodeValue()) ; } }
解析结果:
生成XML文件
生成XML文件到硬盘上,需要使用TransformerFactory、Transformer、DOMSource和StreamResult四个类完成。StreamResult类的主要功能时指定要使用的输出流对象,最后通过Transformer类完成内容的输出。
建立完SAX解析器之后,还需要建立SAXParserFactory和SAXParser两个类,可以通过SAXParserFactory的newSAXParser()方法创建SAXParser对象,之后通过SAXParser的parse()方法指定要解析的XML文件和制定的SAX解析器。
代码如下:
public static void main(String args[]) throws Exception {
// 取得DocumentBuilderFactory类的对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance() ;
// 取得DocumentBuilder类的对象
DocumentBuilder build = factory.newDocumentBuilder() ;
Document doc = build.newDocument() ; // 创建一个新的XML文档
Element addresslist = doc.createElement("addresslist") ;
Element linkman = doc.createElement("linkman") ;
Element name = doc.createElement("name") ;
name.setAttribute("index", "1"); //设置属性
Element email = doc.createElement("email") ;
// 设置节点内容
name.appendChild(doc.createTextNode("小丽")) ;
email.appendChild(doc.createTextNode("xiaoli@163.com")) ;
// 该设置各个节点的关系
linkman.appendChild(name) ; // name是linkeman的子节点
linkman.appendChild(email) ; // email是linkman的子节点
addresslist.appendChild(linkman) ;
doc.appendChild(addresslist) ;
TransformerFactory tf = TransformerFactory.newInstance() ;
Transformer t = tf.newTransformer() ;
t.setOutputProperty(OutputKeys.ENCODING, "GBK") ; // 处理中文的
DOMSource source = new DOMSource(doc) ; // 准备输出文档
StreamResult result = new StreamResult(new File("d:"+File.separator+"output.xml")) ;
t.transform(source,result) ;
}
生成的文件:
SAX(Simple APIs for XML)解析
SAX采用的是一种循序的模式进行访问,是一种快速读取XML数据的方式。当使用SAX解析器进行操作时会触发一系列的事件,当扫描到文档(Document)开始与结束、元素(Element)开始与结束时都会调用相关的处理方法,并由这些操作方法做出相应的操作,直至整个文档扫描结束。
使用SAX解析,首先应该编写一个SAX解析器,定义一个类,并使该类继承自DefaultHandler类,同时覆写上表列出的方法即可。
SAX解析器代码(
注意使用的包,否则可能出错):
package com.xml;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SimpleSAX extends DefaultHandler{
@Override
public void startDocument() throws SAXException {
System.out.println("<?xml version=\"1.0\" encoding=\"GBK\" standalone=\"no\"?>");
}
@Override
public void endDocument() throws SAXException {
System.out.println("\n 文档读取结束");
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
System.out.print("<"+name);
if (attributes!=null) {
for(int i=0;i<attributes.getLength();i++){
System.out.print(" "+ attributes.getQName(i)+"="+"\""+attributes.getValue(i)+"\"");
}
}
System.out.print(">");
}
@Override
public void characters(char[] ch, int start, int end) throws SAXException {
System.out.print(new String(ch,start,end));
}
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
System.out.println("</"+name+">");
}
}
使用SAX解析器:
package com.xml;
import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.helpers.DefaultHandler;
public class XMLtest {
public static void main(String args[]) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
String path = "d:"+File.separator+"qoutput.xml";
try {
parser.parse(path, new SimpleSAX());
} catch (Exception e) {
e.printStackTrace();
}
}
}
解析的XML文件:
<?xml version="1.0" encoding="GBK" standalone="no"?>
<addresslist>
<linkman>
<name index="1">小丽</name>
<email>xiaoli@163.com</email>
</linkman>
</addresslist>
解析结果: