xml介绍
文档说明
一个良好的xml文件,需要对xml文件有一个基本的介绍和基础属性的设置.最基本的文档说明如下:
<?xml version="1.0" ?>
常见的文档说明如下
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- version:声明版本号
encoding:指定编码格式,例如 gb2312 utf-8 注意在编写文件中存取和读取的编码需一致
standalone:文档是否独立 -->
元素(element)
声明格式:以下两种xml声明格式
<!-- 声明格式1 --> <a id="9527">...</a> <!-- 常常把一个元素称为一个标签 -->
<!-- 声明格式2 --> <a id="9527"/> <!--此声明格式不含子标签 --></span>
xml元素需要注意一些规范
1.大小写区分,不能包含空格,不能有;号
2.不要以_开头,也不要以xml开头
注意:在xml文件中空格和换行都算是text内容,会被程序解析(红刷笔刷过的地方)
demo
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<exam> <!-- 根节点为exam -->
<student id="1" > <!-- 子标签student 包含一个属性id -->
<name>xiaosan</name> <!-- 子标签name,location,grade-->
<location>沈阳</location>
<grade>89</grade>
</student>
<student id="2" >
<name>xiaowu</name>
<location>合肥</location>
<grade>29</grade>
</student>
</exam>
特殊语法
使用<![CDATA[ .... ]]>告诉解析器不解析内含字段,原样输出。
<![CDATA[
<student id="1" > <!-- 子标签student 包含一个属性id -->
<name>xiaosan</name> <!-- 子标签name,location,grade-->
<location>沈阳</location>
<grade>89</grade>
</student>
]]>
一些特殊字段使用转义字符来表示
xml约束
所谓的约束,即编写xml文件的指导说明。常用的xml约束有两种:DTD和Schema.DTD语法简单但是对属性类型具有局限性,Schema相对更为严谨也更为复杂,两者都有成熟的文档,可以参考文档编写,一般能看懂即可。
DTD约束
DTD可以直接在相应的xml文档中声明,也可以单独为一个dtd文件。
1.直接在xml文件中定义
<?xml version="1.0" encoding="UTF-8"?>
<!--
内部DTD声明 ,格式为:
<!DOCTYPE root_name root_name为xml文件的根节点
[
....
]
>
-->
<!DOCTYPE person[
<!ELEMENT person (人+)>
<!ELEMENT 人 (姓名+,年龄,(住址*|家乡?))>
<!ELEMENT 姓名 (#PCDATA)>
<!ELEMENT 年龄 (#PCDATA)>
<!ELEMENT 住址 (#PCDATA)>
]>
<person>
<人>
<姓名>小李</姓名>
<年龄>23</年龄>
<住址>岗头村</住址>
</人>
<人>
<姓名>小王</姓名>
<姓名>隔壁老王</姓名>
<年龄>30</年龄>
<家乡>二八村</家乡>
</人>
</person>
2.单独编写一个DTD文件
person.dtd文件
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT person (人+)>
<!ELEMENT 人 (姓名+,年龄,(住址*|家乡?))>
<!ELEMENT 姓名 (#PCDATA)>
<!ELEMENT 年龄 (#PCDATA)>
<!ELEMENT 住址 (#PCDATA)>
对应的person.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
使用外部声明的DTD ,需要加入:
<!DOCTYPE 根元素名称 SYSTEM/PUBLIC "外部文档名称或路径.dtd" >
-->
<<!DOCTYPE person PUBLIC SYSTEM "person.dtd">
<person>
<人>
<姓名>小李</姓名>
<年龄>23</年龄>
<住址>岗头村</住址>
</人>
<人>
<姓名>小王</姓名>
<姓名>隔壁老王</姓名>
<年龄>30</年龄>
<家乡>二八村</家乡>
</人>
</person>
DTD语法简介
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT person (人+)>
<!ELEMENT 人 (姓名+,年龄,(住址*|家乡?))>
<!ELEMENT 姓名 (原名|昵称)>
<!ATTLIST 原名
中文名 CDATA #REQUIRED
英文名 CDATA #IMPLIED
阿三名 CDATA #FIXED "乌拉拉"
>
<!ATTLIST 昵称
QQ昵称 (xiao|li|wang) "sb"
>
<!ELEMENT 年龄 (#PCDATA)>
<!ELEMENT 住址 (#PCDATA)>
<!--
元素内容使用,号表示出现次序需要一致
元素内容使用|号表示只能选择其一
元素中使用+、?、*表示元素出现次数
? 0次或1次 (人?)
+ 1次或多次 (人+)
* 0次或多次 (人*)
对于标签可以使用ATTLIST为其设置属性
<!ATTLIST 元素名
属性1 类型 设置说明
属性2 ... ...
...
>
常见类型:
cdata 为常见字符串
(?|?|?) 给定范围取值
id 表示唯一属性
entity 表示一个实体(类似一个宏定义)
...
设置说明:
#REQUIRED 必须有此属性
#IMPLIED 可有
#FIXED 固定值
"xxx" 如果没表定,则默认值
-->
schema语法
因为schema的语法和xml语法类似。
一个schema文档必须有一个根节点,且根节点名称为schema。每个schema模式文档可以声明一个名称空间,同时用一个唯一的URI表示。
在schema文件中
schema.xsd文档声明
<!--根元素schema。
使用xmlns关键字引入命名空间xs
同时限定该文档的约束对象URI:www.delphifan.com
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.delphifan.com" elementFormDefault="qualified">
对于的xml文件中
<!-- xmlns="http://www.delphifan.com" -> 使用默认命名空间
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -> 使用xsi命名空间 配置 xsi:schemaLocation属性
xsi:schemaLocation="http://www.delphifan.com shiporder.xsd" -> 声明该文档的约束文档的URI和对于的文档名称
-->
<shiporder
xmlns="http://www.delphifan.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.delphifan.com shiporder.xsd"
orderid="23" >
注意: 在声明xsi:schemaLocation属性时候按照xsi:xsi:schemaLocation="{namespace} {location}" 格式声明。namespace和location之间的空格不能少。
demo
shiporder.xsd约束文档
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.delphifan.com" elementFormDefault="qualified">
<xs:element name="shiporder">
<xs:complexType> <!--complexType表示一个复杂类型 -->
<xs:sequence> <!--xs:sequence表示元素值必须按顺序声明 -->
<xs:element name="orderperson" type="xs:string" />
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="address" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="country" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string" />
<xs:element name="note" type="xs:string" minOccurs="0" />
<xs:element name="quantity" type="xs:positiveInteger" />
<xs:element name="price" type="xs:decimal" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
shiporder.xml文档
<?xml version="1.0" encoding="UTF-8"?>
<shiporder
xmlns="http://www.delphifan.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.delphifan.com shiporder.xsd"
orderid="23" >
<orderperson>fan</orderperson>
<shipto>
<name>xiaofan</name>
<address>hefei</address>
<city>anhui</city>
<country>zhongguo</country>
</shipto>
<item>
<title>schema technology</title>
<note>so handsome</note>
<quantity>23</quantity>
<price>12.2</price>
</item>
</shiporder>
xml解析
解析方式分为两种:dom和sax
dom(document object model )解析:
一次性读取xml文件,可对xml里数据操作。 优点CRUD操作方便,但占用内存大
sax(simple API for XML)解析:
一点一点读取。优点是占用内存小,速度快,但CRUD操作不方便
常用的xml解析开发包
jaxp(官方的不需要外部jar包)与dom4j(需要外部jar包)
DOM解析(jaxp包)
整体流程如图所示
过程大致分为两部分
1.修改部分
使用DocumentBuilderFactory产生factory对象-->产生DocumentBuilder对象 -->使用parse()方法得到ducment对象
对document对象可以获取指定元素,作CRUD操作等
2.保存部分
使用TransformerFactory-->得到factory对象-->得到Transformer()对象-->使用transform()方法把改变后的document对象存储至xml文件中
demo
任务需求:要求编写一个工具类
1.直接操作Student对象在xml文件中存储
2.在xml文件中通过examid属性查找对应的student标签
3.通过name属性在xml文件中删除对于的student标签
设计思路如下图
1.studentDao负责对xml文件操作,包含三个方法,即增加学生对象,删除,查找操作
2.因为对xml操作中有大量重复代码,故定义工具类简化操作
student类
package org.nihao.domain;
public class Student {
private int idcard;
private int examid;
private String name;
private String location;
private double score;
public int getIdcard() {
return idcard;
}
public void setIdcard(int idcard) {
this.idcard = idcard;
}
public int getExamid() {
return examid;
}
public void setExamid(int examid) {
this.examid = examid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
studentDao.java
package org.nihao.dao;
import org.nihao.domain.Student;
import org.nihao.exception.StudentNotExistException;
import org.nihao.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class StudentDao {
public void add(Student s){
try {
Document document = XmlUtils.getDocument(); //checked exception
//1.创建标签
Element element = document.createElement("student");
//创建子标签并填充子标签
Element nameElement = document.createElement("name");
nameElement.setTextContent(s.getName());
Element locationElement = document.createElement("location");
locationElement.setTextContent(s.getLocation());
Element gradeElement = document.createElement("grade");
gradeElement.setTextContent(Double.toString(s.getScore()));
//2.填充数据
element.setAttribute("idcard", Integer.toString(s.getIdcard()));
element.setAttribute("examid", Integer.toString(s.getExamid()));
element.appendChild(nameElement);
element.appendChild(locationElement);
element.appendChild(gradeElement);
document.getElementsByTagName("exam").item(0).appendChild(element);
//3.保存标签
XmlUtils.write2Xml(document);
} catch (Exception e) {
throw new RuntimeException(e); //运行时的异常
}
}
public Student find(int examid){
try {
Document document = XmlUtils.getDocument();
NodeList list = document.getElementsByTagName("student");
for (int i = 0; i < list.getLength(); i++) {
Element student = (Element) list.item(i);
String attribute = student.getAttribute("examid");
if (attribute.equals(Integer.toString(examid))) {
Student stu = new Student();
stu.setExamid(examid);
stu.setIdcard(Integer.parseInt(student.getAttribute("idcard").trim()));
stu.setLocation(
student.getElementsByTagName("location").item(0).getTextContent());
stu.setName(
student.getElementsByTagName("name").item(0).getTextContent());
stu.setScore(Double.parseDouble(student.getElementsByTagName("grade")
.item(0).getTextContent()));
return stu;
}
}
return null;
} catch (Exception e) {
throw new RuntimeException(e); //运行时的异常
}
}
public void delete(String name) throws StudentNotExistException{
try {
Document document = XmlUtils.getDocument();
NodeList list = document.getElementsByTagName("name");
for (int i = 0; i < list.getLength(); i++) {
if (list.item(i).getTextContent().equals(name)) {
list.item(i).getParentNode().getParentNode()
.removeChild(list.item(i).getParentNode());
XmlUtils.write2Xml(document);
return;
}
}
throw new StudentNotExistException(name+"不存在!"); //自定义异常,用于通知调用者未查找到学生信息
}catch(StudentNotExistException e){
throw e;
}catch (Exception e ) {
throw new RuntimeException(e); //运行时的异常
}
}
}
XmlUtils.java
package org.nihao.util;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public class XmlUtils {
private static String filename = "src/exam.xml";
public static Document getDocument() throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
return documentBuilder.parse(filename);
}
public static void write2Xml(Document document) throws TransformerException{
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult(filename));
}
}
exam.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<exam>
<student id="1" >
<name>xiaosan</name>
<location>沈阳</location>
<grade>89</grade>
</student>
<student id="2" >
<name>xiaowu</name>
<location>合肥</location>
<grade>29</grade>
</student>
</exam>
sax解析
采用事件处理的方式解析xml文件,分为两个部分:解析器和事件处理器
解析过程如下图
解析器:通过JAXP的api直接创建
事件处理器:
每当解析到一个组成部分,就会调用事件处理器的一个方法,同时会把解析出来的内容作为方法参数传递。
新建一个对象实现给定的ContentHandler,并实现其中方法,重写常用的三个方法startElement、endElement、characters方法
或者使用官方帮我们实现了几个常用的类 DefaultHandler,DefaultHandler2, ValidatorHandler, XMLFilterImpl, XMLReaderAdapter
demo
public class Demo1 {
public static void main(String[] args) throws Exception {
//1.通过工厂得到解析器
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
//2.通过解析器得到Reader
XMLReader xmlReader = parser.getXMLReader();
//设置内容处理器
xmlReader.setContentHandler(new handler());
//3.解析
xmlReader.parse("src/book.xml");
}
}
class handler implements ContentHandler{
@Override
public void setDocumentLocator(Locator locator) {
}
@Override
public void startDocument() throws SAXException {
}
@Override
public void endDocument() throws SAXException {
}
@Override
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
System.out.println("<"+qName+">");
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("<"+qName+">");
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.println(new String(ch,start,length));
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
}
@Override
public void processingInstruction(String target, String data)
throws SAXException {
}
@Override
public void skippedEntity(String name) throws SAXException {
}
}
使用dom4j对xml操作
dom4j的说明文档非常详细,其中包含强大的xpath正则表达式获取元素方法。这里只贴一些简单的demo,需要使用dom4j之间查看其官方的文档即可。
ADU操作
public void add() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
Element book = document.getRootElement().element("书");
List elements = book.elements();
Element element = DocumentHelper.createElement("售价");
element.setText("200yuan");
elements.add(2, element);
//修改完毕后,输出存储
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
writer.write(document);
writer.close();
}
public void delete() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
Element book = document.getRootElement().element("书");
book.remove(book.element("售价"));
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
writer.write(document);
writer.close();
}
public void update() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
Element book = (Element) document.getRootElement().elements("书").get(1);
book.element("售价").setText("2999元");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format);
writer.write(document);
writer.close();
<pre name="code" class="java"> }
public class Demo3 {
//基本的XPATH操作
public void xpath() throws Exception{
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/book.xml"));
String text = document.selectSingleNode("//作者").getText();
System.out.println(text);
}
}
schema语法
因为schema的语法和xml语法类似,且对类型的限制远好于DTD的类型限制,故schema的使用会更加广泛。
文档后缀名:xxx.xsd 一个schema文档必须有一个根节点,且根节点名称为schema 。每个schema模式文档可以声明一个名称空间,同时用一个唯一的URI表示。
在schema文件中
schema文档的头元素声明
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 根元素schema。 使用xmlns关键字引入命名空间xs 同时限定该文档的约束对象URI:www.delphifan.com
targetNamespace="http://www.delphifan.com" elementFormDefault="qualified">
对于的xml文件中
<?xml version="1.0" encoding="UTF-8"?>
<shiporder
xmlns="http://www.delphifan.com" 使用默认命名空间
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 使用xsi命名空间 并声明该文档的约束文档的URI和对于的文档名称
xsi:schemaLocation="http://www.delphifan.com shiporder.xsd"
orderid="23" >
注意 在声明xsi:schemaLocation属性时候按照xsi:xsi:schemaLocation="{namespace} {location}" namespace和location之间的空格不能少。
具体的细节可以参考schema官方文档。
demo
shiporder.xsd约束文档
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.delphifan.com" elementFormDefault="qualified">
<xs:element name="shiporder">
<xs:complexType> <!--complexType表示一个复杂类型 -->
<xs:sequence> <!--xs:sequence表示元素值必须按顺序声明 -->
<xs:element name="orderperson" type="xs:string" />
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string" />
<xs:element name="address" type="xs:string" />
<xs:element name="city" type="xs:string" />
<xs:element name="country" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string" />
<xs:element name="note" type="xs:string" minOccurs="0" />
<xs:element name="quantity" type="xs:positiveInteger" />
<xs:element name="price" type="xs:decimal" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:schema>
shiporder.xml文档
<?xml version="1.0" encoding="UTF-8"?>
<shiporder
xmlns="http://www.delphifan.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.delphifan.com shiporder.xsd"
orderid="23" >
<orderperson>fan</orderperson>
<shipto>
<name>xiaofan</name>
<address>hefei</address>
<city>anhui</city>
<country>zhongguo</country>
</shipto>
<item>
<title>schema technology</title>
<note>so handsome</note>
<quantity>23</quantity>
<price>12.2</price>
</item>
</shiporder>