关于XML的一些总结
- xml的知识结构图
eXtensible Markup Language,可扩展标记语言,简称XML,和HTML比较而言,语法相似,作用不同
XML被设计用来存储和传输数据,但存储数据方面,数据库是主流;传输数据方面会越来越多的使用JSON数据格式;
另一个额外的作用就是作为项目的配置文件使用,但这方面注解会越来越流行
- xml语法
- 必须以XML声明开头 <?xml version="1.0" encoding="UTF-8"?>
- 必须拥有唯一的根元素
- 元素可以包含若干属性、子元素以及文本内容
- 开始标签必须与结束标签相匹配
- 标签必须正确地嵌套,不能交叉
- 标签名大小写敏感
- 支持实体字符和CDATA区 <![CDATA[ ]]>
- 有的空白字符是有意义的,不应该被忽略
<?xml version="1.0" encoding="UTF-8"?> <users> <user id="u001" name="蛋蛋"> <email>dandan@rupeng.com</email> <phones> <phone>13700000001</phone> <phone>18000000001</phone> </phones> </user> </users>
- DTD约束
通过约束可以限定XML文件结构,有助于确保数据的正确性,也为校验XML提供了依据。使用DTD约束XML时,可以规定文档包含哪些元素、元素顺序、元素个数、子元素情况、属性及属性值、默认值等等
DTD约束语法
元素声明:<!ELEMENT 元素名称 元素内容>
属性声明:<!ATTLIST 元素名称 属性列表>
元素内容的类型:ANY、EMPTY、#PCDATA、子元素列表
子元素列表中可使用一些特殊符号:
, 逗号表示元素按声明顺序出现
| 表示元素只能出现其中一个元素
+ 表示元素至少出现一次
* 表示元素可以出现0次或多次
? 表示元素出现0次或1次
属性类型:ID、CDATA、(enum1|enum2|enum3..)枚举
属性值约束:、默认值、#REQIRED、#IMPLIED
<!ELEMENT users (user*)> <!ELEMENT user (email+,phones?)> <!ELEMENT email (#PCDATA)> <!ELEMENT phones (phone*)> <!ELEMENT phone (#PCDATA)> <!ATTLIST user id ID #REQUIRED name CDATA #IMPLIED >
可以把上面的DTD约束代码单独放在一个.dtd文件中,然后使用<!DOCTYPE>引用
引用本地DTD文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE users SYSTEM "users.dtd"> <users> <user id="u001" name="蛋蛋"> <email>dandan@rupeng.com</email> <phones> <phone>13700000001</phone> <phone>18000000001</phone> </phones> </user> </users>
引用网上DTD文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE users PUBLIC "dtd名称" "DTD文件路径"> <users> <user id="u001" name="蛋蛋"> <email>dandan@rupeng.com</email> <phones> <phone>13700000001</phone> <phone>18000000001</phone> </phones> </user> </users>
- schema约束
schema是另一种XML约束方式,它比DTD更加复杂,但功能更强大
schema文件本质上是XML文件,约束步骤如下:
1 由W3C组织事先定义好一组基本规则
使用<element>定义一个新元素 使用<complexType>表示此元素为复合元素 使用<sequence>表示子元素需要按照定义的顺序出现 使用<attribute>定义元素的属性 . . . |
2 由开发人员使用上述基本规则定义自己的规则
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="mystudents" > <element name="students" > <complexType> <sequence> <element name="student" maxOccurs="unbounded"> <complexType> <sequence> <element name="name" type="string"></element> </sequence> </complexType> </element> </sequence> </complexType> </element> </schema>
3 开发人员使用自己的规则约束自己的XML文件
<?xml version="1.0" encoding="UTF-8"?> <students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="mystudents" xsi:schemaLocation="mystudents /students.xsd"> <student> <name>蛋蛋</name> </student> <student> <name>建国</name> </student> </students>
由于schema语法太过庞杂,而且工作时几乎不会自己去写schema文件,所以只需要了解schema的原理,会引入现有的schema文件即可
- xml的解析
无论XML用来存储数据、传递数据还是做配置文件,终究都需要解析XML文件取出想要的数据。XML文件解析有多种方式,这里只介绍DOM解析方式和SAX解析方式。JDK对这两种方式都提供了支持,相关API分布在javax.xml、org.w3c.dom、org.xml.sax包及其子包下。
DOM解析方式
XML DOM和JavaScript DOM非常相似,有两个核心类org.w3c.dom.Document和org.w3c.dom.Element
Document表示整个XML文档,提供了getElementsByTagName()和getElementById()等方法查找想要操作的Element对象
Element表示XML元素,通过getAttribute()、getTextContent()、getElementsByTagName()等方法分别获得属性值、获得元素体文本内容、查找子元素等
public class DOMTest { public static void main(String[] args) throws Exception { // 解析users.xml,得到List<User> // 获得document对象 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); String path = DOMTest.class.getResource("/users.xml").getFile(); Document document = documentBuilder.parse(path); List<User> userList = new ArrayList<User>(); //获得所有的user元素 NodeList userNodeList = document.getElementsByTagName("user"); for (int i = 0; i < userNodeList.getLength(); i++) { User user = new User(); Element userElement = (Element) userNodeList.item(i); String name = userElement.getAttribute("name"); user.setName(name); String id = userElement.getAttribute("id"); user.setId(id); //获得当前user下的所有email子元素 NodeList emailNodeList = userElement.getElementsByTagName("email"); for (int j = 0; j < emailNodeList.getLength(); j++) { Element emailElement = (Element) emailNodeList.item(j); String email = emailElement.getTextContent(); user.setEmail(email); } List<String> phones = new ArrayList<String>(); //获得当前user下的所有phone子元素 NodeList phoneNodeList = userElement.getElementsByTagName("phone"); for (int m = 0; m < phoneNodeList.getLength(); m++) { Element phoneElement = (Element) phoneNodeList.item(m); String phone = phoneElement.getTextContent(); phones.add(phone); } user.setPhones(phones); userList.add(user); } System.out.println(userList); } }
SAX解析方式
SAX(Simple API for XML)基本思路:在读取XML文件内容的过程中,会按照文件结构有规律的发生读取开始标签、读取标签体内容、读取结束标签这三种动作,
开发人员可以根据XML文件结构特点,当发生不同动作的时候进行不同的处理,最终获取想要的数据。
解析过程如下:
1 编写处理器类,对不同的动作进行不同的处理
public class UserXMLHandler extends DefaultHandler { private User user; private String content; // 临时记录一个标签的文本内容 public User getUser() { return user; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // System.out.println("读取到" + qName + "的开始标签"); if ("user".equals(qName)) { user = new User(); String id = attributes.getValue("id"); String name = attributes.getValue("name"); user.setId(id); user.setName(name); } else if ("email".equals(qName)) { } } @Override public void characters(char[] ch, int start, int length) throws SAXException { // System.out.println("读取到一段文本内容:" + new String(ch, start, length)); content = new String(ch, start, length); }
@Override public void endElement(String uri, String localName, String qName) throws SAXException { // System.out.println("读取到" + qName + "的结束标签"); if ("email".equals(qName)) { user.setEmail(content); } else if ("phone".equals(qName)) { user.setPhone(content); } } }
2 执行解析并获取解析结果
public static void main(String[] args) throws Exception { File xmlFile = new File(SAXTest.class.getResource("/user.xml").getFile()); UserXMLHandler userXMLHandler = new UserXMLHandler(); SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxParserFactory.newSAXParser(); saxParser.parse(xmlFile, userXMLHandler); User user = userXMLHandler.getUser(); System.out.println(user); }