一. XML作用及應用(XML:ExtensibleMarkup Language)
1. 作用:描述有關係和層次結構的數據
2. 應用:用於軟件的配置文件,描述數據
注:在開發中,傳統的配置文件使用的是.propeties文件。以key=value的形式。#代碼註釋
二. XML語法
1. XML文檔聲明
<?xml version=”1.0” encoding=”utf-8”?>
version:版本號,目前最高版本還是1.0
encoding:指定編碼,如果不寫,默認的爲utf-8。
注意: 當我們用記事本或其它編輯器編輯xml文件,保存時默認使用的是系統編碼。xml文件保存的編碼應與xml裏encoding編碼一致,否則會因爲寫入及讀取的編碼表不同而出現錯誤或亂碼的情況。
standalone:設置該xml文件是否獨立存在
元素也稱爲標籤,必須要用結束標籤
如果元素中沒有主題內容,如<tag></tag>可以寫成<tag/>
元素中不能交叉嵌套
一個xml文件有且只能有一個根元素
xml不會忽略空格、回車、製表符
不要以xml開頭,因爲xml作爲保留的存在
命名規範:可以用字母、數字、下劃線、減號、英文句點。嚴格區分大小寫
命名規範與元素相同
屬性名不能重複,屬性的值必須要以單引號或雙引號引起來
屬性可以用元素的形式代替
把元素看作爲普通字符串,格式:<![CDATA[ ..... ]]>
& => &
< => <
> => >
" => “
&apos => ‘
作用:用來指揮軟件如何解析XML文檔。
語法:<?開頭 ?>結尾
常用的指令:xml-stylesheet引入樣式
DTD:Document Type Definition文檔類型定義
作用:約束XML編寫
DTD文件保存到磁盤上時必須使用utf-8
引用DTD的方式:
1. 引用本地的DTD文件
<!DOCTYPE 根節點名稱 SYSTEM “DTD路徑名稱”>
2. 引用外部公共的DTD文件
<!DOCTYPE 根節點名稱 PUBLIC “DTD名稱” “DTD的URL”>
語法:
例:<!ELEMENT 元素名稱 使用規則>
使用規則:
(#PCDATA):普通字符串數據
EMPTY:此元素爲空元素
ANY:表示此元素的主體內容可以爲任何類型
(子元素):指示此元素有哪些子元素。
//如果是逗號隔開,表明必須按照聲明順序去編寫XML文檔,如果子元素用 | 隔開,表明任選其一。
可以用*,?,+表示元素出現的次數:*(0次或一次或多次) ?(0次或一次) +(一次或多次) 什麼都沒有表示必須出現一次。
例:<!ATTLIST 元素名稱 屬性名 屬性值類型 設置說明屬性名 屬性值類型 設置說明>
屬性值類型:
CDATA:字符類型
ENUMERATED:枚舉,只能從枚舉中任選其一
ID:表示屬性值必須是唯一
設置說明:
#REQUIRED:表示此屬性必須要寫
#IMPLIED:可選的屬性
#FIXED:取值爲一個固定值 #FIXED“值”
直接值:默認值
引用實體:在DTD中定義,在XML中使用
語法:<!ENTITY 實體名稱 “內容”>
引用:&實體名稱;
參數實體:在DTD中定義,在DTD中使用
語法:<!ENTITY %實體名稱 “內容”>
引用:%實體名稱;
四. XML編程
1. DOM:document object model
好處:CRUD比較方便快捷。
缺點:因爲dom解析時會將整個xml文件加載至內存,變成一個對象,佔用內存較大。還可能導致內存溢出。
DocumentBuilder dBuilder = DocumentBuilerFactory.newInstance().newDocumentBuilder();
Document document = dBuilder.parse(“xml路徑”);
實例:以下文件示例中有對XML文件各種操作
ReadBook.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
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 ReadBook {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dBuilderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder dBuilder = dBuilderFactory.newDocumentBuilder();
Document document = dBuilder.parse("src\\day\\o1\\book.xml");
// test1(document);
// test2(document);
// test3(document);
// test4(document);
// test5(document);
// test6(document);
test7(document);
}
// 1、得到某個具體的節點內容
public static void test1(Document document) {
Node node = document.getElementsByTagName("作者").item(0);
System.out.println(node.getTextContent());
}
// 2、遍歷所有元素節點
// public static void test2(Document document) {
// Node root = document.getElementsByTagName("書架").item(0);
// list(root);
// }
//
// public static void list(Node root) {
// if (root instanceof Element)
// System.out.println(root.getNodeName());
// NodeList nodeList = root.getChildNodes();
// for (int x = 0; x < nodeList.getLength(); x++) {
// list(nodeList.item(x));
// }
// }
//上面的代碼改成
public static void test2(Node node) {
if (node.getNodeType() == node.ELEMENT_NODE)
System.out.println(node.getNodeName());
NodeList nodeList = node.getChildNodes();
for (int x = 0; x < nodeList.getLength(); x++) {
test2(nodeList.item(x));
}
}
// 3、修改某個元素節點的主體內容
public static void test3(Document document) throws Exception {
Element author = (Element) document.getElementsByTagName("作者").item(0);
author.setTextContent("zhangxiaoxiang");
TransformerFactory tfFactory = TransformerFactory.newInstance();
Transformer tf = tfFactory.newTransformer();
tf.transform(new DOMSource(document), new StreamResult(
new OutputStreamWriter(new FileOutputStream(
"src\\day\\o1\\book.xml"), "gbk")));
}
// 4、向指定元素節點中增加子元素節點
public static void test4(Document document) throws Exception {
Element book = (Element) document.getElementsByTagName("書").item(0);
Element newChild = document.createElement("類型");
Element refChild = (Element) document.getElementsByTagName("作者")
.item(0);
newChild.setTextContent("計算機類");
book.insertBefore(newChild, refChild);
TransformerFactory tfFactory = TransformerFactory.newInstance();
Transformer tf = tfFactory.newTransformer();
tf.transform(new DOMSource(document), new StreamResult(
new OutputStreamWriter(new FileOutputStream(
"src\\day\\o1\\book.xml"), "gbk")));
}
// 5、向指定元素節點上增加同級元素節點
public static void test5(Document document) throws Exception {
Element bookName = (Element) document.getElementsByTagName("書名")
.item(1);
Element newChild = document.createElement("類型");
newChild.setTextContent("計算機類");
Element parentNode = (Element) bookName.getParentNode();
parentNode.appendChild(newChild);
TransformerFactory tfFactory = TransformerFactory.newInstance();
Transformer tf = tfFactory.newTransformer();
tf.transform(new DOMSource(document), new StreamResult(
new OutputStreamWriter(new FileOutputStream(
"src\\day\\o1\\book.xml"), "gbk")));
}
// 6、刪除指定元素節點
public static void test6(Document document) throws Exception {
Element price = (Element) document.getElementsByTagName("售價").item(0);
price.getParentNode().removeChild(price);
TransformerFactory tfFactory = TransformerFactory.newInstance();
Transformer tf = tfFactory.newTransformer();
tf.transform(new DOMSource(document), new StreamResult(
new OutputStreamWriter(new FileOutputStream(
"src\\day\\o1\\book.xml"), "gbk")));
}
// 7、操作XML文件屬性
public static void test7(Document document) throws Exception {
Element book = (Element) document.getElementsByTagName("書").item(0);
// System.out.println(book.getAttribute("出版社"));
//
// book.setAttribute("出版社", "黑馬出版社");
NamedNodeMap nodeMap = book.getAttributes();
for (int x = 0; x < nodeMap.getLength(); x++) {
Attr attr = (Attr) nodeMap.item(x);
System.out.println(attr.getName() + ":::" + attr.getValue());
}
// TransformerFactory tfFactory = TransformerFactory.newInstance();
// Transformer tf = tfFactory.newTransformer();
// tf.transform(new DOMSource(document), new StreamResult(
// new OutputStreamWriter(new FileOutputStream(
// "src\\day\\o1\\book.xml"), "gbk")));
}
}
book.xml
<?xml version="1.0" encoding="gbk" standalone="no"?><書架>
<書 出版社="黑馬出版社" 責任人="我">
<書名>JavaOOP</書名>
<類型>計算機類</類型>
<作者>zhangxiaoxiang</作者>
</書>
<書>
<書名>JavaScript</書名>
<作者>王老師</作者>
<售價>5.00</售價>
<類型>計算機類</類型>
</書>
</書架>
好處:讀取xml文件快,佔用內存小。因爲在讀取的方式是一行一行讀取。只適合xml文件的讀取。不適合CUD操作。讀一行處理一行
實例:
//獲取SAX解析器
SAXParser parser =SAXParserFactory.newInstance().newSAXParser();
//通過SAX解析器得到讀取器
XMLReader reader = parser.getXMLReader();
//註冊內容處理器
reader.setContentHandler( 傳入ContentHandler的實現類);
1. 此處可以自己寫一個類實現ContentHandler接口,覆蓋所有方法。
2. 還可以寫一個內部類,因爲DefaultHadler是ContentHandler的實現類,我們可以寫一個內部類繼承DefaultHadler,複寫所需的方法。
需要瞭解到所有的方法用處及運行過程。
實例:
1. 查找指定的作者名。 2. 把讀取到的數據封閉到JAVABEAN中。XML文件同爲上面的BOOK.XML文件
SAXReadDemo.java
package jaxp.sax;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class SAXReadDemo {
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException {
// 得到sax解析器
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
// 得到讀取器
XMLReader reader = parser.getXMLReader();
// 註冊內容處理器
reader.setContentHandler(new DefaultHandler() {
private boolean flag = false;
private int authorIndex = 0;
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
if("作者".equals(qName)){
flag = true;
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if(flag && authorIndex==1){
System.out.println(new String(ch,start,length));
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("作者".equals(qName)){
authorIndex++;
}
flag = false;
}
});
// 讀取xml文檔
reader.parse("src\\book.xml");
}
}
BeanRead.java
package jaxp.sax;
public class BookBean {
private String press;
private String editer;
private String bookname;
private String author;
private String type;
public BookBean() {
// TODO Auto-generated constructor stub
}
public BookBean(String press, String editer, String bookname,
String author, String type) {
super();
this.press = press;
this.editer = editer;
this.bookname = bookname;
this.author = author;
this.type = type;
}
public String getPress() {
return press;
}
public void setPress(String press) {
this.press = press;
}
public String getEditer() {
return editer;
}
public void setEditer(String editer) {
this.editer = editer;
}
public String getBookname() {
return bookname;
}
public void setBookname(String bookname) {
this.bookname = bookname;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "BookBean [press=" + press + ", editer=" + editer
+ ", bookname=" + bookname + ", author=" + author + ", type="
+ type + "]";
}
}
Read2JavaBean.java
package jaxp.sax;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
public class Read2JavaBean {
/**
* 讀取xml文件並將數據封裝至javabean中
*/
static final List list = new ArrayList();
public static void main(String[] args) throws Exception {
// 得到sax解析器
SAXParser sax = SAXParserFactory.newInstance().newSAXParser();
// 得到讀取器
XMLReader reader = sax.getXMLReader();
// 註冊內容處理器
reader.setContentHandler(new DefaultHandler() {
private BookBean book = null;
private String current = null;
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
if ("書".equals(qName)) {
book = new BookBean();
book.setPress(attributes.getValue(0));
book.setEditer(attributes.getValue(1));
}
if ("書名".equals(qName))
current = qName;
if ("作者".equals(qName))
current = qName;
if ("類型".equals(qName))
current = qName;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if ("書名".equals(current))
book.setBookname(new String(ch, start, length));
if ("作者".equals(current))
book.setAuthor(new String(ch, start, length));
if ("類型".equals(current))
book.setType(new String(ch, start, length));
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if ("書".equals(qName)) {
list.add(book);
book = null;
}
current = null;
}
});
// 讀取xml文件內容
reader.parse("src\\book.xml");
System.out.println(list);
}
}
3. DOM4J解析器
結合DOM和SAX的優點,在讀取時用SAX的原理,在CUD操作時用DOM原理。
實例:XML文件進行CRUD操作。XML文件同爲上面的BOOK.XML文件
Dom4JDemo.java
package dom4j;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
public class Dom4jDemo {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
SAXReader reader = new SAXReader();
Document document = reader.read("src//book.xml");
// test1(document);
// test2(document);
// test3(document);
// test4(document);
// test5(document);
// test6(document);
test7(document);
}
// 1、得到某個具體的節點內容
public static void test1(Document document) {
Element root = document.getRootElement();
List<Element> lists = root.elements();
String author = lists.get(1).elementText("作者");
System.out.println(author);
}
// 2、遍歷所有元素節點
public static void test2(Document document) {
treeWalk(document.getRootElement());
}
public static void treeWalk(Element element) {
for (int x = 0; x < element.nodeCount(); x++) {
Node node = element.node(x);
if (node instanceof Element) {
System.out.println(node.getName());
treeWalk((Element) node);
} else
System.out.println(node.getText());
}
}
// 3、修改某個元素節點的主體內容
public static void test3(Document document) throws Exception {
Element root = document.getRootElement();
List<Element> list = root.elements();
Element bookE = list.get(1);
Element typeE = bookE.element("類型");
typeE.setText("圖書類");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gbk");
XMLWriter writer = new XMLWriter(new FileWriter("src//book.xml"),
format);
writer.write(document);
writer.close();
}
// 4、向指定元素節點中增加子元素節點
public static void test4(Document document) throws Exception {
Element root = document.getRootElement();
Element book = root.addElement("書");
book.addAttribute("出版社", "傳智");
book.addElement("書名").addText("html");
book.addElement("作者").addText("王昭廷");
book.addElement("類型").addText("動畫片");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gbk");
XMLWriter writer = new XMLWriter(new FileWriter("src//book.xml"),
format);
writer.write(document);
writer.close();
}
// 5、向指定元素節點上增加同級元素節點
public static void test5(Document document) throws Exception {
Element root = document.getRootElement();
Element bookE = root.element("書");
Element bookNameE = bookE.element("書名");
bookNameE.getParent().addElement("零售價").addText("32.22");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gbk");
XMLWriter writer = new XMLWriter(new FileWriter("src//book.xml"),
format);
writer.write(document);
writer.close();
}
// 6、刪除指定元素節點
public static void test6(Document document) throws Exception {
Element root = document.getRootElement();
Element book = root.element("書");
Element price = book.element("零售價");
price.getParent().remove(price);
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("gbk");
XMLWriter writer = new XMLWriter(new FileWriter("src//book.xml"),
format);
writer.write(document);
writer.close();
}
// 7、操作XML文件屬性
public static void test7(Document document) throws Exception {
Element root = document.getRootElement();
Element book = root.element("書");
for (Iterator<Attribute> it = book.attributeIterator(); it.hasNext();) {
Attribute att = it.next();
System.out.println(att.getName() + "=" + att.getValue());
}
}
}
在Eclipse中可以新建一個Junit Test Case文件,用於對某個類的方法進行測試。
@Before 每測試一個方法之前,都讀取此方法。執行多個方法,此方法也執行多次。
@After 每測試一個方法之後,都讀取此方法。執行多個方法,此方法也執行多次。
@BeforeClass 此上述一樣,區別在於,無論執行多少方法,此方法只執行一次。
@AfterClass 如上。
@Test 在要執行的測試方法前加@Test
(Timeout=1000) 代表測試的方法執行的時間,如果超過此設置的時間,則測試會不通過。
(exception=java.lang.NullPointException.class) 代表測試的方法需要返回一個指定的異常。
Assert.assertEquals(期待值,實際值);
此係列方法很多,還有判斷返回是不是Boolean型的true。具體查API。
用於在讀取XML中元素時能快速定位一個指定的標籤。
Node node = document.selectSingleNode(“//書[1]”);
關於Xpath的使用規則查看Xpath的文檔。
分層結構:
UI---JAVABEAN---DAO---UTILS---DB
Utils中的方法爲static方法。
Dao 中封裝所有對數據庫進行操作的方法。如果操作的方式不同,可以創建多個Dao包。然後抽取成Interface。多個Dao包實現此Interface。方便以後選擇其它操作方式。
Utils包對於異常的處理原則:
可以拋出:但是調用該工具類的必須處理。也可以不拋
非工具類的異常的處理原則:
看調用者能不能處理,不能處理則不拋。
異常轉譯和異常鏈
五. Schema約束
擴展名:xsd 本身也是一個xml文件
1、查看Schema文檔,找到根元素,在xml中先編寫根元素
<?xmlversion="1.0" encoding="gbk"?>
<書架>
</書架>
2、思考:書架來自哪個名稱空間。
使用xmlns關鍵字(xml namespace)來聲明來自的命名空間(查閱schema文檔中targetNamespace指定的值)
<?xmlversion="1.0" encoding="gbk"?>
<itheima:書架 xmlns:itheima="http://www.itcast.cn">
</itheima:書架>
3、思考:名稱空間對應的xsd文件在何方?
使用schemaLocation來說明名稱空間和xsd文件的對應關係。
有2個取值:名稱空間和xsd文件路徑,兩者之間用空格、回車、換行分隔
<?xmlversion="1.0" encoding="gbk"?>
<itheima:書架 xmlns:itheima="http://www.itcast.cn"
schemaLocation="http://www.itcast.cnbook.xsd">
</itheima:書架>
4、思考:schemaLocation又哪來的呢?來自W3C的標準名稱空間
http://www.w3.org/2001/XMLSchema-instance
<?xmlversion="1.0" encoding="gbk"?>
<itheima:書架 xmlns:itheima="http://www.itcast.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cnbook.xsd">
</itheima:書架>