目錄
- XML簡介
- XML基本語法
- XML解析
?* DOM解析
? ?* DOM解析原理及工具
? ?* DOM4J解析工具用法及示例
? ?* xPath技術
?* SAX解析
? ?* SAX解析工具
? ?* SAX解析原理
? ?* SAX解析工具用法及示例
?* SAX解析與DOM解析的區別 - XML約束
?* 引入
?* XML約束技術
?* DTD約束
?* Schema約束
XML簡介
XML(Extend Markup Language)是一種標記語言,被用來格式化的傳輸數據
示例
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type = "text/css">
<!--this is content-->
<CATALOG>
<CD id = "132">
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
</CATALOG>
其中:
- <?xml version="1.0" encoding="ISO-8859-1"?>聲明了XML的版本(version)以及編碼方式(encoding)
- <?xml-stylesheet type = "text/css"> 處理指令,告訴XML解析如何解析XML文件,type的值表示對應的css文件
- < !--this is content-->是注釋
- <CATALOG></CATALOG>是一對標簽它們的名字可以自己定義,其中<CATALOG>是開始標簽,</CATALOG>是關閉標簽
- <CD id = "132"> id是CD的屬性
- <PRICE>10.90</PRICE> 10.90是標簽的內容
- xml描述了一種樹形結構 CATALOG是根,CD是CATALOG的子節點;TITLE,ARTIST,COUNTRY等是CD的子節點
XML基本語法
一、XML對大小寫敏感
二、所有XML標簽都必須有關閉標簽
三、頭尾標簽名應該一樣
四、屬性值必須加引號
五、在 XML 中,空格會被保留(XML中多個空格只會保留一個)
六、實體引用(轉義字符)
-
在 XML 中,一些字符擁有特殊的意義。如果你把字符 "<" 放在 XML 元素中,會發生錯誤,這是因為解析器會把它當作新元素的開始。這樣會產生 XML 錯誤:
解決辦法:
實體引用.PNG - CDATA塊,讓一些需要進行原樣輸出的內容中的特殊字符原樣輸出。
<![CDATA[<html><head></head><body></body></html>]]>
DOM解析
1)DOM解析原理
DOM解析XML文檔時,XML解析器一次性吧整個XML文檔加載進內存,然后在內存中構建一棵Document對象樹,通過Document對象,可以得到下面的節點對象,通過節點對象訪問數據
2)DOM解析工具
- JAXP (oracle-Sun公司官方)
- JDOM工具(非官方)
- Dom4J工具(非官方)(三大框架默認讀取xml的工具就是Dom4j)
DOM4J解析工具
需要導包使用
1)dom4j結構
2)dom4j讀取xml文件
節點:
- Iterator Element.nodeIterator(); //獲取當前標簽節點下的所有子節點
標簽:
- Element Document.getRootElement(); //獲取xml文檔的根標簽
- Element ELement.element("標簽名") //指定名稱的第一個子標簽
- Iterator<Element> Element.elementIterator("標簽名");// 指定名稱的所有子標簽
- List<Element> Element.elements(); //獲取所有子標簽
屬性:
- String Element.attributeValue("屬性名") //獲取指定名稱的屬性值
- Attribute Element.attribute("屬性名");//獲取指定名稱的屬性對象
- Attribute.getName() //獲取屬性名稱
- Attibute.getValue() //獲取屬性值
- List<Attribute> Element.attributes(); //獲取所有屬性對象
- Iterator<Attribute> Element.attibuteIterator(); //獲取所有屬性對象
文本:
- Element.getText(); //獲取當前標簽的文本
- Element.elementText("標簽名") //獲取當前標簽的指定名稱的子標簽的文本內容
示例1:利用dom4j輸出一個xml文件
public class Demo1 {
@Test
public void test()throws Exception {
SAXReader reader = new SAXReader();
Document document = reader.read(new File("./src/contact.xml"));
//獲得根標簽
Element element = document.getRootElement();
StringBuffer sb = new StringBuffer();
//用此方法遍歷整個xml文件(先根遍歷形式)
getchild(element,sb);
System.out.println(sb.toString());
}
private void getchild(Element element, StringBuffer sb) {
// TODO Auto-generated method stub
sb.append("<"+element.getName());
//獲得標簽的所有屬性
List<Attribute> attrs = element.attributes();
//輸出標簽屬性
if(attrs!=null) {
for (Attribute attribute : attrs) {
sb.append(" "+attribute.getName()+"=\""+attribute.getValue()+"\"");
}
}
sb.append(">");
//獲得當前標簽下的所有子標簽
Iterator<Node> iterator= element.nodeIterator();
while(iterator.hasNext()) {
Node node = iterator.next();
//輸出標簽
if(node instanceof Element) {
Element e = (Element)node;
getchild(e,sb);
}
//輸出文本
if(node instanceof Text) {
Text text = (Text)node;
sb.append(node.getText());
}
}
sb.append("</"+element.getName()+">");
}
}
示例2:把xml獲取的信息封裝到對象內
/**
* 把xml封裝到對象中
*
*/
public class Demo2 {
@Test
public void test2() throws Exception{
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("./src/contact.xml"));
Element elem = doc.getRootElement();
Iterator<Element> it = elem.elementIterator();
ArrayList<Contact> contacts = new ArrayList();
while(it.hasNext()) {
Contact contact = new Contact();
Element element = it.next();
contact.setId(element.attributeValue("id"));
contact.setAge(element.elementText("age"));
contact.setPhone(element.elementText("phone"));
contact.setEmail(element.elementText("email"));
contact.setQq(element.elementText("qq"));
contacts.add(contact);
}
for(Contact contact:contacts) {
System.out.println(contact);
}
}
}
3) 修改xml文件
增加:
- DocumentHelper.createDocument() 增加文檔
- addElement("名稱") 增加標簽
- addAttribute("名稱",“值”) 增加屬性
修改:
- Attribute.setValue("值") 修改屬性值
- Element.addAtribute("同名的屬性名","值") 修改同名的屬性值
- Element.setText("內容") 修改文本內容
刪除
- Element.detach(); 刪除標簽
- Attribute.detach(); 刪除屬性
寫入
- OutputFormat.createPrettyPrint() 創建易讀的xml文件
- OutputFormat.createCompactFormat() 創建緊湊的xml文件
- format.setEncoding("編碼方式");設置編碼方式
- XMLWriter(OutputStream out,OutPutformat format) 設置寫入方式
- XMLWriter.write 寫入內容
寫入基本流程:首先創構建一個空的Document對象,然后向其中按照節點關系添加標簽(根標簽只能有一個),然后創建文件輸出流,指定輸出格式,利用XMLWriter對象設置格式和寫入內容,最后關閉writer對象。
示例3:創建文件并寫入一個簡單的XML文檔:
************
/**
* 生成xml文檔
*
<Students>
<Student id="1">
<name>張三</name>
<gender>男</gender>
<grade>計算機1班</grade>
<address>廣州天河</address>
</Student>
<Student id="2">
<name>李四</name>
<gender>女</gender>
<grade>計算機2班</grade>
<address>廣州越秀</address>
</Student>
</Students>
*
*/
public class Demo3 {
@Test
public void test() throws Exception {
//在內存創建Document文檔
Document doc = DocumentHelper.createDocument();
//寫入內容
Element rootElement = doc.addElement("Students");
//增加第二層標簽
Element studentElem = rootElement.addElement("Student");
//增加屬性
studentElem.addAttribute("id", "1");
//添加第三層標簽
studentElem.addElement("name").setText("張三");
studentElem.addElement("gender").setText("男");
studentElem.addElement("grade").setText("計算機一班");
studentElem.addElement("address").setText("廣州天河");
//增加第二個二層標簽
Element studentElemnt2 = rootElement.addElement("Student");
studentElemnt2.addAttribute("id", "2");
//為第二個二層標簽添加子標簽
studentElemnt2.addElement("name").setText("李四");
studentElemnt2.addElement("gender").setText("女");
studentElemnt2.addElement("grade").setText("計算機二班");
studentElemnt2.addElement("address").setText("廣州越秀");
//將內容寫出到文件
//創建輸出流
FileOutputStream out = new FileOutputStream(new File("f:/student.xml"));
//指定輸出方式
OutputFormat format = OutputFormat.createPrettyPrint();
//指定編碼方式
format.setEncoding("utf-8");
XMLWriter writer = new XMLWriter(out,format);
//寫出內容
writer.write(doc);
//關閉資源
writer.close();
}
}
示例4:修改、刪除xml文件
/**
* 修改id為2的學生的姓名+刪除id為2的學生標簽
*
*/
public class Demo3 {
@Test
public void test() throws Exception {
//將XML文件載入為document對象
Document document = new SAXReader().read(new File("f:/student.xml"));
//獲取所有Student標簽
Iterator<Element> it = document.getRootElement().elementIterator("Student");
//查詢id為2的學生
while(it.hasNext()) {
Element elem = it.next();
System.out.println(elem.attribute("id").getValue());
if(elem.attributeValue("id").equals("2")) {
//修改姓名
//elem.element("name").setText("王麗");
//刪除該學生標簽
elem.detach();
break;
}
}
FileOutputStream out = new FileOutputStream("f:/student.xml");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");
XMLWriter writer = new XMLWriter(out,format);
writer.write(document);
writer.close();
}
}
4)xPath技術
當使用dom4j查詢比較深的層次節點時比較麻煩,xPath技術可以使我們快速獲得深層次節點
使用xPath的方法需要導入dom4j文件夾下的jaxen-1.1-beta-6.jar包。
xPath語法:
Xpath語法類似于在一個文件系統中定位文件
W3C的Xpath語法教程:http://www.w3school.com.cn/xpath/xpath_syntax.asp
- / 絕對路徑 表示從xml的根位置開始或子元素(一個層次結構)
- // 相對路徑 表示不分任何層次結構的選擇元素。
- * 通配符 表示匹配所有元素
- [] 條件 表示選擇什么條件下的元素
- @ 屬性 表示選擇屬性節點
- and 關系 表示條件的與關系(等價于&&)
- text() 文本 表示選擇文本內容
在DOM4J中的使用方法:
- List<Node> selectNodes("xpath表達式"); 查詢多個節點對象
- Node selectSingleNode("xpath表達式"); 查詢一個節點對象
SAX解析
1)SAX解析工具
SAX解析工具- Sun公司提供的。內置在jdk中。org.xml.sax.*
2)SAX解析原理
加載一點,讀取一點,處理一點。對內存要求比較低。
核心的API:
SAXParser類: 用于讀取和解析xml文件對象
- parse(File file,DefautHandler);
參數一: File:表示 讀取的xml文件。
參數二: DefaultHandler: SAX事件處理程序。需要自己實現它的子類,覆蓋相應方法進行解析
DefaultHandler類的API:
- void startDocument() : 在讀到文檔開始時調用
- void endDocument() :在讀到文檔結束時調用
- void startElement(String uri, String localName, String qName, Attributes attributes) :讀到開始標簽時調用
- void endElement(String uri, String localName, String qName) :讀到結束標簽時調用
- void characters(char[] ch, int start, int length) : 讀到文本內容時調用
3)示例,利用SAX解析輸出完整xml文檔內容
1.主函數:
/**
* 讀取contact.xml文件,完整輸出文檔內容
*
*/
public class Demo2 {
public static void main(String[] args)throws Exception {
//1.創建SAXParser
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
//2.讀取xml文件
MyDefaultHandler2 handler = new MyDefaultHandler2();
parser.parse(new File("./src/contact.xml"), handler);
String content = handler.getContent();
System.out.println(content);
}
}
2.MyDefaultHandler2類
/**
* SAX處理器程序
*/
public class MyDefaultHandler2 extends DefaultHandler {
//存儲xml文檔信息
private StringBuffer sb = new StringBuffer();
//獲取xml信息
public String getContent(){
return sb.toString();
}
/**
* 開始標簽
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
sb.append("<"+qName);
//判斷是否有屬性
if(attributes!=null){
for(int i=0;i<attributes.getLength();i++){
//得到屬性名稱
String attrName = attributes.getQName(i);
//得到屬性值
String attrValue = attributes.getValue(i);
sb.append(" "+attrName+"=\""+attrValue+"\"");
}
}
sb.append(">");
}
/**
* 文本內容
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//得到當前讀取的文本
String content = new String(ch,start,length);
sb.append(content);
}
/**
* 結束標簽
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
sb.append("</"+qName+">");
}
}
SAX解析與DOM解析的區別
DOM解析 | SAX解析 |
---|---|
原理: 一次性加載xml文檔,不適合大容量的文件讀取 | 原理: 加載一點,讀取一點,處理一點。適合大容量文件的讀取 |
DOM解析可以任意進行增刪改查 | SAX解析只能讀取 |
DOM解析任意讀取任何位置的數據,甚至往回讀 | SAX解析只能從上往下,按順序讀取,不能往回讀 |
DOM解析面向對象的編程方法(Node,Element,Attribute),Java開發者編碼比較簡單。 | SAX解析基于事件的編程方法。java開發編碼相對復雜。 |
XML約束
1)引入
XML語法是由w3c組織制定的規范xml文件的基本編寫規則,而XML約束是開發者自定義規則以使XML符合自己的規范的約束。
2)XML約束技術
DTD約束:語法相對簡單,功能也相對簡單。學習成本也低。
Schema約束:語法相對復雜,功能也相對強大。學習成本相對高!!!(名稱空間)
3)DTD約束
1.導入DTD方式
- 內部導入
<?xml version="1.0"?>
<!DOCTYPE note [//定義此文檔是 note 類型的文檔。
<!ELEMENT note (to,from,heading,body)> //定義 note 元素有四個元素:"to、from、heading,、body"
<!ELEMENT to (#PCDATA)> //元素為 "#PCDATA" 類型
<!ELEMENT from (#PCDATA)> //元素為 "#PCDATA" 類型
<!ELEMENT heading (#PCDATA)> //元素為 "#PCDATA" 類型
<!ELEMENT body (#PCDATA)> //元素為 "#PCDATA" 類型
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
- 外部導入
本地文件系統:<!DOCTYPE note SYSTEM "note.dtd">
公共的外部導入:<!DOCTYPE 根元素 PUBLIC "http://gz.itcast.cn/itcast.dtd">
2.DTD語法
- 約束標簽 <!ELEMENT 元素名稱 類別> 或 <!ELEMENT 元素名稱 (元素內容)>
類別:
??空標簽: EMPTY。 表示元素一定是空元素。
??普通字符串: (#PCDATA)。表示元素的內容一定是普通字符串(不能含有子標簽)。
??任何內容: ANY。表示元素的內容可以是任意內容(包括子標簽)
順序問題:
<!ELEMENT 元素名稱 (子元素名稱 1,子元素名稱 2,.....)>: 表示子標簽必須按順序出現
次數問題:
標簽名 : 表示標簽必須出現且只出現1次。
標簽名+ : 至少出現1次
標簽名* : 0或n次。
標簽名? : 0 或1次。
- 約束屬性 <!ATTLIST 元素名稱 屬性名稱 屬性類型 默認值>
默認值:
????#REQUIRED ?表示屬性是必需的
????#IMPLIED ?表示屬性不是必需的
????#FIXED value ?表示屬性不是必須的,但屬性值是固定的
屬性類型:控制屬性值的
????CDATA :?表示普通字符串
????(en1|en2|..):? 表示一定是任選其中的一個值
????ID:?表示在一個xml文檔中該屬性值必須唯一。值不能以數字開頭
4)Schema約束
名稱空間:告訴xml文檔的哪個元素被哪個schema文檔約束。 在一個xml文檔中,不同的標簽可以受到不同的schema文檔的約束。
1.一個名稱空間受到schema文檔約束的情況
2.多個名稱空間受到多個schema文檔約束的情況
3.默認名稱空間的情況
4.沒有名稱空間的情況