XML文档基本认识和基于JAVA对简单解析
来源:互联网 发布:数据汇集平台 编辑:程序博客网 时间:2024/06/06 00:06
在实际项目中我们经常会需要用到垮平台通讯的情况,支持跨平台通讯的技术很多,用到的通讯使用的文本格式也很多,例如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对简单解析
- Java对xml文件的读取并解析的基本认识
- Java对XML文档进行解析
- Java对XML文档进行解析---实例
- java--JAXP对xml文档的解析
- Java对XML文档进行解析(JAXP-DOM解析)
- Java对XML文档进行解析(SAX、StAX解析)
- Java对XML文档进行解析(dom4j解析)
- Java解析XML文档
- JAVA 解析XML文档
- java解析xml文档
- Java解析XML文档
- java解析xml文档
- Java解析XML文档
- java解析xml文档
- java使用sax对xml文档的解析
- java--DOM对xml文档的解析1
- java--DOM4j-SAXReader对xml文档的解析2
- Redis为什么使用单进程单线程方式也这么快?
- 考研之南京大学软件学院
- Python中装饰器的总结
- java中redis的使用
- Oracle那些事(8)-PL/SQL Developer安装
- XML文档基本认识和基于JAVA对简单解析
- Map四种获取key和value值的方法,以及对map中的元素排序
- NestedScrolling详解
- CAS详解
- map containsKey与get方法区别经典总结
- 树莓派控制数字舵机转动
- Android中利用APT生成代码
- Java网络编程重点总结
- mongo索引创建和索引分析