XML文件解析

作者:xcbeyond
瘋狂源自夢想,技術(shù)成就輝煌!微信公眾號(hào):《程序猿技術(shù)大咖》號(hào)主,專注后端開發(fā)多年,擁有豐富的研發(fā)經(jīng)驗(yàn),樂于技術(shù)輸出、分享,現(xiàn)階段從事微服務(wù)架構(gòu)項(xiàng)目的研發(fā)工作,涉及架構(gòu)設(shè)計(jì)、技術(shù)選型、業(yè)務(wù)研發(fā)等工作。對于Java、微服務(wù)、數(shù)據(jù)庫、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗(yàn)。

XML解析:
    在xml文件中由于更多的是描述信息的內(nèi)容,所以在得到一個(gè)xml文檔之后應(yīng)該利用程序按照里面元素的定義名稱取出對應(yīng)的內(nèi)容,這一過程就稱為xml解析。

解析xml文件的4種方式:
1.DOM         
2.SAX
3.JDOM    
4.DOM4J

文檔對象模型(DOM)

DOM---對象化的XML數(shù)據(jù)接口
 它定義了XML文檔的邏輯結(jié)構(gòu),給出了一種訪問和處理XML文檔的方法。利用DOM,程序開發(fā)人員可以動(dòng)態(tài)地創(chuàng)建文檔,遍歷文檔結(jié)構(gòu),添加、修改、刪除文檔內(nèi)容,改變文檔的顯示方式等等。

DOM樹
  DOM這個(gè)層次的結(jié)構(gòu)是一棵根據(jù)XML文檔生成的節(jié)點(diǎn)樹。在這棵節(jié)點(diǎn)樹中,有一個(gè)根節(jié)點(diǎn)--Document節(jié)點(diǎn),所有其他的節(jié)點(diǎn)都是根節(jié)點(diǎn)的后代節(jié)點(diǎn)。節(jié)點(diǎn)樹生成之后,就可以通過DOM接口訪問、修改、添加、刪除、創(chuàng)建樹中的節(jié)點(diǎn)和內(nèi)容。

讀入xml:
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
// 獲取解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析xml文檔
Document doc = builder.parse(new File("src\\dom.xml"));
Element root = builder.getDocumentElement();//獲得根元素
寫回xml:
TransformerFactory tfactory=TransformerFactory.newInstance();
Transformer tformer = tfactory.newTransformer();
tformer.transform(new DOMSource(doc), new StreamResult(new FileOutputStream("src\\dom1.xml")));

得到文檔模型的根元素
Element root = doc.getDocumentElement();  
元素Element的函數(shù):
String getTagName()   -得到標(biāo)簽的名字
String getAttribute(“unit”) -得到元素的unit屬性值
節(jié)點(diǎn)Node的函數(shù):
NodeList  getChildNodes()   - 得到子節(jié)點(diǎn)的集合
Node getFirstChild()         - 得到第一個(gè)子節(jié)點(diǎn)
Node getLastChild()        - 得到最后一個(gè)子節(jié)點(diǎn)

節(jié)點(diǎn)Node的函數(shù):
Node getNextSibling() - 得到下一個(gè)兄弟節(jié)點(diǎn)
Node getPreviousSibling()   - 得到前一個(gè)兄弟結(jié)點(diǎn)
Node getParentNode()     - 得到父節(jié)點(diǎn)
NamedNodeMap getAttributes()  - 得到所有的屬性集合
String getNodeName()         - 得到當(dāng)前節(jié)點(diǎn)的名字
String getNodeValue()   - 得到當(dāng)前節(jié)點(diǎn)的值
NodeList的函數(shù)
int getLength()    -得到集合長度
Node item(int index)  - 得到集合中的一個(gè)元素

寫XML文檔函數(shù)
DocumentBuilder 的函數(shù):
Document doc = builder.newDocument(); -新建一個(gè)模型
Document 的函數(shù):
Element createElement(String name) – 建立一個(gè)元素
Text createTextNode(String data)-創(chuàng)建一個(gè)文本節(jié)點(diǎn)
Node的函數(shù):
Node appendChild(Node child)  - 添加一個(gè)子節(jié)點(diǎn)
Element 的函數(shù):
void setAttribute(String name, String value)  - 設(shè)置元素的一個(gè)屬性和屬性值

