一、XML:
XML(Extensible Markup Language 可擴展標記語言),XML是一個以文本來描述數據的文檔。
1. 示例:
<?xml version="1.0" encoding="UTF-8"?>
<people>
<person personid="E01">
<name>Tony</name>
<address>10 Downing Street, London, UK</address>
<tel>(061) 98765</tel>
<fax>(061) 98765</fax>
<email>[email protected]</email>
</person>
<person personid="E02">
<name>Bill</name>
<address>White House, USA</address>
<tel>(001) 6400 98765</tel>
<fax>(001) 6400 98765</fax>
<email>[email protected]</email>
</person>
</people>
2. 用途:
(1)充當顯示數據(以XML充當顯示層)
(2)存儲數據(存儲層)的功能
(3)以XML描述數據,並在聯繫服務器與系統的其餘部分之間傳遞。(傳輸數據的一樣格式)
從某種角度講,XML是數據封裝和消息傳遞技術。
3.解析XML:
3.1 :使用SAX解析XML
3.1.1 什麼是SAX:
SAX是Simple API for XML的縮寫
SAX 是讀取和操作 XML 數據更快速、更輕量的方法。SAX 允許您在讀取文檔時處理它,從而不必等待整個文檔被存儲之後才採取操作。它不涉及 DOM 所必需的開銷和概念跳躍。 SAX API是一個基於事件的API ,適用於處理數據流,即隨着數據的流動而依次處理數據。SAX API 在其解析您的文檔時發生一定事件的時候會通知您。在您對其響應時,您不作保存的數據將會被拋棄。
3.1.2 SAX解析XML方式:
SAX API中主要有四種處理事件的接口,它們分別是ContentHandler,DTDHandler, EntityResolver 和 ErrorHandler 。實際上只要繼承DefaultHandler 類就可以,DefaultHandler實現了這四個事件處理器接口,然後提供了每個抽象方法的默認實現。
// 創建SAX解析器工廠對象
SAXParserFactory spf = SAXParserFactory.newInstance();
// 使用解析器工廠創建解析器實例
SAXParser saxParser = spf.newSAXParser();
// 創建SAX解析器要使用的事件偵聽器對象
PersonHandler handler =
new PersonHandler();
// 開始解析文件
saxParser.parse(
new File(fileName), handler);
3.2. DOM解析XML:
DOM:Document Object Model(文檔對象模型)
DOM的特性:
定義一組 Java 接口,基於對象,與語言和平臺無關將 XML 文檔表示爲樹,在內存中解析和存儲 XML 文檔,允許隨機訪問文檔的不同部分。
DOM解析XML
DOM的優點,由於樹在內存中是持久的,因此可以修改後更新。它還可以在任何時候在樹中上下導航,API使用起來也較簡單。
DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
DocumentBuilder db = builder.newDocumentBuilder();
db.parse("person.xml");
NodeList node_person = doc.getElementsByTagName("person");
3.3. JDOM解析XML:
JDOM是兩位著名的 Java 開發人員兼作者,Brett Mclaughlin 和 Jason Hunter 的創作成果, 2000 年初在類似於Apache協議的許可下,JDOM作爲一個開放源代碼項目正式開始研發了。
JDOM 簡化了與 XML 的交互並且比使用 DOM 實現更快,JDOM 與 DOM 主要有兩方面不同。首先,JDOM 僅使用具體類而不使用接口。這在某些方面簡化了 API,但是也限制了靈活性。第二,API 大量使用了 Collections 類,簡化了那些已經熟悉這些類的 Java 開發者的使用。
解析步驟:
(1)SAXBuilder sax = new SAXBuilder();
(2)Document doc = sax.build(….);
(3)Element el = doc.getRootElement();(4)List list = el.getChildren();
(5)遍歷內容
3.4. DOM4J解析XML:
dom4j是一個非常非常優秀的Java XML API,具有性能優異、功能強大和極端易用使用的特點,同時它也是一個開放源代碼的軟件,可以在SourceForge上找到它。在對主流的Java XML API進行的性能、功能和易用性的評測,dom4j無論在那個方面都是非常出色的。如今你可以看到越來越多的Java軟件都在使用dom4j來讀寫XML,特別值得一提的是連Sun的JAXM也在用dom4j。這是必須使用的jar包, Hibernate用它來讀寫配置文件。
解析步驟:
(1)SAXReader sax = new SAXReader();
(2)Document doc = sax.read(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("person.xml"));
(3)Element root = doc.getRootElement();
(4)Iterator iterator = root.elementIterator();
(5)遍歷迭代器
4.各種解析方法比較:
JDOM 和 DOM 在性能測試時表現不佳,在測試 10M 文檔時內存溢出。
SAX表現較好,這要依賴於它特定的解析方式。一個 SAX 檢測即將到來的XML流,但並沒有載入到內存(當然當XML流被讀入時,會有部分文檔暫時隱藏在內存中。DOM4J是這場測試的獲勝者,目前許多開源項目中大量採用 DOM4J,例如大名鼎鼎的 Hibernate 也用 DOM4J 來讀取 XML 配置文件。
xstream 實現XML的轉換
5.案例:
public class Person {
private String personid;
private String name;
private String address;
private String tel;
private String fax;
private String email;
@Override
public String toString() {
return "Person{" +
"personid='" + personid + '\'' +
", name='" + name + '\'' +
", address='" + address + '\'' +
", tel='" + tel + '\'' +
", fax='" + fax + '\'' +
", email='" + email + '\'' +
'}';
}
public String getPersonid() {
return personid;
}
public void setPersonid(String personid) {
this.personid = personid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getFax() {
return fax;
}
public void setFax(String fax) {
this.fax = fax;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<people>
<person personid="E01">
<name>Tony Blair</name>
<address>10 Downing Street, London, UK</address>
<tel>(061) 98765</tel>
<fax>(061) 98765</fax>
<email>[email protected]</email>
</person>
<person personid="E02">
<name>Bill Clinton</name>
<address>White House, USA</address>
<tel>(001) 6400 98765</tel>
<fax>(001) 6400 98765</fax>
<email>[email protected]</email>
</person>
</people>
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Hu Guanzhong
* SAX解析的特點:
* 1、基於事件驅動
* 2、順序讀取,速度快
* 3、不能任意讀取節點(靈活性差)
* 4、解析時佔用的內存小
* 5、SAX更適用於在性能要求更高的設備上使用(Android開發中)
*
*/
public class PersonHandler extends DefaultHandler{
private List<Person> persons = null;
private Person p;//當前正在解析的person
private String tag;//用於記錄當前正在解析的標籤名
public List<Person> getPersons() {
return persons;
}
//開始解析文檔時調用
@Override
public void startDocument() throws SAXException {
super.startDocument();
persons = new ArrayList<>();
System.out.println("開始解析文檔...");
}
//在XML文檔解析結束時調用
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println("解析文檔結束.");
}
/**
* 解析開始元素時調用
* @param uri 命名空間
* @param localName 不帶前綴的標籤名
* @param qName 帶前綴的標籤名
* @param attributes 當前標籤的屬性集合
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if ("person".equals(qName)){
p = new Person();
String personid = attributes.getValue("personid");
p.setPersonid(personid);
}
tag = qName;
System.out.println("startElement--"+qName);
}
//解析結束元素時調用
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if ("person".equals(qName)) {
persons.add(p);
}
tag = null;
System.out.println("endElement--"+qName);
}
//解析文本內容時調用
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
if (tag != null) {
if ("name".equals(tag)) {
p.setName(new String(ch,start,length));
}else if("address".equals(tag)){
p.setAddress(new String(ch,start,length));
}else if("tel".equals(tag)){
p.setTel(new String(ch,start,length));
}else if("fax".equals(tag)){
p.setFax(new String(ch,start,length));
}else if("email".equals(tag)){
p.setEmail(new String(ch,start,length));
}
System.out.println(ch);
}
}
}
public class XMLDemo {
/**
* 使用第三方xstream組件實現XML的解析與生成
*/
@Test
public void xStream(){
Person p = new Person();
p.setPersonid("1212");
p.setAddress("北京");
p.setEmail("[email protected]");
p.setFax("6768789798");
p.setTel("13838389438");
p.setName("38");
XStream xStream = new XStream(new Xpp3Driver());
xStream.alias("person",Person.class);
xStream.useAttributeFor(Person.class,"personid");
String xml = xStream.toXML(p);
System.out.println(xml);
//解析XML
Person person = (Person)xStream.fromXML(xml);
System.out.println(person);
}
/**
* 從XML文件中讀取對象
*/
@Test
public void xmlDecoder() throws FileNotFoundException {
BufferedInputStream in = new BufferedInputStream(new FileInputStream("test.xml"));
XMLDecoder decoder = new XMLDecoder(in);
Person p = (Person)decoder.readObject();
System.out.println(p);
}
/**
* 把對象轉成XML文件寫入
*/
@Test
public void xmlEncoder() throws FileNotFoundException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.xml"));
XMLEncoder xmlEncoder = new XMLEncoder(bos);
Person p = new Person();
p.setPersonid("1212");
p.setAddress("北京");
p.setEmail("[email protected]");
p.setFax("6768789798");
p.setTel("13838389438");
p.setName("38");
xmlEncoder.writeObject(p);
xmlEncoder.close();
}
/**
* DOM4J解析XML
* 基於樹型結構,第三方組件
* 解析速度快,效率更高,使用的JAVA中的迭代器實現數據讀取,在WEB框架中使用較多(Hibernate)
*
*/
@Test
public void dom4jParseXML() throws DocumentException {
//1 創建DOM4J的解析器對象
SAXReader reader = new SAXReader();
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/vince/xml/person.xml");
org.dom4j.Document doc = reader.read(is);
org.dom4j.Element rootElement = doc.getRootElement();
Iterator<org.dom4j.Element> iterator = rootElement.elementIterator();
ArrayList<Person> persons = new ArrayList<>();
Person p = null;
while(iterator.hasNext()){
p = new Person();
org.dom4j.Element e = iterator.next();
p.setPersonid(e.attributeValue("personid"));
Iterator<org.dom4j.Element> iterator1 = e.elementIterator();
while(iterator1.hasNext()){
org.dom4j.Element next = iterator1.next();
String tag = next.getName();
if("name".equals(tag)){
p.setName(next.getText());
}else if("address".equals(tag)){
p.setAddress(next.getText());
}else if("tel".equals(tag)){
p.setTel(next.getText());
}else if("fax".equals(tag)){
p.setFax(next.getText());
}else if("email".equals(tag)){
p.setEmail(next.getText());
}
}
persons.add(p);
}
System.out.println("結果:");
System.out.println(Arrays.toString(persons.toArray()));
}
/**
* JDOM解析 XML
* 1、與DOM類似基於樹型結構,
* 2、與DOM的區別:
* (1)第三方開源的組件
* (2)實現使用JAVA的Collection接口
* (3)效率比DOM更快
*/
@Test
public void jdomParseXML() throws JDOMException, IOException {
//創建JDOM解析器
SAXBuilder builder = new SAXBuilder();
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/vince/xml/person.xml");
org.jdom2.Document build = builder.build(is);
Element rootElement = build.getRootElement();
List<Person> list = new ArrayList<>();
Person person = null;
List<Element> children = rootElement.getChildren();
for(Element element: children){
person = new Person();
String personid = element.getAttributeValue("personid");
person.setPersonid(personid);
List<Element> children1 = element.getChildren();
for (Element e: children1){
String tag = e.getName();
if("name".equals(tag)){
person.setName(e.getText());
}else if("address".equals(tag)){
person.setAddress(e.getText());
}else if("tel".equals(tag)){
person.setTel(e.getText());
}else if("fax".equals(tag)){
person.setFax(e.getText());
}else if("email".equals(tag)){
person.setEmail(e.getText());
}
}
list.add(person);
}
System.out.println("結果:");
System.out.println(Arrays.toString(list.toArray()));
}
/**
* DOM解析XML
* 1、基於樹型結構,通過解析器一次性把文檔加載到內存中,所以會比較佔用內存,可以隨機訪問
* 更加靈活,更適合在WEB開發中使用
*/
@Test
public void domParseXML() throws ParserConfigurationException, IOException, SAXException {
//1、創建一個DOM解析器工廠對象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//2、通過工廠對象創建解析器對象
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
//3、解析文檔
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/vince/xml/person.xml");
//此代碼完成後,整個XML文檔已經被加載到內存中,以樹狀形式存儲
Document doc = documentBuilder.parse(is);
//4、從內存中讀取數據
//獲取節點名稱爲person的所有節點,返回節點集合
NodeList personNodeList = doc.getElementsByTagName("person");
ArrayList<Person> persons = new ArrayList<>();
Person p = null;
//此循環會迭代兩次
for (int i=0;i<personNodeList.getLength();i++){
Node personNode = personNodeList.item(i);
p = new Person();
//獲取節點的屬性值
String personid = personNode.getAttributes().getNamedItem("personid").getNodeValue();
p.setPersonid(personid);
//獲取當前節點的所有子節點
NodeList childNodes = personNode.getChildNodes();
for (int j = 0;j<childNodes.getLength();j++){
Node item = childNodes.item(j);
String nodeName = item.getNodeName();
if ("name".equals(nodeName)) {
p.setName(item.getFirstChild().getNodeValue());
}else if("address".equals(nodeName)){
p.setAddress(item.getFirstChild().getNodeValue());
}else if("tel".equals(nodeName)){
p.setTel(item.getFirstChild().getNodeValue());
}else if("fax".equals(nodeName)){
p.setFax(item.getFirstChild().getNodeValue());
}else if("email".equals(nodeName)){
p.setEmail(item.getFirstChild().getNodeValue());
}
}
persons.add(p);
}
System.out.println("結果:");
System.out.println(Arrays.toString(persons.toArray()));
}
/**
* SAX解析的特點:
* 1、基於事件驅動
* 2、順序讀取,速度快
* 3、不能任意讀取節點(靈活性差)
* 4、解析時佔用的內存小
* 5、SAX更適用於在性能要求更高的設備上使用(Android開發中)
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
@Test
public void saxParseXML() throws ParserConfigurationException, SAXException, IOException {
//1、創建一個SAX解析器工廠對象
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
//2、通過工廠對象創建SAX解析器
SAXParser saxParser = saxParserFactory.newSAXParser();
//3、創建一個數據處理器(需要我們自己來編寫)
PersonHandler personHandler = new PersonHandler();
//4、開始解析
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("com/vince/xml/person.xml");
saxParser.parse(is,personHandler);
List<Person> persons = personHandler.getPersons();
for (Person p:persons){
System.out.println(p);
}
}
}
二、JSON:
1. 示例:
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。 JSON 官方:http://www.json.org
JSON 數據格式的特點
JSON 建構於兩種結構:
1、 “名稱/值”對的集合
2.、 值的有序列表(數組)
JSON 表示名稱 / 值對的方式 :
{ "firstName": "vince", "lastName":"ma", "email": "[email protected]" }
表示數組
{ "user": { "firstName": "vince", "lastName":"ma", "email": "[email protected]" },
{ "firstName": "lin", "lastName":"jacks", "email": “[email protected]”}]
}
2. 使用GSON解析JSON:
//GSON是Google開發的Java API,用於轉換Java對象和Json對象。
//下載地址:http://www.mvnrepository.com/artifact/com.google.code.gson/gson
//解析JSON:
JsonReader reader = new JsonReader(new StringReader(jsonData));
//生成JSON:
private String createJSON(ArrayList<User> users) {
JSONObject jsonObject = new JSONObject();JSONArray array = new JSONArray();
int size = users.size();
try {for (int i = 0; i < size; i++) {
User user = users.get(i); JSONObject object = new JSONObject();
object.put("name", user.name);object.put("age", user.age);array.put(object);}
jsonObject.put("users",array);
return jsonObject.toString();
} catch (JSONException e) {e.printStackTrace();}
return null;
}
static class User {String name; int age;//…}
//使用 Gson 直接把 JSON 數據轉換成 Java 對象
public Student parserJSON2(String data){
Gson gson = new Gson();
Student s = gson.fromJson(data, Student.class);
return s;
}
//使用 Gson 直接把 JSON 數組轉換成 Java 對象
public List<Student> parserJSON3(String data){
Type type = new TypeToken<ArrayList<Student>>(){}.getType();
Gson gson = new Gson();
List<Student> list = gson.fromJson(data, type);
return list;
}
3. 案例:
public class JsonDemo{
/**
* 使用JsonReader解析複雜的JSON數據
*/
@Test
public void parseJSONMessages(){
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("message.json");
InputStreamReader in = new InputStreamReader(is);
JsonReader jsonReader = new JsonReader(in);
ArrayList<Message> list = readMessageArray(jsonReader);
for (Message m: list){
System.out.println(m);
}
}
//讀取Message數組
private ArrayList<Message> readMessageArray(JsonReader jsonReader) {
ArrayList<Message> list = new ArrayList<>();
try {
jsonReader.beginArray();
while(jsonReader.hasNext()){
list.add(readMessage(jsonReader));
}
jsonReader.endArray();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
//解析一個Message對象
private Message readMessage(JsonReader jsonReader) {
Message m = new Message();
try {
jsonReader.beginObject();
while (jsonReader.hasNext()){
String name = jsonReader.nextName();
if("id".equals(name)){
m.setId(jsonReader.nextLong());
}else if("text".equals(name)){
m.setText(jsonReader.nextString());
}else if("geo".equals(name) && jsonReader.peek()!= JsonToken.NULL){
m.setGeo(readGeo(jsonReader));
}else if("user".equals(name)){
m.setUser(readUser(jsonReader));
}else{
jsonReader.skipValue();
}
}
jsonReader.endObject();
} catch (IOException e) {
e.printStackTrace();
}
return m;
}
/**
* 解析User對象
* @param jsonReader
* @return
*/
private User readUser(JsonReader jsonReader) {
User user = new User();
try {
jsonReader.beginObject();
while (jsonReader.hasNext()){
String name = jsonReader.nextName();
if("name".equals(name)){
user.setName(jsonReader.nextString());
}else if("followers_count".equals(name)){
user.setFollowers_count(jsonReader.nextInt());
}else{
jsonReader.skipValue();
}
}
jsonReader.endObject();
} catch (IOException e) {
e.printStackTrace();
}
return user;
}
/**
* 解析GEO
* @param jsonReader
* @return
*/
private ArrayList<Double> readGeo(JsonReader jsonReader) {
ArrayList<Double> list = new ArrayList<>();
try {
jsonReader.beginArray();
while (jsonReader.hasNext()){
list.add(jsonReader.nextDouble());
}
jsonReader.endArray();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
}
[
{
"id": 912345678901,
"text": "How do I read a JSON stream in Java?",
"geo": null,
"user": {
"name": "json_newb",
"followers_count": 41
}
},
{
"id": 912345678902,
"text": "@json_newb just use JsonReader!",
"geo": [50.454722, -104.606667],
"user": {
"name": "jesse",
"followers_count": 2
}
}
]
public class User {
private String name;
private int followers_count;
public User() {
}
public User(String name, int followers_count) {
this.name = name;
this.followers_count = followers_count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getFollowers_count() {
return followers_count;
}
public void setFollowers_count(int followers_count) {
this.followers_count = followers_count;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", followers_count=" + followers_count +
'}';
}
}
三、 XML與JSON的比較:
從以下6點比較JSON與XML:
1、JSON和XML的數據可讀性基本相同
2、JSON和XML同樣擁有豐富的解析手段
3、JSON相對於XML來講,數據的體積小
4、JSON與JavaScript的交互更加方便
5、JSON對數據的描述性比XML較差
6、JSON的速度要遠遠快於XML
適合的場景:
(1)數據傳輸:JSON要比XML更有優勢
(2)存儲數據:XML描述性更強
(3)XML通常用做配置文件(WEB課程中會有詳細介紹)