第十四节 XML与JSON
1. XML简介
XML(可扩展标记语言),XML是一个以文本描述数据的文档。
一个XML文档示例
<?xml version="1.0" encoding="UTF-8">
<people>
<person personid="E01">
<name>Tony</name>
<address>10 Downing Street,London,UK</address>
<tel>(061)98765</tel>
<fax>(061)98765</fax>
<email>tony@everywhere.com</email>
</person>
</people>
2. XML的用途
XML技术的用途:
(1)充当显示数据(以XML充当显示层)
(2)存储数据(存储层)的功能
(3)以xml描述数据,并在服务器与系统的其余部分之间传递(传输数据的一种格式)
从某种角度上讲,xml是一种数据封装和消息传递技术
3. SAX解析XML
SAX是Simple API for XML的缩写
SAX是读取和操作XML数据更快速、更轻量的方法。SAX允许您在读取文档时处理它,从而不必等待整个文档 被存储下来之后才采取操作。它不涉及DOM所必须的开销和概念跳跃。SAX API是一个基于事件的API,适用于处理数据流,即随着数据的流动而依次处理数据。SAX API在其解析您的文档时发生一定事件的时候会通知您,在您对其响应时,您不作保存的数据将会被抛弃。
SAX API中主要有四种处理事件的接口,它们分别是ContentHandler,DTDHandler,EntityResolver和ErrorHandler。实际上只需继承DefaultHandler类就可以,DefaultHandler实现了这四个事件处理器接口,然后提供了每个抽象方法的默认实现。
//创建SAX解析器工厂对象
SAXParserFactory spf=SAXParserFactory.newInstance();
//使用解析器工厂创建解析器实例
SAXParser saxParser=spf.newSAXParser();
//创建SAX解析器要使用的事件侦听器对象(这个对象需要我们自己来创建要继承DefaultHandler)
PersonHandler handler=new PersonHandler();
//开始解析文件
saxParser.parse(new File(fileName),handler);
利用SAX去解析xml的案例:
<people>
<person personid="E01">
<name>Tony</name>
<address>10 Downing Street,London,UK</address>
<tel>(061)98765</tel>
<fax>(061)98765</fax>
<email>tony@everywhere.com</email>
</person>
</people>
public class Person {
public void setPersonid(String personid) {
this.personid = personid;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public void setTel(String tel) {
this.tel = tel;
}
public void setFax(String fax) {
this.fax = fax;
}
public void setEmail(String email) {
this.email = email;
}
private String personid;
private String name;
private String address;
private String tel;
private String fax;
private String email;
public String getPersonid() {
return personid;
}
@Override
public String toString() {
return "Person{" +
"personid='" + personid + '\'' +
", name='" + name + '\'' +
", address='" + address + '\'' +
", tel='" + tel + '\'' +
", fax='" + fax + '\'' +
", email='" + email + '\'' +
'}';
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public String getTel() {
return tel;
}
public String getFax() {
return fax;
}
public String getEmail() {
return email;
}
}
public class XMLDemo {
@Test
public void saxParseXML() throws IOException, SAXException, ParserConfigurationException {
//1.创建一个SAX解析器工厂对象
SAXParserFactory saxParserFactory=SAXParserFactory.newInstance();
//2.创建一个SAX解析器
SAXParser saxParser = saxParserFactory.newSAXParser();
//3.创建解析器处理对象(需要自己编写)
PersonHandler personHandler=new PersonHandler();
//根据上下文获取输入流
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("person.xml");
//进行解析
saxParser.parse(is,personHandler);
List<Person> persons=personHandler.getPersons();
for (Person p:persons){
System.out.println(p);
}
}
}
public class PersonHandler extends DefaultHandler {
/**
* SAX解析的特点:
* 1.基于事件驱动
* 2.顺序读取,速度快
* 3.不能任意的读取节点(灵活性差)
* 4.解析时占用的内存小(不会出现内存溢出的情况
* 5.SAX更适用于在性能要求更高的设备上使用(例如:Android开发中)
*/
private List<Person> persons=null;
private Person p;//当前正在解析的Person
private String tag;//用于记录当前正在解析的标签名
public List<Person> getPersons() {
return persons;
}
//开始解析文档时调用
@Override
public void startDocument() throws SAXException {
super.startDocument();
persons=new ArrayList<>();
System.out.println("开始解析文档.....");
}
//在解析结束的时候调用
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("解析文档结束....");
}
//解析开始元素(标签)时调用
/**
* @param uri 命名空间
* @param localName 不带前缀的标签名
* @param qName 带前缀的标签名
* @param attributes 当前标签的属性集合
* @throws SAXException
* */
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if("person".equals(qName)){
p=new Person();
String personid=attributes.getValue("personid");
p.setPersonid(personid);
}
tag=qName;
}
//解析结束元素(标签)时调用
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if("person".equals(qName)){
persons.add(p);
}
tag=null;
}
//解析文本内容时调用
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
if(tag!=null){
if("name".equals(tag)){
p.setName(new String(ch,start,length));
}else if("address".equals(tag)){
p.setAddress(new String(ch,start,length));
}else if("tel".equals(tag)){
p.setTel(new String(ch,start,length));
}else if("email".equals(tag)){
p.setEmail(new String(ch,start,length));
}else if("fax".equals(tag)){
p.setFax(new String(ch,start,length));
}
}
}
}
在进行传输的时候尽量的将xml文件弄到一行去,因为减少解析次数,同时缩小文件大小。
4.DOM解析XML
Java解析XML通常有两种方式,DOM和SAX
DOM:文档对象模型
DOM特性:
定义一组Java接口,基于对象,与语言和平台无关将XML文档表示为树,在内存中解析和存储XML文档,允许随机访问文档的不同部分。
DOM解析XML:
DOM优点,由于树在内存中是持久的,因此可以修改后更新。它还可以在任何时候在树中上下导航,API使用起来也比较简单。
解析步骤:
DocumentBuilderFactory builder=DocumentBuilderFactory.newInstance();
DocumentBuilder db=builder.newDocumentBuilder();
db.parse(“person.xml”);
NodeList node_person=doc.getElementsByTagName(“person”);
示例:
/**
* DOM解析XML
* 1.基于树形结构,通过解析器一次性把文档加载到内存中,所以会比较占内存,可以随机访问
* 更加灵活,更适合在WEB开发中使用
*/
@Test
public void domParseXML() throws ParserConfigurationException, IOException, SAXException {
//1.创建一个DOM解析器工厂对象
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
//2.通过工厂创建解析器对象
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
//3.解析文档
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("person.xml");
//此代码完成后,整个xml文档已经被加载到内存中,以树状存储在内存中
Document doc = documentBuilder.parse(is);
//4.从内存中读取数据
//获取节点名称为person的所有节点,返回节点集合
NodeList personNodeList = doc.getElementsByTagName("person");
ArrayList<Person> persons=new ArrayList<>();
Person p=null;
for(int i=0;i<personNodeList.getLength();i++){
Node personNode = personNodeList.item(i);
p=new Person();
//获取节点的属性值
String personid = personNode.getAttributes().getNamedItem("personid").getNodeValue();
p.setPersonid(personid);
//获取当前节点的子节点
NodeList childNodes = personNode.getChildNodes();
for(int j=0;j<childNodes.getLength();j++){
Node item = childNodes.item(j);
String nodeName = item.getNodeName();
if("name".equals(nodeName)){
p.setName(item.getFirstChild().getNodeValue());
}else if("address".equals(nodeName)){
p.setAddress(item.getFirstChild().getNodeValue());
}else if("tel".equals(nodeName)){
p.setTel(item.getFirstChild().getNodeValue());
}else if("email".equals(nodeName)){
p.setEmail(item.getFirstChild().getNodeValue());
}else if("fax".equals(nodeName)){
p.setFax(item.getFirstChild().getNodeValue());
}
}
persons.add(p);
}
System.out.println("结果:");
System.out.println(Arrays.toString(persons.toArray()));
}
这里的Person类和person.xml与上面的SAX的一样。
5. JDOM解析XML
JDOM是两位著名的Java开发人员兼作者,Brett Mclaughlin和Jason Hunter的创作成果,
2000年初在类似于Apache协议的许可下,JDOM作为一个开源代码项目正式开始研发了。
JDOM简化了与XML的交互并且比使用DOM实现更快,JDOM与DOM主要两方面不同。
首先,JDOM仅使用具体类而不使用接口。这在某些方面简化了API,但是也限制了灵活性。第二,API大量使用了Collections类,简化了那些已经熟悉这些类的Java开发者的使用。
下载地址:http://www.jdom.org/downloads/index.html
使用示例:
/**
* 使用JDOM解析XML
* 1. 与DOM类似,都是基于树型结构
* 2.与DOM的区别:
* (1)使用第三方开源的组件
* (2)实现使用Java的Collections接口
* (3)效率比DOM更快
*/
@Test
public void jdomParseXML() throws Exception {
//1. 创建JDOM解析器
SAXBuilder builder=new SAXBuilder();
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("person.xml");
org.jdom2.Document build = builder.build(is);
Element rootElement = build.getRootElement();
List<Person> list=new ArrayList<>();
Person person=null;
List<Element> children = rootElement.getChildren();
for(Element element:children){
Person p=new Person();
String personid = element.getAttribute("personid").getValue();
p.setPersonid(personid);
List<Element> children1 = element.getChildren();
for(Element e:children1){
String tag = e.getName();
if("name".equals(tag)){
person.setName(e.getText());
}else if("address".equals(tag)){
person.setAddress(e.getText());
}else if("tel".equals(tag)){
person.setTel(e.getText());
}else if("fax".equals(tag)){
person.setFax(e.getText());
}else if("email".equals(tag)){
person.setEmail(e.getText());
}
}
list.add(person);
}
System.out.println("结果:");
System.out.println(Arrays.toString(list.toArray()));
}
6. DOM4J 解析XML
dom4j是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在对主流的Java XML API进行的性能、功能和易用性的评测,dom4j无论在哪方面都是非常出色的。如今你可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这是必须使用的jar包,Hibernate用它来读写配置文件。
示例如下:
/**
* 使用DOM4J
* 1.基于树型结构,第三方组件
* 2.解析速度快,效率更高,使用JAVA中的迭代器来实现数据读取,在WEB框架中使用较多(比如Hibernate)
*
*/
@Test
public void dom4jParseXML() throws DocumentException {
//创建DOM4J的解析器对象
SAXReader reader=new SAXReader();
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("person.xml");
org.dom4j.Document doc = reader.read(is);
org.dom4j.Element rootElement = doc.getRootElement();
Iterator<Element> iterator = rootElement.elementIterator();
ArrayList<Person> person = new ArrayList<>();
Person p=null;
while (iterator.hasNext()){
p=new Person();
org.dom4j.Element e= (org.dom4j.Element) iterator.next();
p.setPersonid(e.attributeValue("personid"));
Iterator<org.dom4j.Element> iterator1 = e.elementIterator();
while (iterator1.hasNext()){
org.dom4j.Element element = iterator1.next();
String tag = element.getName();
if("name".equals(tag)){
p.setName(element.getText());
}else if("address".equals(tag)){
p.setAddress(element.getText());
}else if("tel".equals(tag)){
p.setTel(element.getText());
}else if("fax".equals(tag)){
p.setFax(element.getText());
}else if("email".equals(tag)){
p.setEmail(element.getText());
}
}
person.add(p);
}
System.out.println("结果:");
System.out.println(Arrays.toString(person.toArray()));
}
7. 通过对象生成XML文件
根据对象生成xml文档:
使用java提供的java.beans.XMLEncoder和java.beans.XMLDecoder类。
这是JDK1.4以后才出现的类
步骤:
(1)实例化XML编码器
XMLEncoder xmlEncoder=new XMLEncoder(new BufferedOutputStream(new FileOutputStream(new File(“a.xml”))));
(2)输出对象
(3)关闭
示例如下:
/**
* 从xml文件中读取对象
*
*/
@Test
public void xmlDecoder() throws FileNotFoundException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("test.xml")));
XMLDecoder decoder=new XMLDecoder(bis);
Person person = (Person)decoder.readObject();
System.out.println(person);
}
/**
* 把对象转成XML文件写入
*/
@Test
public void xmlEncoder() throws FileNotFoundException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("test.xml")));
XMLEncoder xmlEncoder = new XMLEncoder(bos);
Person p=new Person();
p.setPersonid("1110");
p.setName("liushuai");
p.setTel("99999");
p.setEmail("19134189@qq.com");
p.setFax("0234-899");
p.setAddress("He Nan Finance university");
xmlEncoder.writeObject(p);
xmlEncoder.close();
}
8. 各种解析方法比较
JDOM和DOM在性能测试时表现不佳,在测试10M文档时内存溢出。
SAX表现较好,这要依赖于它特定的解析方式。一个SAX检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。
DOM4J是这场测试的获胜者,目前许多开源项目中,大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。
xstream实现XML的转换:
需要下载两个Jar包,一个是xstream-1.4.2.jar另一个是xxp3_min-1.1.4c.jar
下载地址:http://x-stream.github.io/download.html
使用示例:
/**
* 使用第三方的xstream实现XML解析与生成
* xstream常用于服务器传输的时候使用,而前面讲的SAX,DOM,JDOM,DOM4J等一般
* 是用来进行解析配置文件用,那样比较灵活的获取我们想要的数据,进行过滤
*
*/
@Test
public void xStream(){
Person p=new Person();
p.setPersonid("1110");
p.setName("liushuai");
p.setTel("99999");
p.setEmail("19134189@qq.com");
p.setFax("0234-899");
p.setAddress("He Nan Finance university");
XStream xStream = new XStream(new Xpp3Driver());
//取一个别名
xStream.alias("Person",Person.class);
//将一个字段作为属性
xStream.useAttributeFor(Person.class,"personid");
String xml = xStream.toXML(p);
System.out.println(xml);
//解析XML
Person person = (Person)xStream.fromXML(xml);
}
9. JSON简介
JSON是一种轻量级的数据交换格式。JSON官方:http://www.json.org
JSON数据格式的特点
JSON建构于两种结构:
1.“名称/值对”的集合
2.值的有序列表(数组)
JSON表示名称/值对的方式:{“firstName”:“vince”,“lastName”:“ma”,“email”:“finally_m@foxmail.com”}
表示数组
{“user”:[{“firstName”:“vince”,“lastName”:“ma”,“email”:“finally_m@foxmail.com”},{“firstName”:“lin”,“lastName”:“jacks”,“email”:“jacks@qq.com”}]}
10. GSON组件的使用
GSON是Google开发的API,用于转换Java对象和Json对象
下载地址:http://www.mvnrepository.com/artifact/com.google.code.gson/gson
解析JSON:JsonReader reader=new JsonReader(new StringReader(jsonData));
使用示例:
//names.json文件
[
{"firstName":"vince","lastName":"ma","email":"finally_m@foxmail.com"},
{"firstName":"lin","lastName":"jacks","email":"jacks@qq.com"}]
//Name对象
public class Name {
private String firstName;
private String lastName;
private String email;
@Override
public String toString() {
return "Name{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
'}';
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
}
//解析JSON文件
public class JSONDome {
/**
* 解析一个JSON数组
*/
@Test
public void parseJSONNames(){
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("xmlandjson/names.json");
InputStreamReader in=new InputStreamReader(is);
//JSON的解析工具(可以理解为解析器)
JsonReader reader=new JsonReader(in);
ArrayList<Name> list=new ArrayList<>();
try {
//开始解析数组
reader.beginArray();
while (reader.hasNext()){
list.add(parseName(reader));
}
//结束解析数组
reader.endArray();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(Arrays.toString(list.toArray()));
}
//解析对象Name
private Name parseName(JsonReader jsonReader) throws IOException {
Name name=null;
//开始解析Name对象
jsonReader.beginObject();
name=new Name();
while (jsonReader.hasNext()){
String attr = jsonReader.nextName();
if("firstName".equals(attr)){
name.setFirstName(jsonReader.nextString());
}else if("lastName".equals(attr)){
name.setLastName(jsonReader.nextString());
}else if("email".equals(attr)){
name.setEmail(jsonReader.nextString());
}
}
jsonReader.endObject();
return name;
}
}
解析复杂的JSON文件
示例如下:
//message.json文件
[
{
"id": 912345678901,
"text": "How do I read a JSON stream in Java?",
"geo": null,
"user": {
"name": "json_newb",
"followers_count": 41
}
},
{
"id": 912345678902,
"text": "@json_newb just use JsonReader!",
"geo": [50.454722, -104.606667],
"user": {
"name": "jesse",
"followers_count": 2
}
}
]
public class User {
private String name;
private int followers_count;
public void setName(String name) {
this.name = name;
}
public void setFollowers_count(int followers_count) {
this.followers_count = followers_count;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", followers_count=" + followers_count +
'}';
}
public String getName() {
return name;
}
public int getFollowers_count() {
return followers_count;
}
}
public class Message {
private long id;
private String text;
@Override
public String toString() {
return "Message{" +
"id=" + id +
", text='" + text + '\'' +
", geo=" + geo +
", user=" + user +
'}';
}
private ArrayList<Double> geo;
private User user;
public Message(){
}
public Message(long id, String text, ArrayList<Double> geo, User user) {
this.id = id;
this.text = text;
this.geo = geo;
this.user = user;
}
public void setId(long id) {
this.id = id;
}
public void setText(String text) {
this.text = text;
}
public void setGeo(ArrayList<Double> geo) {
this.geo = geo;
}
public void setUser(User user) {
this.user = user;
}
public long getId() {
return id;
}
public String getText() {
return text;
}
public ArrayList<Double> getGeo() {
return geo;
}
public User getUser() {
return user;
}
}
public class JSONDemo02 {
@Test
public void parseJSONMessages() throws IOException {
//第一步:拿到文件
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("xmlandjson/message.json");
//将字节流转换为字符流
InputStreamReader in=new InputStreamReader(is);
//构造JsonReader对象
JsonReader jsonReader = new JsonReader(in);
ArrayList<Message> list = readMessageArray(jsonReader);
for (Message m:list){
System.out.println(m);
}
}
//读取Message数组
private ArrayList<Message> readMessageArray(JsonReader jsonReader) throws IOException {
ArrayList<Message> list = new ArrayList<>();
jsonReader.beginArray();
while (jsonReader.hasNext()){
list.add(readMessage(jsonReader));
}
return list;
}
//解析一个Message对象
private Message readMessage(JsonReader jsonReader) throws IOException {
Message m=new Message();
jsonReader.beginObject();
while (jsonReader.hasNext()){
String name = jsonReader.nextName();
if("id".equals(name)){
m.setId(jsonReader.nextLong());
}else if("text".equals(name)){
m.setText(jsonReader.nextString());
//如果geo为空就不设置了
}else if("geo".equals(name)&&jsonReader.peek()!= JsonToken.NULL){
m.setGeo(readerGeo(jsonReader));
}else if("user".equals(name)){
m.setUser(readUser(jsonReader));
}else{
jsonReader.skipValue();
}
}
jsonReader.endObject();
return m;
}
//解析User对象
private User readUser(JsonReader jsonReader) throws IOException {
User u=new User();
jsonReader.beginObject();
while (jsonReader.hasNext()){
String tag = jsonReader.nextName();
if("name".equals(tag)){
u.setName(jsonReader.nextString());
}else if("followers_count".equals(tag)){
u.setFollowers_count(jsonReader.nextInt());
}else{
jsonReader.skipValue();
}
}
jsonReader.endObject();
return u;
}
private ArrayList<Double> readerGeo(JsonReader jsonReader) throws IOException {
//解析Message里面的Geo
ArrayList<Double> list=new ArrayList<>();
jsonReader.beginArray();
while (jsonReader.hasNext()){
list.add(jsonReader.nextDouble());
}
jsonReader.endArray();
return list;
}
}
生成JSON:
@Test
public void createJSON(){
List<Name> list=new ArrayList<>();
list.add(new Name("vince","ma","1223455@qq.com"));
list.add(new Name("jack","wang","123456@qq.com"));
JsonArray array=new JsonArray();
for (Name n:list){
JsonObject obj=new JsonObject();
obj.addProperty("firstName",n.getFirstName());
obj.addProperty("lastName",n.getLastName());
obj.addProperty("email",n.getEmail());
array.add(obj);
}
System.out.println(array.toString());
}
使用Gson直接把JSON数据转换成Java对象,或者把Java对象转换成JSON对象
//把一个Java对象转换成JSON对象或者把一个JSON对象转换成Java
public Name parseJSON2(String data){
Gson gson=new Gson();
Name name=gson.fromJson(data,Name.class);
return name;
}
@Test
//将json中单个转换为对象
public Name parseJSON2(){//参数可以为String data
Gson gson=new Gson();
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("xmlandjson/names.json");
InputStreamReader in=new InputStreamReader(is);
Name name = gson.fromJson(in, Name.class);
// Name name=gson.fromJson(data,Name.class);
System.out.println(name.toString());
return name;
}
//把一个Java对象转换成JSON对象
Gson gson=new Gson();
String json=gson.toJson(new Name("shuai","liu","1234@qq.com"));
System.out.println(json);
使用Gson直接把JSON数组转换成Java对象,或者把多个Java对象转换成JSON数组
@Test
//将json数组转换成对象
public List<Name> parseJSON3(){//参数可以为String data
Type type=new TypeToken<ArrayList<Name>>(){}.getType();
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("xmlandjson/names.json");
InputStreamReader in=new InputStreamReader(is);
Gson gson=new Gson();
List<Name> list=gson.fromJson(in,type);//这里的in可以是Reader,也可以是String data
System.out.println(Arrays.toString(list.toArray()));
return list;
}
//把一个Java对象集合转换成JSON数组
List<Name> list=new ArrayList<>();
list.add(new Name("mingan","hua","11111@qq.com"));
list.add(new Name("qingpeng","liu","3333@qq.com");
Gson gson=new Gson();
String json=gson.toJson(list,typeToken.getType());
System.out.println(json);
11. XML与JSON的比较
通过以下六点比较JSON和XML:
(1)JSON和XML的数据可读性基本相同
(2)JSON和XML同样拥有丰富的解析手段
(3)JSON相对于XML,数据的体积小
(4)JSON与JavaScript的交互更加的方便
(5)JSON对数据的描述性,比XML差
(6)JSON的速度要远比XML快
适合的场景:
(1)数据传输的话:JSON要比XML更有优势
(2)存储数据:XML描述性更强
(3)XML通常用作配置文件(WEB)