簡單應(yīng)用程序接口(SAX)

SAX是一種事件驅(qū)動(dòng)的接口,它的基本原理是由接口的用戶提供符合定義的處理器,XML分析時(shí)遇到特定的事件,就去調(diào)用處理器中特定事件的處理函數(shù)。

捕獲和響應(yīng)各個(gè)事件
startDocument( ) 和 endDocument( ) 事件是在文檔的起始處和結(jié)束處被激發(fā)的
 startElement( ) 和 endElement( ) 事件是在遇到起始標(biāo)記和結(jié)束標(biāo)記時(shí)被激發(fā)的
 characters( ) 事件是在遇到字符數(shù)據(jù)時(shí)被激發(fā)的

使用 SAX 解析 XML 文檔的步驟如下:
創(chuàng)建 SAXParserFactory 的實(shí)例
創(chuàng)建 SAXParser 的實(shí)例
創(chuàng)建 SAXParserHandler 類
使用 parse() 方法解析 XML 文檔

SAXParserFactory spfactory = SAXParserFactory.newInstance();
// 生成SAX解析對象
SAXParser parser = spfactory.newSAXParser();
// 指定XML文件,進(jìn)行XML解析
 parser.parse(new File("src\\dom.xml"), new SaxReader());

 






Jdom

JDOM 使用標(biāo)準(zhǔn)的 Java 編碼模式,用以來彌補(bǔ)DOM及SAX在實(shí)際應(yīng)用當(dāng)中的不足之處。
這些不足之處主要在于SAX沒有文檔修改、隨機(jī)訪問以及輸出的功能,而對于DOM來說,在使用時(shí)來用起來不太方便。
在 JDOM 中,XML 元素就是 Element 的實(shí)例,XML 屬性就是 Attribute 的實(shí)例,XML 文檔本身就是 Document 的實(shí)例。
因?yàn)?JDOM 對象就是像 Document、Element 和 Attribute 這些類的直接實(shí)例,因此創(chuàng)建一個(gè)新 JDOM 對象就如在 Java 語言中使用 new 操作符一樣容易。而不使用復(fù)雜的工廠化模式,使對象操作更為方便。

Document類操作
Element root=new Element("GREETING");
Document doc=new Document(root);
root.setText("HelloJDOM!");

Attribute 類操作
Attribute rootAttri = new Attribute("comment","introduce myself");//創(chuàng)建名為 commnet,值為 introduce myself 的屬性。
rootElement.setAttribute(rootAttri);//將剛創(chuàng)建的屬性添加到根元素。

Element類操作
Element root=doc.getRootElement();//獲得根元素element
List allChildren=root.getChildren();//獲得所有子元素的一個(gè)list
List namedChildren=root.getChildren("name");//獲得指定名稱子元素的list
Element child=root.getChild(“name”);//獲得指定名稱的第一個(gè)子元素
allChildren.remove(3);//刪除第四個(gè)子元素
allChildren.removeAll(root.getChildren("jack"));//刪除叫“jack”的子元素
root.removeChildren("jack");//便捷寫法
allChildren.add(new Element("jane"));//加入
root.addContent(new Element(“jane”));//便捷寫法
Element nameElement = new Element("name");//創(chuàng)建 name 元素
nameElement.addContent("kingwong");//將kingwong作為content添加到name元素
rootElement.addContent(nameElement);//將name元素作為content添加到根元素 getAttributeValue("name") 返回指定屬性名字的值。如果沒有該屬性則返回null,有該屬性但是值為空,則返回空字符串。
getChildText("childname") 返回指定子節(jié)點(diǎn)的內(nèi)容文本值。  
root.getChild("book").getChild("name").getText();
root.getChild("book").getChild("name").setText("dsgdghdgasg");

