xml解析方式:
dom(Document Object Model):文檔對象模型,是w3c組織解析xml的一種方式
sax(Simple API for XML):不是官方標準,但他是xml社區的標準,幾乎所有的xml解析器都支持
xml的解析開發包:jaxp(sun),jdom(開源組織)和dom4j(開源組織)
dom和sax的區別{
1.dom解析的優點是對文檔crud比較方便,缺點是佔用內存比較大。原理:因爲解析的時候需要將整個文檔加載到內存,將文檔的節點作爲對象,在內存建立一個對象關係表
2.sax解析的優點是佔用內存少,解析速度快,缺點是隻適合作爲文檔的讀取,不適合作爲文檔的crud。原理:讀取一行解析一行的方式
}
JAXP{
1.是j2se的一部分,由javax.xml、org.w3c.dom、org.xml.sax包及其子包組成
2.在javax.xml.parsers包中,定義了幾個工廠類,程序員可以通過調用工廠類得到xml文檔的dom、sax的解析器,從而對xml文檔進行解析
dom解析{讀取完文檔再解析
}1.獲得javax.xml.parsers包中的DocumentBuilderFactory(工廠模式,不可實例化,可以通過公共方法獲得實例)
2.創建dom模式的解析器對象
3.解析xml文檔,獲得文檔對象
4.通過文檔對象可以通過標籤名獲得文檔內的所有標籤
// 1.創建工廠 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 2.通過工廠獲得解析器對象 DocumentBuilder builder = factory.newDocumentBuilder(); // 3.通過對象解析文件,獲得代表文檔的document對象 Document document = builder.parse("src/book.xml"); // 獲取標籤,返回多個節點組成的list,標籤名相同 NodeList list = document.getElementsByTagName("書名"); // 獲取list中的節點,所有從0開始.獲取第二個名爲書名的節點 Node node = list.item(1); // 得到該節點的內容 String content = node.getTextContent();
5.通過標籤的節點又可以獲得該標籤的子標籤:getChildNodes();
// 獲得指定標籤下的所有標籤 public void list(Node node){ // 由於xml文檔中的換行符也會作爲節點的子節點。所以先判斷該節點是否爲標籤 if(node instanceof Element){ System.out.println(node.getNodeName()); } // 1.獲取該標籤下的所有子標籤 NodeList list = node.getChildNodes(); // 2.遍歷子標籤,在獲得它的子標籤(遞歸) for (int i = 0; i < list.getLength(); i++) { Node child = list.item(i); list(child); } }
6.可以將節點轉爲標籤對象,再使用屬性名來獲取屬性值Element book = (Element) document.getElementsByTagName("書").item(0); book.getAttribute("name");
7.以下幾個都是對內存中的文檔對象進行修改,並未修改xml文檔,就需要使用javax.xml.transformer包中的Transform方法把代表xml文件的document對象轉換成某種格式後再輸出到xml文件中,這個類的轉換方法需要接受源(通過DOMSource關聯要轉換的document對象)和目的(用StreamResult對象表示數據的目的地)8.使用文檔對象創建標籤:createElement("..."),爲標籤賦值之後,綁定在一個標籤上
// 添加標籤到文檔中(添加指定的位置:insertBefore(newChild,refChild)) public void add() throws Exception{ // 1.獲得文檔對象 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml"); // 2.創建一個售價的標籤 Element price = document.createElement("售價"); // 3.爲該標籤添加內容 price.setTextContent("49.00元"); // 4.將該標籤放在第一個名爲“書”的標籤下 Element book = (Element) document.getElementsByTagName("書").item(0); book.getAttribute("name"); book.appendChild(price); // 5.由於以上代碼知識將內存中的文檔更新了,需要將內存中的文檔更新到xml文檔 //先獲生產轉換對象的工廠 TransformerFactory factory = TransformerFactory.newInstance(); //得到轉化對象 Transformer ts = factory.newTransformer(); //將document對象封裝成源,xml位置流封裝成目的地 DOMSource source = new DOMSource(document);//直接使用創建對象的方法封裝document StreamResult result = new StreamResult(new FileOutputStream("src/book.xml"));//將xml文件的路徑封裝成目的流 //調用轉化方法 ts.transform(source, result); }
9.獲得標籤的element對象,使用setAttribute()設置屬性// 給標籤添加一個屬性 public void addAttr() throws Exception{ // 1.獲得文檔對象 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml"); // 2.獲得要添加屬性的標籤,第一本書 Element book = (Element) document.getElementsByTagName("書").item(0); // 3.爲該節點添加屬性 book.setAttribute("name", "java編程"); // 4.將內存中的文檔更新到xml文件 TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult("src/book.xml")); }
10.獲得標籤的element對象,使用setTextContent()修改標籤的內容// 修改標籤的內容 public void update() throws Exception{ // 1.獲得文檔對象 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml"); // 2.獲得要修改內容的標籤對象 Element book = (Element) document.getElementsByTagName("書").item(0); // 3.修改內容 book.setTextContent("哈哈哈"); // 4.將內存中的文檔更新到xml文件 TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml"))); }
11.獲得old的父標籤Element對象,再使用removeChild(old)來刪除old節點// 刪除某個標籤 public void delete() throws Exception{ // 1.獲得文檔對象 Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/book.xml"); // 2.獲得要刪除的書的標籤對象 Element book = (Element) document.getElementsByTagName("書").item(0); // 3.獲得書的父標籤刪除。 book.getParentNode().removeChild(book); // 4.將內存中的文檔更新到xml文件 TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(new FileOutputStream("src/book.xml"))); }
注意:dom解析下,xml文檔的每一個組成部分都用一個對象表示,例如標籤的Element和屬性的Attr,但不管什麼對象都是Node的子類,所以標籤可以當做節點來對待sax解析{邊讀取邊解析
採用事件處理方式解析xml文件,該技術涉及兩個部分:
解析器:使用JAXP的API創建,創建出解析器後就可以通過讀取器去解析某個 xml文檔。在解析的時候,只要解析到文件的一個組成部分就會去調用事件處理器的一個方法,在調用方法的時候會將當前解析的xml文件內容作爲方法的參數傳給事件處理器。
public void parse() throws Exception{ // 1.獲得解析器工廠 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2.獲得解析器對象 SAXParser parser = factory.newSAXParser(); // 3.獲得解析器的讀取器 XMLReader reader = parser.getXMLReader(); // 4.定義讀取器的內容處理器 reader.setContentHandler(new MyHandler()); // 5.使用讀取器進行解析xml文件 reader.parse("src/book.xml");
事件處理器:由程序員編寫,通過事件處理器方法的參數就可輕鬆得到sax解析器解析到的數據,從而對數據進行處理(通過事件處理器可以知道sax確實只適合進行讀取操作,不適合CRD)// 定義處理器類,實現內容處理器接口。如果不想實現過多方法可以繼承一個默認實現類DefaultHandler.只覆蓋想要覆蓋的方法 // class MyHandler extends DefaultHandler class MyHandler implements ContentHandler{ // 解析到開始標籤的處理方法 @Override public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {//將該標籤的所有屬性通過Attributes對象傳入 // 直接把開始標籤輸出 System.out.println("<"+ name + ">"); } // 解析到內容的處理方法 @Override public void characters(char[] ch, int start, int length) throws SAXException { // 直接輸出內容 System.out.println(new String(ch, start, length)); } // 解析到結束標籤的處理方法 @Override public void endElement(String uri, String localName, String name) throws SAXException { System.out.println("</"+ name + ">"); } } ......實現所有方法}
定義一個想要獲得某個標籤內容的處理器:例:結合反射將sax解析的數據封裝到指定的對象中// 繼承實現類,覆蓋部分方法 class GetContentHandler extends DefaultHandler{ // 定義一個變量,獲得當前處理的是哪個標籤 String currentname = null; String needname= "作者"; // 定義想要獲得第幾個標籤的內容 int neednumber = 2; int number = 0;//當前是第幾個該標籤 // 需要使用處理開始標籤,結束標籤,內容的方法 @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { currentname = qName; number++; } @Override public void characters(char[] ch, int start, int length) throws SAXException { // 如果當前是想要的標籤則輸出該內容 if(currentname.equals(needname) && neednumber==number){ System.out.println(new String(ch, start, length)); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // 將當前處理的標籤名置爲空,方便下次讀取。如果不清空就會把結束標籤後的換行符也當爲內容來處理,就會影響數據 currentname = null; } }
class BeanHandler extends DefaultHandler{ private List list = new ArrayList(); private String currentname = null; private Class clazz; private Object bean = null; public BeanHandler(Class clazz) { super(); this.clazz = clazz; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { currentname = qName; if("書".equals(currentname)){ try { bean = clazz.newInstance(); } catch (Exception e) { } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { try { Field f = clazz.getDeclaredField(currentname); f.setAccessible(true); f.set(bean, new String(ch,start,length)); } catch (Exception e) { } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("書".equals(qName)){ list.add(bean); bean = null; } currentname = null; } public List getList() { return list; } }
}
}
DOM4j{
}是一個簡單、靈活的開源的庫,性能優異,功能強大和極易使用。具體使用方法查看dom4j的快速入門文檔
// 1.創建一個SAX讀取器 SAXReader reader = new SAXReader(); // 2.通過讀取器直接讀取文件。 Document document = reader.read(new File("src/book.xml")); // 3.獲取根節點 Element root = document.getRootElement(); // 4.獲取根節點的子標籤(有嵌套就需要一層一層的獲得標籤) //獲得根節點下的第一個書標籤 Element book = (Element) root.elements("書").get(1); // 5.獲得這個書的書名這個標籤的內容及屬性name的值 String content = book.element("書名").getText(); String value = book.element("書名").attributeValue("name");
// 爲第一個書的標籤添加一個子標籤 public void add() throws DocumentException, IOException{ Document document = new SAXReader().read(new File("src/book.xml")); // 獲得文檔對象後,獲得根節點再獲得需要添加的標籤 Element book = document.getRootElement().element("書"); // 爲該標籤添加子標籤並賦值 book.addElement("售價").setText("50.00元"); // 再將內存中的文檔對象寫到xml文件中 //使用一個文件流來創建將文檔寫到文件的對象xmlwriter //亂碼問題:1.設置一個格式輸出器,設置它的編碼,要與xml文檔相同的編碼 OutputFormat format = OutputFormat.createPrettyPrint(); format.setEncoding("UTF-8"); // 2.如果使用字符流需要指定編碼表,如果使用字節流則不需要(字節流會自己查格式器的碼錶) // XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format); XMLWriter writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream("src/book.xml"),"UTF-8"),format); writer.write(document); writer.close(); }
// 在指定位置添加一個標籤 Document document = new SAXReader().read(new File("src/book.xml")); Element book = document.getRootElement().element("書"); List list = book.elements(); // 使用documentHelper來創建標籤,document無該方法 Element price = DocumentHelper.createElement("售價"); price.setText("100.00元"); // 將price存到list中的索引爲2的地方(第三個節點),自動將索引爲2或以後的後移 list.add(2, price);<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>//更新到xml文件 <span style="white-space:pre"> </span>OutputFormat format = OutputFormat.createPrettyPrint(); <span style="white-space:pre"> </span>format.setEncoding("UTF-8"); <span style="white-space:pre"> </span>XMLWriter writer = new XMLWriter(new FileOutputStream("src/book.xml"),format); <span style="white-space:pre"> </span>writer.write(document); <span style="white-space:pre"> </span>writer.close();
如果要獲得指定的標籤,結合xpath使用即可:例:SAXReader reader = new SAXReader(); Document document = reader.read(new File("src/book.xml")); List list = document.selectNodes("//作者");//查找多個 Node node = document.selectSingleNode("//作者");//查找單個
//xpath應用在查找數據 public void login(String username, String password) throws DocumentException{ Document document = new SAXReader().read(new File("src/users.xml")); // 獲得一個屬性名爲name值爲username並且另一個屬性爲password,值爲password的user標籤 Node node = document.selectSingleNode("//user[@name='"+username+"'and @password='"+password+"']"); if(node == null){ System.out.println("失敗"); }else{ System.out.println("成功"); } }