您的位置:首页 > 编程语言 > Java开发

XML文档基本认识和基于JAVA对简单解析

2017-06-18 20:37 561 查看
在实际项目中我们经常会需要用到垮平台通讯的情况,支持跨平台通讯的技术很多,用到的通讯使用的文本格式也很多,例如JSON和XML等。在这里浅谈下对XML的认识和简单的解析。

XML:可扩展的标记语言;Extend Markup Language,是以标记和子标记的方法描述对象,集合。

例如我们现在有这么一个实体类

public class Stutent {

private int id;
private String name;
private String sex;

}


那么我们用XML文件可以这么表示

<?xml version="1.0" encoding="utf-8"?>
<Students>
<student id="1">
<name>张三</name>
<sex>男</sex>
</student>

<student id="2">
<name>李四</name>
<sex>女</sex>
</student>

<student id="3">
<name>王五</name>
<sex>男</sex>
</student>

</Students>


一个标准的XML的组成格式

–version –文档符合XML 1.0规范,现在只有1.0

–encoding– 文档字符编码,默认为“UTF-8”

– standalone– 文档定义是否在一个文件内(没有DTD可以不定义)

* stanalond="yes"
* stanalone="no"


<?xml version="1.0" encoding="utf-8" stanalone="no">


standalone 定义了外部定义的 DTD 文件的存在性,no 表示这个 XML 文档不是独立的而是依赖于外部所定义的一个 DTD. 值 yes 表示这个 XML 文档是自包含的(self-contained)

XML中的空元素,表示标签直接没有内容。例如现在我们的XML中有money这么个元素

<money></money>

<money?>


XML根元素

* 每个XML文档必须有有且只有一个根元素
* 根元素是一个完全包括文档中的其他素有元素的元素
* 所有元素都必须在根元素中定义


XML有严格的格式要求,对大小写和符号敏感,在XML中有有5个特殊符号需要转义

需要注意的是:

1. 转义序列各字符间不能有空格;

2. 转义序列必须以”;”结束;

3. 单独的&不被认为是转义开始;

4. 区分大小写。

&(逻辑与)  &
<(小于)    <
>(大于)    >
"(双引号)  "
'(单引号)  '


如果不想用转义符,也可以使用CDATA标签,CDATA是不被解析的文件。文本内的标签不会被当做标记,实体不会被展开。

<![CDATA[
**********************
]]>


结构完整的XML文档

满足XML基本的语法规则,如果XMML文档不是良好的格式,就不能被引用程序和游览器正确识别和解析

语法规范

1. 必须有XML声明语句

<?xml version="1.0" encoding="utf-8"?>


2.必须有且只有一个根元素

3.标记大小写敏感

4. 属性值需用引号

5. 标记成对

6. 空标记记得关闭

7. 元素正确嵌套

有效的XML

有效的XML除了要满足XML规范外,还要满足相应的DTD和Schema定义的元素规则

有效的XML一定是格式良好的,但是格式良好的XML不一定是有效的

DTD

