引子:某班级的学生信息,要求符合XML语法的规范。学生信息包括姓名、年龄、电子邮箱、身高、电话、单位等;单位又包含地址、邮编等信息,每个学生都要有一个“编号”属性作为标识。例如,姓名为“张三”的学生有两个电子邮箱,每个学生有电话或手机。XML代码如下所示:
<班级>
<学生 编号="A0001">
<姓名>张三</姓名>
<年龄>23</年龄>
<电子邮箱>zhangsan@163.com</电子邮箱>
<电子邮箱>zhangsan@yahoo.com</电子邮箱>
<身高>179.5</身高>
<电话>686868</电话>
<单位>
公司
<地址>上海</地址>
<邮编>100002</邮编>
</单位>
</学生>
<学生 编号="A0003">
<姓名>李四</姓名>
<年龄>24</年龄>
<电子邮箱>lisi@263.com</电子邮箱>
<身高>168.0</身高>
<手机>135013562554</手机>
<单位>
<地址>北京</地址>
</单位>
</学生>
<学生 编号="A0002">
<姓名>王五</姓名>
<年龄>21</年龄>
<电子邮箱>wangwu@163.com</电子邮箱>
<身高>179.5</身高>
<电话>686868</电话>
<单位>XXXX公司</单位>
</学生>
</班级>
XML的起源和目的
XML是Extensible Markup Language的缩写,即可扩展标记语言。它是一种用来创建的标记的标记语言。1996年,万维网协会(或者叫W3C,http://www.w3c.org)开始设计一种可扩展的标记语言,1998年2月,XML1.0成为了W3C的推荐标准。这种XML语言继承了SGML的规范,Standard Generalized Markup Language (SGML)是一种基于记号文本的语言。关于SGML语言,我们会在本章的扩展部分给大家介绍,另外XML还保持了对现有的面向SGML系统的向下兼容性。XML将SGML的灵活性和强大功能与已经被广泛采用的HTML结合起来,简化了计算机对文档和数据交换的处理,使得现有的协议和软件更为协调,从而简化了数据的处理和传输。
使用XML标记语言可以做到数据或数据结构在任何编程语言环境下的共享。例如我们在某个计算机平台上用某种编程语言编写了一些数据或数据结构,然后用XML标记语言进行处理,那样的话,其他人就可以在其他的计算机平台上来访问这些数据或数据结构,甚至可以用其他的编程语言来操作这些数据或数据结构了。这就是XML标记语言作为一种数据交换语言存在的价值。
XML数据解析
是将数据文档解析成不同的格式。因为不同平台(软件)在做数据传递或数据文档共享的时候,同一数据文档可能在不同平台的 显示格式要求不同,这就出现了相对中立的
语言(XML),来表示数据,给二者做转化。
常用的XML解析方式及各自特征
一:DOM(dom4,这种是标准的方式)
DOM 文档对象模型(w3c标准模型)[既能解析XML文档,也能把对象写成XML文件格式]
解析文档前,全部加载,转化为树模型。
DOM是HTML和XML文档的编程接口规范,它与平台和语言是无关的,因而可以用各种语言和在各种平台上实现。
DOM的原理简单的说,就是通过解析XML文档,为XML文档在逻辑上建立一个树模型,树的节点是一个个对象。我们通过存取这些对象就能够操作XML文档中的内容了。
用到的节点(节点都需要自己创建)
Document文档节点
Element元素节点
Text文本节点
Attr属性节点
DOM的优势主要表现在:易用性强,使用DOM时,将把所有的XML文档信息都存于内存中,并且遍历简单,支持XPath,增强了易用性。
DOM的缺点主要表现在:效率低,解析速度慢,内存占用量过高,对于大文件来说几乎不可能使用。另外效率低还表现在大量的消耗时间,因为使用DOM进行解析时,将为文档的每个element、attribute、processing-instrUCtion和comment都创建一个对象,这样在DOM机制中所运用的大量对象的创建和销毁无疑会影响其效率。
二:SAX解析:Simple API for XML
占内存小,难理解
加载一部分,解析一部分
顺序解析,基于事件驱动[只能解析]
1.文档开始 startDocument()
2.元素开始 startElement(String arg0, String arg1, String arg2,Attributes arg3)
3.文本characters(char[] arg0, int arg1, int arg2)
4.文本结束 endDocument()
5.元素结束 endElement
加载文档时,遇到不同标签,自动触发不同的事件,自动调用相应的5种处理方法(方法的具体实现自己编写),直到文档结束
SAX,既是指一种接口,也是指一个软件包。SAX最初是由David Megginson采用Java语言开发,之后SAX很快在Java开发者中流行起来。San现在负责管理其原始API的开发工作,这是一种公开的、开放源代码软件。不同于其他大多数XML标准的是,SAX没有语言开发商必须遵守的标准SAX参考版本。因此,SAX的不同实现可能采用区别很大的接口。
...使用详解..................................................................
一:DOM解析
//假设有实体对象Student类如下:
public class Student {
private String name;
private int age;
private String address;
//.构造及get/set方法此处省略........
}
//student.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name>张三</name>
<age>77</age>
<address>cs</address>
</student>
<student>
<name>蕾丝</name>
<age>88</age>
<address>csww</address>
</student>
<student>
<name>王五</name>
<age>99</age>
<address>mm</address>
</student>
</students>
把student.xml 文件解析成一个个的String对象,如何做?
/**
* 把XML文件,解析成实体对象(Student)
* @author ljh
*
*/
public class DomParseXML {
public static List<Student> domParseXML(String str) {
List<Student> stus = new ArrayList<Student>();
try {
//从解析工厂获得具体的解析器builder
DocumentBuilder builder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
//解析文件(把XML文档解析成DOM模型[树模型,由节点组成])
Document document = builder.parse(str);//解析完,返回Document对象
//节点列表
NodeList nlist = document.getElementsByTagName("student");
System.out.println(nlist.getLength());//打印节点列表的长度
for (int i = 0; i < nlist.getLength(); i++) {
//通过节点名,获取节点的第一个子节点的值
String name = document.getElementsByTagName("name").item(i).getFirstChild().getNodeValue();
int age = Integer.parseInt(document.getElementsByTagName("age").item(i).getFirstChild().getNodeValue());
String address=document.getElementsByTagName("address").item(i).getFirstChild().getNodeValue();
Student st = new Student(name, age, address);//通过获取XML文件的温饱节点值,构造一个String对象
stus.add(st);//添加到学生列表
}
} 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();
}
return stus;
}
public static void main(String[] args) {
String str = "student.xml";//待解析文件,位于过程目录下
List<Student> list= domParseXML(str);//解析后,返回学生对象列表
for (Student student : list) {
System.out.println(student);//遍历打印输出
}
}
..DOM还可以把实体对象,解析成XML文件格式.................................
/**
* 把 实体对象(Student),写成XML文档
* @author ljh
*
*/
public class WriteXML {
public static void writeXML(){
Student[] stus = new Student[3];
stus[0]=new Student("张三", 11, "cs1");
stus[1]=new Student("李四", 21, "cs2");
stus[2]=new Student("王五", 29, "c3s");
Document document = null;
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//创建一个空白文档document,用于保存解析后的数据
document = builder.newDocument();
//创建根元素root
Element root = document.createElement("students");
for (int i = 0; i < stus.length; i++) {
Student stu=stus[i];
//创建根节点的下一级节点,即student
Element element = document.createElement("student");
//创建student节点的三个属性节点_name,_age,_address
Element _name = document.createElement("name");
//_name追加一个文本节点,设值为stu.getName()
_name.appendChild(document.createTextNode(stu.getName()));
Element _age = document.createElement("age");
_age.appendChild(document.createTextNode(stu.getAge()+""));
Element _address=document.createElement("address");
_address.appendChild(document.createTextNode(stu.getAddress()));
//student节点,把三个属性节点加上
element.appendChild(_name);
element.appendChild(_age);
element.appendChild(_address);
root.appendChild(element);//根节点追加此学生节点
}
//把root根节点,添加到整个文档
document.appendChild(root);
//还需转换
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer tf = tFactory.newTransformer();//转化器
tf.setOutputProperty("encoding", "UTF-8");//设置输出编码
DOMSource sourse = new DOMSource(document);//原对象文档
Result target = new StreamResult("text.xml");//解析到"text.xml"
tf.transform(sourse, target);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
writeXML();//解析后,刷新工程,将出现text.xml
}
....二:SAX解析[只能解析]...................................................
public class Student {
private String name;
private String sex;
private Set<Lesson> lessons;学生的课程(是个课程集合)
class Lesson {
private String lessonName;
private double lessonScore;
}
//..............
}
public class SAXDome {
/**
* @param args
*/
public static void main(String[] args) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
//用工厂,创建SAX解析器parser
SAXParser parser = factory.newSAXParser();
//创建 要解析的XML文档
InputStream is = new FileInputStream("student.xml");
MyHandler handler = new MyHandler();//这个类需要我们自己写
//解析器parser调用解析方法parse(is, handler)将XML文档交给handler解析
parser.parse(is, handler);
//遍历打印
Set<Student> Stuset = handler.getStudents();
for (Student st : Stuset) {
System.out.println(st);
System.out.println(".............................");
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 5个方法,遇到不同的标签,自动调用
*/
public class MyHandler extends DefaultHandler{
private Student student;
private Lesson lesson;
private Set<Student> students;
private Set<Lesson> lessons;
private String preTag; //用于记录前标签
public Set<Student> getStudents() {
return students;
}
public Set<Lesson> getLessons() {
return lessons;
}
@Override //文本节点(数据)解析成字符数组char[] ch
public void characters(char[] ch, int start, int length)
throws SAXException {
String data = new String(ch,start,length);
if("name".equals(preTag)){
student.setName(data);
}
if("sex".equals(preTag)){
student.setSex(data);
}
if("lessonName".equals(preTag)){
lesson.setLessonName(data);
}
if("lessonScore".equals(preTag)){
lesson.setLessonScore(Double.parseDouble(data));
}
}
@Override
public void endDocument() throws SAXException {
System.out.println("整个文档解析完成.........");
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if(student !=null && qName.equals("student")){
student.setLessons(lessons);
students.add(student);
student = null;
lessons = new HashSet<Lesson>();
}
if(lesson !=null && qName.equals("lesson")){
lessons.add(lesson);
lesson = null;
}
preTag = null;
}
@Override
public void startDocument() throws SAXException {
System.out.println("开始解析整个文档...........");
students = new HashSet<Student>();
lessons = new HashSet<Lesson>();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(qName.equals("student")){
student = new Student();
}
if(qName.equals("lesson")){
lesson = new Lesson();
}
preTag = qName;
}
}
<班级>
<学生 编号="A0001">
<姓名>张三</姓名>
<年龄>23</年龄>
<电子邮箱>zhangsan@163.com</电子邮箱>
<电子邮箱>zhangsan@yahoo.com</电子邮箱>
<身高>179.5</身高>
<电话>686868</电话>
<单位>
公司
<地址>上海</地址>
<邮编>100002</邮编>
</单位>
</学生>
<学生 编号="A0003">
<姓名>李四</姓名>
<年龄>24</年龄>
<电子邮箱>lisi@263.com</电子邮箱>
<身高>168.0</身高>
<手机>135013562554</手机>
<单位>
<地址>北京</地址>
</单位>
</学生>
<学生 编号="A0002">
<姓名>王五</姓名>
<年龄>21</年龄>
<电子邮箱>wangwu@163.com</电子邮箱>
<身高>179.5</身高>
<电话>686868</电话>
<单位>XXXX公司</单位>
</学生>
</班级>
XML的起源和目的
XML是Extensible Markup Language的缩写,即可扩展标记语言。它是一种用来创建的标记的标记语言。1996年,万维网协会(或者叫W3C,http://www.w3c.org)开始设计一种可扩展的标记语言,1998年2月,XML1.0成为了W3C的推荐标准。这种XML语言继承了SGML的规范,Standard Generalized Markup Language (SGML)是一种基于记号文本的语言。关于SGML语言,我们会在本章的扩展部分给大家介绍,另外XML还保持了对现有的面向SGML系统的向下兼容性。XML将SGML的灵活性和强大功能与已经被广泛采用的HTML结合起来,简化了计算机对文档和数据交换的处理,使得现有的协议和软件更为协调,从而简化了数据的处理和传输。
使用XML标记语言可以做到数据或数据结构在任何编程语言环境下的共享。例如我们在某个计算机平台上用某种编程语言编写了一些数据或数据结构,然后用XML标记语言进行处理,那样的话,其他人就可以在其他的计算机平台上来访问这些数据或数据结构,甚至可以用其他的编程语言来操作这些数据或数据结构了。这就是XML标记语言作为一种数据交换语言存在的价值。
XML数据解析
是将数据文档解析成不同的格式。因为不同平台(软件)在做数据传递或数据文档共享的时候,同一数据文档可能在不同平台的 显示格式要求不同,这就出现了相对中立的
语言(XML),来表示数据,给二者做转化。
常用的XML解析方式及各自特征
一:DOM(dom4,这种是标准的方式)
DOM 文档对象模型(w3c标准模型)[既能解析XML文档,也能把对象写成XML文件格式]
解析文档前,全部加载,转化为树模型。
DOM是HTML和XML文档的编程接口规范,它与平台和语言是无关的,因而可以用各种语言和在各种平台上实现。
DOM的原理简单的说,就是通过解析XML文档,为XML文档在逻辑上建立一个树模型,树的节点是一个个对象。我们通过存取这些对象就能够操作XML文档中的内容了。
用到的节点(节点都需要自己创建)
Document文档节点
Element元素节点
Text文本节点
Attr属性节点
DOM的优势主要表现在:易用性强,使用DOM时,将把所有的XML文档信息都存于内存中,并且遍历简单,支持XPath,增强了易用性。
DOM的缺点主要表现在:效率低,解析速度慢,内存占用量过高,对于大文件来说几乎不可能使用。另外效率低还表现在大量的消耗时间,因为使用DOM进行解析时,将为文档的每个element、attribute、processing-instrUCtion和comment都创建一个对象,这样在DOM机制中所运用的大量对象的创建和销毁无疑会影响其效率。
二:SAX解析:Simple API for XML
占内存小,难理解
加载一部分,解析一部分
顺序解析,基于事件驱动[只能解析]
1.文档开始 startDocument()
2.元素开始 startElement(String arg0, String arg1, String arg2,Attributes arg3)
3.文本characters(char[] arg0, int arg1, int arg2)
4.文本结束 endDocument()
5.元素结束 endElement
加载文档时,遇到不同标签,自动触发不同的事件,自动调用相应的5种处理方法(方法的具体实现自己编写),直到文档结束
SAX,既是指一种接口,也是指一个软件包。SAX最初是由David Megginson采用Java语言开发,之后SAX很快在Java开发者中流行起来。San现在负责管理其原始API的开发工作,这是一种公开的、开放源代码软件。不同于其他大多数XML标准的是,SAX没有语言开发商必须遵守的标准SAX参考版本。因此,SAX的不同实现可能采用区别很大的接口。
...使用详解..................................................................
一:DOM解析
//假设有实体对象Student类如下:
public class Student {
private String name;
private int age;
private String address;
//.构造及get/set方法此处省略........
}
//student.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name>张三</name>
<age>77</age>
<address>cs</address>
</student>
<student>
<name>蕾丝</name>
<age>88</age>
<address>csww</address>
</student>
<student>
<name>王五</name>
<age>99</age>
<address>mm</address>
</student>
</students>
把student.xml 文件解析成一个个的String对象,如何做?
/**
* 把XML文件,解析成实体对象(Student)
* @author ljh
*
*/
public class DomParseXML {
public static List<Student> domParseXML(String str) {
List<Student> stus = new ArrayList<Student>();
try {
//从解析工厂获得具体的解析器builder
DocumentBuilder builder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
//解析文件(把XML文档解析成DOM模型[树模型,由节点组成])
Document document = builder.parse(str);//解析完,返回Document对象
//节点列表
NodeList nlist = document.getElementsByTagName("student");
System.out.println(nlist.getLength());//打印节点列表的长度
for (int i = 0; i < nlist.getLength(); i++) {
//通过节点名,获取节点的第一个子节点的值
String name = document.getElementsByTagName("name").item(i).getFirstChild().getNodeValue();
int age = Integer.parseInt(document.getElementsByTagName("age").item(i).getFirstChild().getNodeValue());
String address=document.getElementsByTagName("address").item(i).getFirstChild().getNodeValue();
Student st = new Student(name, age, address);//通过获取XML文件的温饱节点值,构造一个String对象
stus.add(st);//添加到学生列表
}
} 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();
}
return stus;
}
public static void main(String[] args) {
String str = "student.xml";//待解析文件,位于过程目录下
List<Student> list= domParseXML(str);//解析后,返回学生对象列表
for (Student student : list) {
System.out.println(student);//遍历打印输出
}
}
..DOM还可以把实体对象,解析成XML文件格式.................................
/**
* 把 实体对象(Student),写成XML文档
* @author ljh
*
*/
public class WriteXML {
public static void writeXML(){
Student[] stus = new Student[3];
stus[0]=new Student("张三", 11, "cs1");
stus[1]=new Student("李四", 21, "cs2");
stus[2]=new Student("王五", 29, "c3s");
Document document = null;
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//创建一个空白文档document,用于保存解析后的数据
document = builder.newDocument();
//创建根元素root
Element root = document.createElement("students");
for (int i = 0; i < stus.length; i++) {
Student stu=stus[i];
//创建根节点的下一级节点,即student
Element element = document.createElement("student");
//创建student节点的三个属性节点_name,_age,_address
Element _name = document.createElement("name");
//_name追加一个文本节点,设值为stu.getName()
_name.appendChild(document.createTextNode(stu.getName()));
Element _age = document.createElement("age");
_age.appendChild(document.createTextNode(stu.getAge()+""));
Element _address=document.createElement("address");
_address.appendChild(document.createTextNode(stu.getAddress()));
//student节点,把三个属性节点加上
element.appendChild(_name);
element.appendChild(_age);
element.appendChild(_address);
root.appendChild(element);//根节点追加此学生节点
}
//把root根节点,添加到整个文档
document.appendChild(root);
//还需转换
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer tf = tFactory.newTransformer();//转化器
tf.setOutputProperty("encoding", "UTF-8");//设置输出编码
DOMSource sourse = new DOMSource(document);//原对象文档
Result target = new StreamResult("text.xml");//解析到"text.xml"
tf.transform(sourse, target);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
writeXML();//解析后,刷新工程,将出现text.xml
}
....二:SAX解析[只能解析]...................................................
public class Student {
private String name;
private String sex;
private Set<Lesson> lessons;学生的课程(是个课程集合)
class Lesson {
private String lessonName;
private double lessonScore;
}
//..............
}
public class SAXDome {
/**
* @param args
*/
public static void main(String[] args) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
//用工厂,创建SAX解析器parser
SAXParser parser = factory.newSAXParser();
//创建 要解析的XML文档
InputStream is = new FileInputStream("student.xml");
MyHandler handler = new MyHandler();//这个类需要我们自己写
//解析器parser调用解析方法parse(is, handler)将XML文档交给handler解析
parser.parse(is, handler);
//遍历打印
Set<Student> Stuset = handler.getStudents();
for (Student st : Stuset) {
System.out.println(st);
System.out.println(".............................");
}
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 5个方法,遇到不同的标签,自动调用
*/
public class MyHandler extends DefaultHandler{
private Student student;
private Lesson lesson;
private Set<Student> students;
private Set<Lesson> lessons;
private String preTag; //用于记录前标签
public Set<Student> getStudents() {
return students;
}
public Set<Lesson> getLessons() {
return lessons;
}
@Override //文本节点(数据)解析成字符数组char[] ch
public void characters(char[] ch, int start, int length)
throws SAXException {
String data = new String(ch,start,length);
if("name".equals(preTag)){
student.setName(data);
}
if("sex".equals(preTag)){
student.setSex(data);
}
if("lessonName".equals(preTag)){
lesson.setLessonName(data);
}
if("lessonScore".equals(preTag)){
lesson.setLessonScore(Double.parseDouble(data));
}
}
@Override
public void endDocument() throws SAXException {
System.out.println("整个文档解析完成.........");
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if(student !=null && qName.equals("student")){
student.setLessons(lessons);
students.add(student);
student = null;
lessons = new HashSet<Lesson>();
}
if(lesson !=null && qName.equals("lesson")){
lessons.add(lesson);
lesson = null;
}
preTag = null;
}
@Override
public void startDocument() throws SAXException {
System.out.println("开始解析整个文档...........");
students = new HashSet<Student>();
lessons = new HashSet<Lesson>();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if(qName.equals("student")){
student = new Student();
}
if(qName.equals("lesson")){
lesson = new Lesson();
}
preTag = qName;
}
}