| 使用JAXP處理XML文件 作者:賈波 作者簡(jiǎn)介 賈波,程序員,您可以通過(guò)mosaic@hotmail.com與他聯(lián)系。 簡(jiǎn)介 JAXP是Java API for XML Processing的縮寫(xiě)。JAXP API主要的部分在javax.xml.parsers 這個(gè)包中。在這個(gè)包中,向用戶(hù)提供了兩個(gè)最重要的工廠(chǎng)類(lèi),SAXParserFactory 和DocumentBuilderFactory,相應地,提供了SAXParser 和DocumentBuilder兩個(gè)類(lèi)。 SAX是由XML-DEV定義的;DOM是由W3C定義的。讓我們來(lái)看看這些API庫。 - javax.xml.parsers
JAXP API, 定義個(gè)SAX和DOM的一個(gè)通用接口
- org.w3c.dom
定義了DOM中的所有組件
- org.xml.sax
定義了SAX的所有API
- javax.xml.transform
定義了XSLT API,使用它,你可以將XML轉化為一般的可視的頁(yè)面。 SAX指一種"事件驅動(dòng)"的處理方式,他對XML文件連續地一個(gè)對象一個(gè)對象地操作,由于它的這個(gè)特點(diǎn),所以它可以用于服務(wù)器端或者對速度有特殊要求的地方。 相比較而言DOM是個(gè)使用起來(lái)更簡(jiǎn)單些。他是將所有個(gè)XML數據全部讀到內存里面,然后使用"樹(shù)"結構將這些數據組織起來(lái),用戶(hù)可以對XML的數據進(jìn)行任意的操作。 至于XSLT,我們在這里就不介紹太多,如果感興趣請參考相應的資料。我們還是先看看SAX。 SAX SAX的框架輪廓 系統是從SAXParserFactory產(chǎn)生parser的實(shí)例開(kāi)始的。一個(gè)parser中包含了一個(gè)SAXReader對象,當這個(gè)parser調用parse方法的時(shí)候,這個(gè)reader就調用回調方法已實(shí)現這個(gè)應用;而這些方法呢?是定義在ContentHandler,ErrorHandler,DTDHandler and EntityResolver接口中的。 以下是對SAX API庫的概述: - SAXParserFactory
SAXParserFactory是一個(gè)根據系統屬性生成parser實(shí)例的一個(gè)對象。
- SAXParser
SAXParser是一個(gè)定義了不同種類(lèi)的parser()方法的接口。一般而言,你向parser傳XML數據后,使用DefaultHandler再來(lái)處理,系統就會(huì )調用一些合適的方法來(lái)處理XML文件,這樣的一種處理方法是最為簡(jiǎn)單的。
- SAXReader
SAXParser包含了一個(gè)SAXReader,通常你是不需要關(guān)心它的,但是當你要使用SAXReader的getXMLReader()方法的時(shí)候,你就需要配置他。簡(jiǎn)言之,SAXParser就是一個(gè)與SAX事件通訊的處理器,這樣,你就可以使用自定義的handler。
- DefaultHandler
DefaultHandler 實(shí)現了 ContentHandler, ErrorHandler, DTDHandler, 和EntityResolver 接口 (當然其中有一些null方法), 如果你感興趣的話(huà),你可以在你的程序中重載它。
- ContentHandler
當讀到XML的tag時(shí),就會(huì )調用到這個(gè)接口中的startDocument, endDocument, startElement, 和 endElement 方法。同時(shí),這個(gè)接口還定義了characters 和processingInstruction,方法,分別地,當parser遇到XML的element或者inline processing instruction的時(shí)候調用。
- ErrorHandler
當遇到不同類(lèi)型的錯誤的時(shí)候分別調用相應的"錯誤"方法,這些方法包括:error,fatalError和warning。
- DTDHandler
該接口所定義的方法只用在處理DTD信息的時(shí)候。
- EntityResolver
給接口中的resolveEntity方法只在parser遇到URI標識數據的時(shí)候才調用。
更詳細地api介紹,請參看SAX的官方API文檔。 例子: 在我們這個(gè)例子中,我們處理一個(gè)xml文件,然后將其值set到對象中。這是一個(gè)非常常用的使用情況。以下就是我們需要處理的xml文件。 Test.xml <?xml version="1.0" ?> <customers> <customer> <id>#001</id> <name>Micke</name> <address>Najing</address> </customer> <customer> <id>#002</id> <name>Car</name> <address>Suzhou</address> </customer> <customer> <id>#003</id> <name>Jimmy</name> <address>ChengDu</address> </customer> <customer> <id>#004</id> <name>Henry</name> <address>Xi‘a(chǎn)n</address> </customer> </customers> 這是一個(gè)非常簡(jiǎn)單的xml文件,customers中間有數個(gè)customer,每一個(gè)customer中包含三個(gè)屬性id, name, address。 根據這個(gè)xml文件,我們將Date Object設置如下。 /* * Customers.java * Create @ 2004-4-27 22:04:45 * by Jiabo */ import java.util.*; /** * Customers * Create @ 2004-4-27 22:04:45 * by Jiabo */ public class Customers { private Vector customers; public Customers() { customers = new Vector(); } public void addCustomer(Customer customer) { customers.add(customer); } public String toString() { String newline = System.getProperty("line.separator"); StringBuffer buf = new StringBuffer(); for (int i = 0; i < customers.size(); i++) { buf.append(customers.elementAt(i)).append(newline); } return buf.toString(); } } class Customer { private String id; private String name; private String address; /** * @return */ public String getAddress() { return address; } /** * @return */ public String getId() { return id; } /** * @return */ public String getName() { return name; } /** * @param string */ public void setAddress(String string) { address = string; } /** * @param string */ public void setId(String string) { id = string; } /** * @param string */ public void setName(String string) { name = string; } public String toString(){ return "Customer: ID=‘" + id + "‘ Name=‘" + name + "‘ Address=‘" + address + "‘"; } } 接下來(lái)是xml的處理器。 /* * Test.java * Created on 2004-4-10 * by Jiabo */ import java.util.*; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; /** * Test * Create on 2004-4-10 19:20:27 * by Jiabo */ public class Unmarshaller extends DefaultHandler { private Customers customers; private Stack stack; private boolean isStackReadyForText; private Locator locator; /** * init */ public Unmarshaller() { stack = new Stack(); isStackReadyForText = false; } /** * @return customers */ public Customers getCustomers() { return customers; } /** * callbacks */ public void setDocumentLocator(Locator rhs) { locator = rhs; } //========================================== // SAX DocumentHandler methods //========================================== public void startElement( String uri, String sName, String qName, Attributes attrs) { isStackReadyForText = false; if (sName.equals("customers")) { stack.push(new Customers()); } else if (sName.equals("customer")) { stack.push(new Customer()); } else if ( sName.equals("id") || sName.equals("name") || sName.equals("address")) { stack.push(new StringBuffer()); isStackReadyForText = true; } else { } } public void endElement(String namespaceURI, String sName, String qName){ isStackReadyForText = false; Object temp = stack.pop(); if (sName.equals("customers")) { customers = (Customers) temp; } else if (sName.equals("customer")) { ((Customers) stack.peek()).addCustomer((Customer) temp); } else if (sName.equals("id")) { ((Customer) stack.peek()).setId(temp.toString()); } else if (sName.equals("name")) { ((Customer) stack.peek()).setName(temp.toString()); } else if (sName.equals("address")) { ((Customer) stack.peek()).setAddress(temp.toString()); } } public void characters(char[] data, int start, int length) { if (isStackReadyForText == true) { ((StringBuffer) stack.peek()).append(data, start, length); } else { } } } 在這里我們處理xml文件的思路非常簡(jiǎn)單,就是使用一個(gè)棧,遇到"<"表示element的開(kāi)始,然后就看與我們既定的Data Object的名字是否相符合,符合就new一個(gè)該對象,并將其壓棧;不符合就什么都不做,sax的處理框架就會(huì )自己去處理下一個(gè)element。而當遇到"/>"的時(shí)候我們還是看的他名字與DataObject的名字是否相符,相符合的話(huà)就出棧,然后set進(jìn)對象里面。如此循環(huán),就處理完了我們上面那個(gè)簡(jiǎn)單得xml文件。 我們需要做的事情就只有這些。其他如何處理的,handler回自己調用相應的startElement,endElement等方法去處理。 以下是程序的入口: /* * main.java * Create @ 2004-4-27 22:18:41 * by Jiabo */ import java.io.*; import javax.xml.parsers.*; import org.xml.sax.*; /** * main * Create @ 2004-4-27 22:18:41 * by Jiabo */ public class Main { public static void main(String args[]) { Customers customers = null; if (args.length != 1) { System.err.println("Usage: cmd filename"); System.exit(1); } try { Unmarshaller handler = new Unmarshaller(); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); File file = new File(args[0]); InputSource src = new InputSource(new FileInputStream(file)); saxParser.parse( src ,handler); customers = handler.getCustomers(); } catch (Throwable t) { t.printStackTrace(); } System.out.println(customers); } } 如前面所述,通過(guò)一個(gè)工廠(chǎng)方法得到一個(gè)SAXParser的實(shí)例,然后就可以編譯這個(gè)xml文件了。這樣你就可以得到如下結果: Customer: ID =‘#001‘ Name=‘Micke‘ Address=‘Najing‘ Customer: ID =‘#002‘ Name=‘Car‘ Address=‘Suzhou‘ Customer: ID =‘#003‘ Name=‘Jimmy‘ Address=‘ChengDu‘ Customer: ID =‘#004‘ Name=‘Henry‘ Address=‘Xi‘a(chǎn)n‘ Sax的系統框架中還有其他得好些方法,讀者不妨試試他們是如何使用的,這對以后實(shí)戰處理xml文件會(huì )有很大的方便。 DOM DOM的框架輪廓 DOM的API概述 一般而言,我們使用javax.xml.parsers.DocumentBuilderFactory來(lái)得到DocumentBuilder的一個(gè)實(shí)例。當然你也可以DocumentBuilder newDocument()方法來(lái)得到一個(gè)實(shí)現了org.w3c.dom.Document接口的空的Document對象。 - DocumentBuilderFactory
它可以根據系統屬性生成一個(gè)builder實(shí)例。
- DocumentBuilder
用于處理生成Document。 更詳細地api介紹,請參看DOM的官方API文檔。 所以我們可以簡(jiǎn)單地這樣: DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse("test.xml"); 就可以出得到一個(gè)Document。 實(shí)例: 我們依然處理test.xml。和SAX一樣,也需要有paser。其實(shí)思路是非常簡(jiǎn)單而明晰的,上面我們已經(jīng)說(shuō)過(guò),DOM是將所有的xml讀入內存,以樹(shù)的結構來(lái)處理的,所以呢,對節點(diǎn)的分析就是解決問(wèn)題的關(guān)鍵,如下。 代碼如下: /* * Test.java * Created on 2004-4-10 * by Jiabo */ import org.w3c.dom.*; /** * Test * Create on 2004-4-10 19:20:27 * by Jiabo */ public class Unmarshaller { public Unmarshaller() { } public Customers UnmarshallCustomers(Node rootNode) { Customers customers = new Customers(); Node n; NodeList nodes = rootNode.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { n = nodes.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { if ("customer".equals(n.getNodeName())) { customers.addCustomer(UnmarshallCustomer(n)); } else { } } } return customers; } public Customer UnmarshallCustomer(Node customerNode) { Customer customer = new Customer(); Node n; NodeList nodes = customerNode.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { n = nodes.item(i); if ("id".equals(n.getNodeName())) { customer.setId(UnmarshallText(n)); } else if ("name".equals(n.getNodeName())) { customer.setName(UnmarshallText(n)); } else if ("address".equals(n.getNodeName())) { customer.setAddress(UnmarshallText(n)); } } return customer; } public String UnmarshallText(Node textNode) { StringBuffer buf = new StringBuffer(); Node n; NodeList nodes = textNode.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { n = nodes.item(i); if (n.getNodeType() == Node.TEXT_NODE) { buf.append(n.getNodeValue()); } else { } } return buf.toString(); } } 下面是如何驅動(dòng)DOM去處理xml文件部分。還是先得到一個(gè)DocumentBuilderFactory工廠(chǎng),在用他生成一個(gè)DocumentBuilder一個(gè)實(shí)例,在調用parse方法就可以分析這個(gè)xml文件了。 /* * main.java * Create @ 2004-4-27 22:18:41 * by Jiabo */ import java.io.*; import org.w3c.dom.*; import javax.xml.parsers.*; /** * main * Create @ 2004-4-27 22:18:41 * by Jiabo */ public class Main { public static void main(String args[]) { Customers customers = null; Document doc = null; if (args.length != 1) { System.err.println("Usage: cmd filename"); System.exit(1); } try { Unmarshaller handler = new Unmarshaller(); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); doc = builder.parse( new File(args[0]) ); customers = handler.UnmarshallCustomers(doc.getDocumentElement()); } catch (Throwable t) { t.printStackTrace(); } System.out.println(customers); } } 總結: 這里是對xml處理的一個(gè)簡(jiǎn)介,力求簡(jiǎn)介,明了,以最快的速度幫助讀者入門(mén),所以,沒(méi)有完整地使用庫中的方法。 Xml文件的處理,對于webservice是基礎的基礎。而SAX和DOM又是xml處理中基礎的基礎。濁文請讀者笑納。 參考: http://java.sun.com/xml/jaxp/docs.html |