<?xml version="1.0" encoding="GB2312" ?>
<!DOCTYPE 家庭 [                <!--DOCTYPE定义根元素:家庭-->
<!ELEMENT 家庭 (人+,家电*)>   <!--ELEMENT表示描述元素:()表示定义元素的子元素-->
<! ELEMENT 人 (#PCDATA)>     <!--#PCDATA表示"人"元素,标签中间的内容为文本-->
<!ELEMENT 家电 EMPTY>          <!--EMPTY表示"家电"元素为空元素-->
<!ATTLIST 人               <!--ATTLIST 表示定义元素的属性>
名字 CDATA #REQUIRED     <!--CDATA 表示属性的内容为文本-->
性别 (男|女) #REQUIRED     <!--#REQUIRED表示该属性必须书写-->
年龄 CDATA #REQUIRED
爱好 CDATA #IMPLIED          <!--#IMPLIED表示该属性可有可无-->
>
<!ATTLIST 家电
名称 CDATA #REQUIRED
数量 CDATA #REQUIRED
说明 CDATA #IMPLIED
>
]>


XML的解析技术有很多种这里只列举了两种

XML解析技术

文档对象模型(DOM),一种基于树结构的API

DOM解析

1.基于树状结构的API

2.整个XML文档必须在内存中解析和存储

3.客户端引用程序就可以随机访问这些对象

4. 大型文档为造成内存紧张

XML简单(SAX),一种事件驱动API

SAX

1.SAX提供一种用于解析XML文档的事件驱动模型

2.使用回调机制将事件通知应用程序

特点

1. 不必将整个文件加载到内存中,占用内存少

2. 不能对文档进行随机访问

3. SAX是只读的

4. 文档只能遍历一次

下面就基于SAX做一个简单的XML解析,这里我们用的dom4j这个jar来做解析

需要的jar



XML对应的实体Bean

package com.lovo.beans;

import java.io.Serializable;

/**
* 测试用简单商品类
* @author WZH
*
*/
public class Product implements Serializable{

private static final long serialVersionUID = 5801648617772990983L;

//商品id
private Long id;
//商品名
private String name;
//商品价格
private double price;
//厂商
private String factory;

public Product() {
super();
// TODO Auto-generated constructor stub
}

public Product(Long id, String name, double price, String factory) {
super();
this.id = id;
this.name = name;
this.price = price;
this.factory = factory;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public String getFactory() {
return factory;
}

public void setFactory(String factory) {
this.factory = factory;
}

@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price
+ ", factory=" + factory + "]";
}

}


一个简单的XML文件

<?xml version="1.0" encoding="utf-8"?>
<shopping>
<product code="1">
<name>薯片</name>
<price>15</price>
<factory>乐事</factory>
</product>
<product code="2">
<name>可乐</name>
<price>3</price>
<factory>可口可乐</factory>
</product>
</shopping>


读取并解析现有XML或XML字符串的简单方法

/**
* 读取并解析XML文件方法
* @param xmlUrl 如果是读取本地工程文件使用此参数传入文件路径
* @param xml  如果是传入xml字符串使用此参数
* @return 解析后的XML字符串
*/
public List<Product> readXML(String xmlUrl, String xml) {

List<Product> list=new ArrayList<Product>();
FileInputStream inXml = null;
Document doc = null;

// 判断为需解析的XML为本地文件或xml字符串
try {

if (xmlUrl !=null && !("".equals(xmlUrl))) {
inXml = new FileInputStream(new File(xmlUrl));
SAXReader saxReader = new SAXReader();
// xml文档对应实体文档
doc = saxReader.read(inXml);

}
if (xml !=null &&!("".equals(xml))) {
// 将xml格式字符串转化为DOM对象
doc = DocumentHelper.parseText(xml);
}

//获取shopping根元素下所有子元素
List<Element> elementList=doc.selectNodes("//shopping/product");

//以直接通过标签获取到XML的值
for (Element em : elementList) {
Product temp=new Product();
//得到product标签的属性
temp.setId(Long.parseLong(em.attributeValue("code")));
//获取标签内文本值的方法
temp.setName(em.elementText("name"));
temp.setPrice(Double.parseDouble(em.elementText("price")));
temp.setFactory(em.elementText("factory"));
list.add(temp);
}

} catch (Exception e) {
e.printStackTrace();

} finally {
try {

if(inXml != null){
inXml.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}

return list;

}


测试

public static void main(String[] args) {
XMLUtils util = new XMLUtils();

String src = "C:/shopping.xml";
System.out.println("------读取XML文件并解析-------");
System.out.println(util.readXML(src, null));

String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<shopping><product code='1'>"
+ "<name>老坛酸菜</name><"
+ "price>3.5</price>"
+ "<factory>统一</factory>"
+ "</product><product code='2'>"
+ "<name>加多宝</name>"
+ "<price>6</price>"
+ "<factory>加多宝</factory>"
+ "</product>"
+ "</shopping>";
System.out.println("------读取XML格式字符串并解析-------");
System.out.println(util.readXML(null, xml));

}


控制台输出结果



创建一个XML文件,个人感觉这个方法貌似并没有多大用,因为格式一般都是写好了,存成文件或者在数据库中的。

/**
* 创建一个XML实体文件的方法
* @param products 商品集合
* @param fileName 文件名
* @param src 文件保存地址
* @return true 创建成功,false 创建失败
*/
public boolean createXMLFile(List<Product> products,String fileName,String src){

//默认创建成功
boolean flag = true;
try {
//创建document对象
Document document = DocumentHelper.createDocument();
//创建根节点
Element shoppingtElement = document.addElement("shopping");
//加入一行注释
shoppingtElement.addComment("这是一个商品的XML");
//循环添加商品子节点
for(int i = 0;i < products.size(); i++){
//为shipping加入一个子节点
Element product = shoppingtElement.addElement("product");
//为product添加一个code属性
product.addAttribute("code", String.valueOf(products.get(i).getId()));
//为product添加子节点
Element name = product.addElement("name");
Element price = product.addElement("price");
Element factory = product.addElement("factory");
//给节点添加文本内容
name.setText(products.get(i).getName());
price.setText(String.valueOf(products.get(i).getPrice()));
factory.setText(products.get(i).getFactory());
}

//生成XML文件
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
//判断保存目录是否存在
File path = new File(src);
if(!path.exists()){
path.mkdirs();
System.out.println("-----文件目录不存在,创建对应目录------------");
}

File xmlFile = new File(src+"\\"+fileName+".xml");
XMLWriter writer = new XMLWriter(new FileOutputStream(xmlFile), format);
writer.write(document);
writer.flush();
writer.close();

} catch (Exception e) {
e.printStackTrace();
flag = false;
}
return flag;

}


测试

public static void main(String[] args) {
XMLUtils util = new XMLUtils();
List<Product> list=new ArrayList<Product>();
list.add(new Product(1L, "电脑", 7000, "联想"));
list.add(new Product(2L, "手机", 6800, "苹果"));
list.add(new Product(3L, "电视", 75000, "索尼"));
System.out.println(util.createXMLFile(list, "test", "c:\\test"));

}


运行结果,成功生成了一个test.xml





其实也可以直接用字符串拼接的方式实现新增一个XML,然后用

Document document = DocumentHelper.parseText(xmlStr)方法把他转换为document对象输出成XML文件就可以了

修改一个现有的XML的方法,在实际的项目中,XML文件格式经常会以字符串的形式存在数据库中,这里我们以这种条件为前提,写个简单的方法,当传入一个XML字符串时,怎么实现修改

/**
* 根据XML字符串创建一个实体XML文件
* @param products 商品集合
* @param fileName 文件名
* @param src 文件保存地址
* @param xmlStr 传入的xml格式文件
* @return true 创建成功,false 创建失败
*/
public boolean createXMLByStr(List<Product> products,String fileName,String src,String xmlStr){
//默认转换成功
boolean flag = true;
try {
//获取document对象
Document document = DocumentHelper.parseText(xmlStr);
//获取shopping根元素下所有子元素
List<Element> elementList=document.selectNodes("//shopping/product");
if(products.size() > 0){
//模板中已经存在一条空白的标签,这里这么写是为了展现修改方法
Element em = elementList.get(0);
em.addAttribute("code", String.valueOf(products.get(0).getId()));
em.element("name").setText(products.get(0).getName());
em.element("price").setText(String.valueOf(products.get(0).getPrice()));
em.element("factory").setText(products.get(0).getFactory());

}
//如果超过一条数据需要向XML追加节点
if(products.size() > 1){
//获取product节点上级父节点
Element em = elementList.get(0).getParent();
//循环添加商品子节点
for(int i = 1;i < products.size(); i++){
//为shipping加入一个子节点
Element product = em.addElement("product");
//为product添加一个code属性
product.addAttribute("code", String.valueOf(products.get(i).getId()));
//为product添加子节点
Element name = product.addElement("name");
Element price = product.addElement("price");
Element factory = product.addElement("factory");
//给节点添加文本内容
name.setText(products.get(i).getName());
price.setText(String.valueOf(products.get(i).getPrice()));
factory.setText(products.get(i).getFactory());
}
}

//生成XML文件
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
//判断保存目录是否存在
File path = new File(src);
if(!path.exists()){
path.mkdirs();
System.out.println("-----文件目录不存在,创建对应目录------------");
}

File xmlFile = new File(src+"\\"+fileName+".xml");
XMLWriter writer = new XMLWriter(new FileOutputStream(xmlFile), format);
writer.write(document);
writer.flush();
writer.close();

} catch (Exception e) {
e.printStackTrace();
flag = false;
}

return flag;

}


测试

public static void main(String[] args) {
XMLUtils util = new XMLUtils();
List<Product> list=new ArrayList<Product>();
list.add(new Product(1L, "电脑", 6666, "联想"));
list.add(new Product(2L, "手机", 7777, "苹果"));
list.add(new Product(3L, "电视", 8888, "索尼"));

String xml = "<?xml version='1.0' encoding='utf-8'?>"
+ "<shopping><product>"
+ "<name></name><"
+ "price></price>"
+ "<factory></factory>"
+ "</product>"
+ "</shopping>";
System.out.println(util.createXMLByStr(list, "test", "c:\\test",xml));

}


运行结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  xml java 跨平台 文档