解析xml
使用Jdom解析xml要導(dǎo)入org.dom的jar包
1.實(shí)例化一個(gè)合適的解析器對象
SAXBuilder builder = new SAXBuilder();
2.構(gòu)建一個(gè)文檔對象doc
Document doc = builder.build(new File("src\\dom.xml"));
XML文檔輸出
XMLOutputter outputter=new XMLOutputter();
outputter.output(doc,new FileOutputStream("src\\dom.xml"));

 

Dom4j

Dom4j是一個(gè)Java的XML API,類似于jdom,用來讀寫XML文件的。它應(yīng)用于Java平臺(tái),采用了Java集合框架并完全支持DOM,SAX和JAXP。

1.讀取并解析XML文檔:
讀寫XML文檔主要依賴于org.dom4j.io包,其中提供DOMReader和SAXReader兩類不同方式,而調(diào)用方式是一樣的。這就是依靠接口的好處。 // 從文件讀取XML,輸入文件名,返回XML文檔
public Document read(String fileName) throws MalformedURLException, DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(new File(fileName));
return document;
}
2、取得Root節(jié)點(diǎn)
  public Element getRootElement(Document doc){
return doc.getRootElement();
}

3、遍歷XML樹
for ( Iterator i = root.elementIterator(); i.hasNext(); ) {// 枚舉所有子節(jié)點(diǎn)
Element element = (Element) i.next();}
for ( Iterator i = root.elementIterator(foo); i.hasNext();) {// 枚舉名稱為foo的節(jié)點(diǎn)
Element foo = (Element) i.next();} // 枚舉屬性
for ( Iterator i = root.attributeIterator(); i.hasNext(); ) {
Attribute attribute = (Attribute) i.next();}

遞歸也可以采用Iterator作為枚舉手段,但文檔中提供了另外的做法

public void treeWalk() {
         treeWalk(getRootElement());
 }
 public void treeWalk(Element element) {
       for (int i = 0, size = element.nodeCount(); i < size; i++) {
           Node node = element.node(i);
          if (node instanceof Element) {
              treeWalk((Element) node);
         }   else { // do something....
       }
  }
 }
獲取節(jié)點(diǎn)數(shù)量,包含自身。 這個(gè)方法所遍歷出來的對象是多種的,node,namespace,text等類型的。 if(element instanceof Element) 條件 element.nodeCount()==1 表示當(dāng)前元素是子元素

4. 創(chuàng)建XML
public Document createDocument() {
 Document document = DocumentHelper.createDocument();
 Element root = document.addElement(root);
 Element author1 =root.addElement(author).addAttribute(name, James)
  .addAttribute(location, UK).addText(James Strachan);
 Element author2 =root.addElement(author).addAttribute(name, Bob)
  .addAttribute(location, US).addText(Bob McWhirter);
 return document;
}
5字符串與XML的轉(zhuǎn)換
有時(shí)候經(jīng)常要用到字符串轉(zhuǎn)換為XML或反之
// XML轉(zhuǎn)字符串
Document document = ...;
String text = document.asXML();
// 字符串轉(zhuǎn)XML
String text = <name>James</name>   
Document document = DocumentHelper.parseText(text);
6文件輸出
一個(gè)簡單的輸出方法是將一個(gè)Document或任何的Node通過write方法輸出
FileWriter out = new FileWriter( foo.xml );
 document.write(out);
美化輸出或縮進(jìn)格式,可以用XMLWriter類 public void write(Document document) throws IOException {
// 讀取文件
FileWriter fileWriter = new FileWriter("src\\dom2.xml");
//OutputFormat xmlFormat = OutputFormat.createPrettyPrint();// 縮減型格式
OutputFormat xmlFormat =OutputFormat.createCompactFormat();//緊湊型格式
//format.setTrimText(false);//設(shè)置text中是否要?jiǎng)h除其中多余的空格
xmlFormat.setEncoding("gb2312");// 設(shè)置編碼
// 創(chuàng)建寫文件方法
XMLWriter xmlWriter = new XMLWriter(fileWriter, xmlFormat);
// 寫入文件
xmlWriter.write(document);
// 關(guān)閉
xmlWriter.close();
}