Java解析XML與建立
一、什麼是 XML?
- XML 指可擴充套件標記語言(EXtensible Markup Language)
- XML 是一種標記語言,很類似 HTML
- XML 的設計宗旨是傳輸資料,而非顯示資料
- XML 標籤沒有被預定義。您需要自行定義標籤。
- XML 被設計為具有自我描述性。
- XML 是 W3C 的推薦標準
一個xml文件,用於描述傳輸圖書資訊
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="1"> <name>射鵰英雄傳</name> <author>金庸</author> <publisher>三聯出版社</publisher> <price>200</price> </book> <book id="2"> <name>神鵰俠侶</name> <author>金庸</author> <publisher>三聯出版社</publisher> <price>200</price> </book> <book id="3"> <name>倚天屠龍記</name> <author>金庸</author> <publisher>三聯出版社</publisher> <price>200</price> </book> <book id="4"> <name>鹿鼎記</name> <author>金庸</author> <publisher>三聯出版社</publisher> <price>500</price> </book> <book id="5"> <name>天龍八部</name> <author>金庸</author> <publisher>三聯出版社</publisher> <price>500</price> </book> </books>
二、xml解析
JAVA 解析 XML 通常有兩種方式,DOM 和 SAX。
1、dom解析
package edu.cduestc.xml.domain; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class DOMParseXml { public static List<Book> parseXml(InputStream is){ List<Book> list = new ArrayList<Book>(); try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(is); Element root = document.getDocumentElement(); NodeList nodes = root.getElementsByTagName("book"); for(int i = 0; i < nodes.getLength(); i++) { Book book = new Book(); Element node = (Element)nodes.item(i); Integer id = Integer.valueOf(node.getAttribute("id")); book.setId(id); NodeList childNodes = node.getChildNodes(); for(int j = 0; j < childNodes.getLength(); j++) { //Element childNode = (Element)childNodes.item(j); if(childNodes.item(j).getNodeType() == Node.ELEMENT_NODE){ Element childNode = (Element)childNodes.item(j); if("name".equals(childNode.getTagName())) book.setName(childNode.getTextContent()); if("author".equals(childNode.getTagName())) book.setAuthor(childNode.getTextContent()); if("publisher".equals(childNode.getTagName())) book.setPublisher(childNode.getTextContent()); if("price".equals(childNode.getTagName())) book.setPrice(Float.parseFloat(childNode.getTextContent())); } } list.add(book); } is.close(); } catch (Exception e) { e.printStackTrace(); } return list; } public static void main(String[] args) throws FileNotFoundException { BufferedInputStream is = new BufferedInputStream(new FileInputStream("books.xml")); parseXml(is).forEach(System.out::println);; } }
DOM 雖然是 W3C 的標準,提供了標準的解析方式,但它的解析效率一直不盡如人意,因為使用DOM解析XML時,解析器讀入整個文件並構建一個駐留記憶體的樹結構(節點樹),然後您的程式碼才可以使用 DOM 的標準介面來操作這個樹結構。但大部分情況下我們只對文件的部分內容感興趣,根本就不用先解析整個文件,並且從節點樹的根節點來索引一些我們需要的資料也是非常耗時的。
SAX是一種XML解析的替代方法。相比於文件物件模型DOM,SAX 是讀取和操作 XML 資料的更快速、更輕量的方法。SAX 允許您在讀取文件時處理它,從而不必等待整個文件被儲存之後才採取操作。它不涉及 DOM 所必需的開銷和概念跳躍。 SAX API是一個基於事件的API ,適用於處理資料流,即隨著資料的流動而依次處理資料。SAX API 在其解析您的文件時發生一定事件的時候會通知您。在您對其響應時,您不作儲存的資料將會 被拋棄。
package edu.cduestc.xml.domain; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.InputStream; 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.helpers.DefaultHandler; public class SAXParseXml { public static List<Book> parseXml(InputStream is) throws Exception, SAXException{ SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); BookHandler handler = new BookHandler(); parser.parse(is, handler); return handler.getBooks(); } private static class BookHandler extends DefaultHandler{ private List<Book> books; private Book book; private String tag; @Override public void startDocument() throws SAXException { books = new ArrayList<Book>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if("book".equals(qName)) { book = new Book(); book.setId(Integer.valueOf(attributes.getValue("id"))); } tag = qName; } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("book".equals(qName)) { books.add(book); } tag = null; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if(tag != null) { String data = new String(ch,start,length); if("name".equals(tag))book.setName(data); else if("author".equals(tag))book.setAuthor(data); else if("publisher".equals(tag))book.setPublisher(data); else if("price".equals(tag))book.setPrice(Float.parseFloat(data)); } } public List<Book> getBooks() { return books; } } public static void main(String[] args) throws Exception { BufferedInputStream is = new BufferedInputStream(new FileInputStream("books.xml")); parseXml(is).forEach(System.out::println); } }
PULL解析類似於SAX解析,都採用事件驅動(利用getEventType()方法)方式進行解析,當PULL解析器開始解析之後,可以不斷地呼叫PULL解析器的next()方法獲取下一個解析事件(開始文件START_DOCUMENT、結束文件END_DOCUMENT、開始標籤START_TAG、結束標籤END_TAG等),當處於某個元素時,可呼叫XmlPullParser的getAttributeValue()方法來獲取該元素的屬性值(可以利用屬性索引和屬性名皆可),也可呼叫XmlPullParser的nextText()方法來獲取文字節點的值。
package edu.cduestc.xml.domain; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; import org.xml.sax.SAXException; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; public class PullParseXml { public static List<Book> parseXml(Reader reader) throws Exception, SAXException { List<Book> books = new ArrayList<Book>(); Book book = null; XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser = factory.newPullParser(); parser.setInput(reader); int event = parser.getEventType();// 觸發第一個事件 while (event != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_TAG: if ("book".equals(parser.getName())) { book = new Book(); book.setId(Integer.valueOf(parser.getAttributeValue(0))); } if (book != null) { if ("name".equals(parser.getName())) book.setName(parser.nextText()); if ("author".equals(parser.getName())) book.setAuthor(parser.nextText()); if ("publisher".equals(parser.getName())) book.setPublisher(parser.nextText()); if ("price".equals(parser.getName())) book.setPrice(Float.parseFloat(parser.nextText())); } break; case XmlPullParser.END_TAG: if ("book".equals(parser.getName())) { books.add(book); book = null; } } event = parser.next();// 繼續下一次事件 } return books; } public static void main(String[] args) throws FileNotFoundException, SAXException, Exception { parseXml(new FileReader("books.xml")).forEach(System.out::println); } }