XML就是這麼簡單

什麼是XML?

XML:extensiable markup language 被稱做可擴展標記語言css

XML簡單的歷史介紹:html

  • gml->sgml->html->xml
  • gml(通用標記語言)–在不一樣的機器進行通訊的數據規範
  • sgml(標準通用標記語言)
  • html(超文本標記語言)

爲何咱們須要使用XML呢?

  • ①咱們沒有XML這種語言以前,咱們使用的是String做爲兩個程序之間的通信!如今問題就來了,若是咱們傳輸的是帶有關係型結構的數據,String怎麼表達呢?String對關係型數據不擅長,要是描述起來也不免會有歧義的時候!關係型數據如圖下所示:

 

 

  • HTML語言自己就有缺陷
    • **標記都是固定的,不能自定義。HTML語言中有什麼標記就只能用什麼標記 **
    • HTML標籤自己就缺乏含義(tr標籤裏面什麼內容都能放進去,不規範!!)
    • HTML沒有實現真正的國際化

XML文件就解決了以上的問題了,若是使用XML描述上述圖片的關係,是很是簡單的!node

<?xml version="1.0" encoding="UTF-8" ?>
	<中國>
	    <北京>
	        <海淀></海淀>
	        <豐臺></豐臺>
	    </北京>
	    <湖南>
	        <長沙></長沙>
	        <岳陽></岳陽>
	    </湖南>
	    <湖北>
	        <武漢></武漢>
	        <荊州></荊州>
	    </湖北>
	</中國>

XML文件還能使用瀏覽器打開:程序員

 

 

咱們能夠發現XML是能夠描述很複雜的數據關係的web

XML的用途

①:配置文件(例子:Tomcat的web.xml,server.xml......),XML可以很是清晰描述出程序之間的關係數據庫

②:程序間數據的傳輸,XML的格式是通用的,可以減小交換數據時的複雜性!瀏覽器

③:充當小型數據庫,若是咱們的數據有時候須要人工配置的,那麼XML充當小型的數據庫是個不錯的選擇,程序直接讀取XML文件顯然要比讀取數據庫要快呢!微信

XML的技術架構#

XML被設計爲「什麼都不作」,XML數據或XML文檔只用於組織、存儲數據,除此以外的數據生成、讀取、傳送、存取等等操做都與XML自己無關!架構

因而乎,想要操做XML,就須要用到XML以外的技術了app

  • 爲XML定規則:如今通常使用DTD或Schema技術,固然了Schema技術更爲先進!
  • 解析XML的數據:通常使用DOM或者SAX技術,各有各的優勢
  • 提供樣式:XML通常用來存儲數據的,但設計者野心很大,也想用來顯示數據(但沒人用XML來顯示數據),就有了XSLT(eXtensiable Stylesheet Language Transformation)可擴展樣式轉換語言

XML語法:

文檔聲明:

  • XML聲明放在XML的第一行

  • version----版本

  • encoding--編碼

  • standalone--獨立使用--默認是no。standalone表示該xml是否是獨立的,若是是yes,則表示這個XML文檔時獨立的,不能引用外部的DTD規範文件;若是是no,則該XML文檔不是獨立的,表示能夠引用外部的DTD規範文檔。

  • 正確的文檔聲明格式,屬性的位置不能改變!

<?xml version="1.0" encoding="utf-8" standalone="no"?>


 

元素

首先在這裏說明一個概念:在XML中元素和標籤指的是同一個東西!不要被不一樣的名稱所迷惑了!

元素中須要值得注意的地方

  • XML元素中的出現的空格和換行都會被當作元素內容進行處理
  • 每一個XML文檔必須有且只有一個根元素
  • 元素必須閉合
  • 大小寫敏感
  • 不能交叉嵌套
  • 不能以數字開頭

看起來好像有不少須要值得注意的地方,其實只須要記住:XML的語法是規範的!不要隨意亂寫!

屬性

屬性是做爲XML元素中的一部分的,命名規範也是和XML元素同樣的!

<!--屬性名是name,屬性值是china-->
	<中國 name="china">

	</中國>

註釋

註釋和HTML的註釋是同樣的

<!---->

CDATA

在編寫XML文件時,有些內容可能不想讓解析引擎解析執行,而是看成原始內容處理。遇到此種狀況,能夠把這些內容放在CDATA區裏,對於CDATA區域內的內容,XML解析程序不會處理,而是直接原封不動的輸出

語法:

<![CDATA[
		...內容
	]]>

轉義字符

對於一些單個字符,若想顯示其原始樣式,也可使用轉義的形式予以處理。

 

 

處理指令

處理指令,簡稱PI (processing instruction)。處理指令用來指揮解析引擎如何解析XML文檔內容。

例如:

在XML文檔中可使用xml-stylesheet指令,通知XML解析引擎,應用css文件顯示xml文檔內容。

<?xml-stylesheet type="text/css" href="1.css"?>
  • XML代碼:
<?xml version="1.0" encoding="UTF-8" ?>
	<?xml-stylesheet type="text/css" href="1.css"?>
	
	<china>
	    <guangzhou>
	        廣州
	    </guangzhou>
	    <shenzhen>
	        深圳
	    </shenzhen>
	</china>
  • CSS代碼:
guangzhou{
	    font-size: 40px;
	}
  • 效果:

 

 

JDK中的XML API

①:JAXP(The Java API For XML Processing):主要負責解析XML

②:JAXB(Java Architecture for XML Binding):主要負責將XML映射爲Java對象

什麼是XML解析

前面XML章節已經說了,XML被設計爲「什麼都不作」,XML只用於組織、存儲數據,除此以外的數據生成、讀取、傳送等等的操做都與XML自己無關!

XML解析就是讀取XML的數據!

XML解析方式

XML解析方式分爲兩種:

①:dom(Document Object Model)文檔對象模型,是W3C組織推薦解析XML的一種方式

②:sax(Simple API For XML),它是XML社區的標準,幾乎全部XML解析器都支持它!

XML解析操做

 

 

從上面的圖很容易發現,應用程序不是直接對XML文檔進行操做的,而是由XML解析器對XML文檔進行分析,而後應用程序經過XML解析器所提供的DOM接口或者SAX接口對分析結果進行操做,從而間接地實現了對XML文檔的訪問!

經常使用的解析器和解析開發包的關係以下所示

 

 

爲何有3種開發包?

  • jaxp開發包是JDK自帶的,不須要導入開發包。
  • 因爲sun公司的jaxp不夠完善,因而就被研發了Jdom。XML解析若是使用Jdom,須要導入開發包
  • dom4j是因爲Jdom的開發人員出現了分歧,dom4j由Jdom的一批開發人員所研發。XML解析若是使用Jdom,須要導入開發包【如今用dom4j是最多的!】

jaxp

雖然jaxp解析XML的性能以及開發的簡易度是沒有dom4j好,可是jaxp無論怎麼說都是JDK內置的開發包,咱們是須要學習的

DOM解析操做

DOM解析是一個基於對象的API,它把XML的內容加載到內存中,生成與XML文檔內容對應的模型!當解析完成,內存中會生成與XML文檔的結構與之對應的DOM對象樹,這樣就可以根據樹的結構,以節點的形式對文檔進行操做!

簡單來講:DOM解析會把XML文檔加載到內存中,生成DOM樹的元素都是以對象的形式存在的!咱們操做這些對象就可以操做XML文檔了!

  • 下面這樣圖就能很好地說明了,是怎麼樣生成與XML文檔內容對應的DOM樹!

 

 

既然XML文檔的數據是帶有關係型的,那麼生成的DOM樹的節點也是有關係的:

  • 位於一個節點之上的節點是該節點的父節點(parent)
  • 一個節點之下的節點是該節點的子節點(children)
  • 同一層次,具備相同父節點的節點是兄弟節點(sibling)
  • 一個節點的下一個層次的節點集合是節點後代(descendant)
  • 父、祖父節點及全部位於節點上面的,都是節點的祖先(ancestor)

在DOM解析中有幾個核心的操做接口:

  • Document【表明整個XML文檔,經過Document節點能夠訪問XML文件中全部的元素內容!】
  • Node【Node節點幾乎在XML操做接口中幾乎至關於普通Java類的Object,不少核心接口都實現了它,在下面的關係圖能夠看出!】
  • NodeList【表明着一個節點的集合,一般是一個節點中子節點的集合!】
  • NameNodeMap【表示一組節點和其惟一名稱對應的一一對應關係,主要用於屬性節點的表示(書上說是核心的操做接口,但我好像沒用到!呃呃呃,等我用到了,我再來填坑!)】

節點之間的關係圖:

 

 

  • 有人可能會很難理解,爲何Document接口比Node接口還小,呃呃呃,我是這樣想的:一個Document由無數個Node組成,這樣我也能把Document當成是Node呀!若是實在想不通:人家都這樣設計了,你有種就不用啊!!(開玩笑的.....)

好的,不跟大家多bb,咱們來使用一下Dom的方式解析XML文檔吧!

  • XML文檔代碼
<?xml version="1.0" encoding="UTF-8" ?>
	<china>
	    <guangzhou >廣州</guangzhou>
	    <shenzhen>深圳</shenzhen>
	    <beijing>北京</beijing>
	    <shanghai>上海</shanghai>
	</china>
  • 根據XML解析的流程圖,咱們先要獲取到解析器對象!
public class DomParse {
	
	    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
	
	        //API規範:須要用一個工廠來造解析器對象,因而我先造了一個工廠!
	        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
	
	        //獲取解析器對象
	        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
	
	        //獲取到解析XML文檔的流對象
	        InputStream inputStream = DomParse.class.getClassLoader().getResourceAsStream("city.xml");
	
	        //解析XML文檔,獲得了表明XML文檔的Document對象!
	        Document document = documentBuilder.parse(inputStream);
	        
	    }
	}
  • 解析XML文檔的內容用來幹嗎?無非就是增刪改查遍歷,只要咱們會對XML進行增刪改查,那就說明咱們是會使用DOM解析的

遍歷

  • 咱們再來看一下XML文檔的內容,若是咱們要遍歷該怎麼作?

 

 

  • 可能咱們會有兩種想法

    • ①:從XML文檔內容的上往下看,看到什麼就輸出什麼!【這正是SAX解析的作法】
    • ②:把XML文檔的內容分紅兩部分,一部分是有子節點的,一部分是沒有子節點的(也就是元素節點!)。首先咱們判斷是否爲元素節點,若是是元素節點就輸出,不是元素節點就獲取到子節點的集合,再判斷子節點集合中的是不是元素節點,若是是元素節點就輸出,若是不是元素節點獲取到該子節點的集合....好的,一不當心就遞歸了...
  • 咱們來對XML文檔遍歷一下吧,爲了更好地重用,就將它寫成一個方法吧(也是可以更好地用遞歸實現功能)

public class DomParse {
	
	    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
	
	        //API規範:須要用一個工廠來造解析器對象,因而我先造了一個工廠!
	        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
	
	        //獲取解析器對象
	        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
	
	        //獲取到解析XML文檔的File對象
	        InputStream inputStream = DomParse.class.getClassLoader().getResourceAsStream("city.xml");
	
	        //解析XML文檔,獲得了表明XML文檔的Document對象!
	        Document document = documentBuilder.parse(inputStream);
	
	        //把表明XML文檔的document對象傳遞進去給list方法
	        list(document);
	
	    }
	
	
	    //咱們這裏就接收Node類型的實例對象吧!多態!!!
	    private static void list(Node node) {
	
	        //判斷是不是元素節點,若是是元素節點就直接輸出
	        if (node.getNodeType() == Node.ELEMENT_NODE) {
	            System.out.println(node.getNodeName());
	        }
	
	        //....若是沒有進入if語句,下面的確定就不是元素節點了,因此獲取到子節點集合
	        NodeList nodeList = node.getChildNodes();
	
	        //遍歷子節點集合
	        for (int i = 0; i < nodeList.getLength(); i++) {
	
	            //獲取到其中的一個子節點
	            Node child = nodeList.item(i);
	
	            //...判斷該子節點是否爲元素節點,若是是元素節點就輸出,不是元素節點就再獲取到它的子節點集合...遞歸了
	
	            list(child);
	        }
	        
	    }
	}
  • 效果:

 

 

查詢

如今我要作的就是:讀取guangzhou這個節點的文本內容!

private static void read(Document document) {

        //獲取到全部名稱爲guangzhou節點
        NodeList nodeList = document.getElementsByTagName("guangzhou");
        
        //取出第一個名稱爲guangzhou的節點
        Node node = nodeList.item(0);
        
        //獲取到節點的文本內容
        String value = node.getTextContent();

        System.out.println(value);

    }
  • 效果:

 

 

增長

如今我想多增長一個城市節點(杭州),我須要這樣作:

private static void add(Document document) {

        //建立須要增長的節點
        Element element = document.createElement("hangzhou");

        //向節點添加文本內容
        element.setTextContent("杭州");

        //獲得須要添加節點的父節點
        Node parent = document.getElementsByTagName("china").item(0);

        //把須要增長的節點掛在父節點下面去
        parent.appendChild(element);

    }
  • 作到這裏,我僅僅在內存的Dom樹下添加了一個節點,要想把內存中的Dom樹寫到硬盤文件中,須要轉換器

  • 獲取轉換器也十分簡單

//獲取一個轉換器它須要工廠來造,那麼我就造一個工廠
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        
        //獲取轉換器對象
        Transformer transformer = transformerFactory.newTransformer();
  • 把內存中的Dom樹更新到硬盤文件中的transform()方法就稍稍有些複雜了

 

 

  • 它須要一個Source實例對象和Result的實例對象,這兩個接口究竟是什麼玩意啊?

  • 因而乎,我就去查API,發現DomSource實現了Source接口,咱們使用的不正是Dom解析嗎,再看看構造方法,感受就是它了!

 

 

  • 而SteamResult實現了Result接口,有人也會想,DomResult也實現了Result接口啊,爲何不用DomResult呢?咱們如今作的是把內存中的Dom樹更新到硬盤文件中呀,固然用的是StreamResult啦!

  • 完整代碼以下:

private static void add(Document document) throws TransformerException {

        //建立須要增長的節點
        Element element = document.createElement("hangzhou");

        //向節點添加文本內容
        element.setTextContent("杭州");

        //獲得須要添加節點的父節點
        Node parent = document.getElementsByTagName("china").item(0);

        //把須要增長的節點掛在父節點下面去
        parent.appendChild(element);

        //獲取一個轉換器它須要工廠來造,那麼我就造一個工廠
        TransformerFactory transformerFactory = TransformerFactory.newInstance();

        //獲取轉換器對象
        Transformer transformer = transformerFactory.newTransformer();

        //把內存中的Dom樹更新到硬盤中
        transformer.transform(new DOMSource(document),new StreamResult("city.xml"));
    }
  • 效果:

 

 

剛剛增長的節點是在china節點的末尾處的,如今我想指定增長節點的在beijing節點以前,是這樣作的:

private static void add2(Document document) throws TransformerException {

        //獲取到beijing節點
        Node beijing = document.getElementsByTagName("beijing").item(0);

        //建立新的節點
        Element element = document.createElement("guangxi");

        //設置節點的文本內容
        element.setTextContent("廣西");

        //獲取到要建立節點的父節點,
        Node parent = document.getElementsByTagName("china").item(0);

        //將guangxi節點插入到beijing節點以前!
        parent.insertBefore(element, beijing);

        //將內存中的Dom樹更新到硬盤文件中
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.transform(new DOMSource(document), new StreamResult("city.xml"));
        
    }
  • 效果:

 

 

刪除

如今我要刪除的是beijing這個節點!

private static void delete(Document document) throws TransformerException {

        //獲取到beijing這個節點
        Node node = document.getElementsByTagName("beijing").item(0);

        //獲取到父節點,而後經過父節點把本身刪除了
        node.getParentNode().removeChild(node);

        //把內存中的Dom樹更新到硬盤文件中
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.transform(new DOMSource(document), new StreamResult("city.xml"));


    }
  • 效果:

 

 

修改

將guangzhou節點的文本內容修改爲廣州你好

private static void update(Document document) throws TransformerException {

        //獲取到guangzhou節點
        Node node = document.getElementsByTagName("guangzhou").item(0);

        node.setTextContent("廣州你好");

        //將內存中的Dom樹更新到硬盤文件中
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.transform(new DOMSource(document), new StreamResult("city.xml"));


    }
  • 效果:

 

 

操做屬性

XML文檔是可能帶有屬性值的,如今咱們要guangzhou節點上的屬性

private static void updateAttribute(Document document) throws TransformerException {

        //獲取到guangzhou節點
        Node node = document.getElementsByTagName("guangzhou").item(0);

        //如今node節點沒有增長屬性的方法,因此我就要找它的子類---Element
        Element guangzhou = (Element) node;

        //設置一個屬性,若是存在則修改,不存在則建立!
        guangzhou.setAttribute("play", "gzchanglong");

        //若是要刪除屬性就用removeAttribute()方法


        //將內存中的Dom樹更新到硬盤文件中
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.transform(new DOMSource(document), new StreamResult("city.xml"));


    }
  • 效果:

 

 

SAX解析

SAX採用的是一種順序的模式進行訪問,是一種快速讀取XML數據的方式。當時候SAX解析器進行操做時,會觸發一系列事件SAX。採用事件處理的方式解析XML文件,利用 SAX 解析 XML 文檔,涉及兩個部分:解析器和事件處理器

sax是一種推式的機制,你建立一個sax 解析器,解析器在發現xml文檔中的內容時就告訴你(把事件推給你). 如何處理這些內容,由程序員本身決定。

當解析器解析到<?xml version="1.0" encoding="UTF-8" standalone="no"?>聲明頭時,會觸發事件。解析到<china>元素頭時也會觸發事件!也就是說:當使用SAX解析器掃描XML文檔(也就是Document對象)開始、結束,以及元素的開始、結束時都會觸發事件,根據不一樣事件調用相對應的方法!

 

 

首先咱們仍是先拿到SAX的解析器再說吧!

//要獲得解析器對象就須要造一個工廠,因而我造了一個工廠
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        
        //獲取到解析器對象
        SAXParser saxParse = saxParserFactory.newSAXParser();


 

  • 調用解析對象的解析方法的時候,須要的不只僅是XML文檔的路徑!還須要一個事件處理器!

 

 

  • 事件處理器都是由咱們程序員來編寫的,它通常繼承DefaultHandler類,重寫以下5個方法:
@Override
    public void startDocument() throws SAXException {
        super.startDocument();
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
    }
  • 獲取解析器,調用解析器解析XML文檔的代碼:
public static void main(String[] args) throws Exception{

        //要獲得解析器對象就須要造一個工廠,因而我造了一個工廠
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();

        //獲取到解析器對象
        SAXParser saxParse = saxParserFactory.newSAXParser();

        //獲取到XML文檔的流對象
        InputStream inputStream = SAXParse.class.getClassLoader().getResourceAsStream("city.xml");

        saxParse.parse(inputStream, new MyHandler());

    }
  • 事件處理器的代碼:
public class MyHandler extends DefaultHandler {
	    @Override
	    public void startDocument() throws SAXException {
	        System.out.println("我開始來掃描啦!!!!");
	    }
	
	    @Override
	    public void endDocument() throws SAXException {
	
	        System.out.println("我結束了!!!!");
	    }
	
	    @Override
	    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

			//若是要解析出節點屬性的內容,也很是簡單,只要經過attributes變量就好了!

			//輸出節點的名字!
	        System.out.println(qName);
	    }
	
	    @Override
	    public void endElement(String uri, String localName, String qName) throws SAXException {
	
	        System.out.println(qName);
	    }
	
	    @Override
	    public void characters(char[] ch, int start, int length) throws SAXException {
	
	        System.out.println(new String(ch,start,length));
	    }
	}
  • 咱們發現,事件處理器的代碼都很是簡單,而後就如此簡單地就可以遍歷整個XML文檔了!

  • 若是要查詢單獨的某個節點的內容也是很是簡單的喲!只要在startElement()方法中判斷名字是否相同便可!

  • 如今我只想查詢guangzhou節點的內容:

//定義一個標識量,用於指定查詢某個節點的內容
    boolean flag = false;

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

        //若是節點名稱是guangzhou,我才輸出,而且把標識量設置爲true
        if (qName == "guangzhou") {
            System.out.println(qName);
            flag = true;
        }
    }


    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //只有在flag爲true的狀況下我才輸出文本的內容
        if (flag == true) {
            System.out.println(new String(ch, start, length));

        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {

        //在執行到元素的末尾時,不要忘了將標識量改爲false
        if (qName == "guangzhou" && flag == true) {
            System.out.println(qName);
            flag = false;

        }
    }
  • 效果:

 

 

DOM和SAX解析的區別:

DOM解析讀取整個XML文檔,在內存中造成DOM樹,很方便地對XML文檔的內容進行增刪改。但若是XML文檔的內容過大,那麼就會致使內存溢出!

SAX解析採用部分讀取的方式,能夠處理大型文件,但只能對文件按順序從頭至尾解析一遍,不支持文件的增刪改操做

DOM和SAX解析有着明顯的差異,何時使用DOM或者SAX就很是明瞭了。

dom4j

Dom4j是一個很是優秀的Java XML API,具備性能優異、功能強大和極易使用的特色。

爲何須要有dom4j

  • dom缺點:比較耗費內存

  • sax缺點:只能對xml文件進行讀取,不能修改,添加,刪除

  • dom4j:既能夠提升效率,同時也能夠進行crud操做

由於dom4j不是sun公司的產品,因此咱們開發dom4j須要導入開發包

獲取dom4j的解析器

  • 使用dom4j對XML文檔進行增刪改查,都須要獲取到dom4j的解析器
//獲取到解析器
        SAXReader saxReader = new SAXReader();

        //獲取到XML文件的流對象
        InputStream inputStream = DOM4j.class.getClassLoader().getResourceAsStream("1.xml");

        //經過解析器讀取XML文件
        Document document = saxReader.read(inputStream);

獲取Document對象

咱們都知道,Document表明的是XML文檔,通常咱們都是經過Document對象開始,來進行CRUD(增刪改查)操做的!

獲取Document對象有三種方式:

①:讀取XML文件,得到document對象(這種最經常使用)

SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));

②:解析XML形式的文本,獲得document對象

String text = "<members></members>";
	Document document=DocumentHelper.parseText(text);

③:主動建立document對象.

Document document =DocumentHelper.createDocument();

//建立根節點
Element root = document.addElement("members");

CRUD的重要一句話:

讀取XML文檔的數據,都是經過Document獲取根元素,再經過根元素獲取獲得其餘節點的,從而進行操做!

若是XML的結構有多層,須要一層一層地獲取!

查詢

@Test
    public void read() throws DocumentException {

        //獲取到解析器
        SAXReader saxReader = new SAXReader();

        //獲取到XML文件的流對象
        InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");
   
        //經過解析器讀取XML文件
        Document document = saxReader.read(inputStream);

        //獲取獲得根節點
        Element root = document.getRootElement();

        //獲取獲得name節點
        Element name = root.element("name");

        //獲得了name節點,就能夠獲取name節點的屬性或者文本內容了!
        String text = name.getText();

        String attribute = name.attributeValue("littleName");

        System.out.println("文本內容是:" + text);
        System.out.println("屬性內容是:" + attribute);
        
    }
  • XML文件以下:
<?xml version="1.0" encoding="UTF-8" ?>
	     <person>
	    <name littleName="fucheng">zhongfucheng</name>
	    <age>20</age>
	</person>
  • 效果:

 

 

  • 多層結構的查詢:
//獲取獲得根節點
        Element root = document.getRootElement();

        //一層一層地獲取到節點
        Element element = root.element("guangdong").element("guangzhou").element("luogang");

        String value = element.getText();

        System.out.println(value);
  • XML文件和結果:

 

 

增長

在DOM4j中要對內存中的DOM樹寫到硬盤文件中,也是要有轉換器的支持的!

dom4j提供了XMLWriter供咱們對XML文檔進行更新操做,通常地建立XMLWriter的時候咱們都會給出兩個參數,一個是Writer,一個是OutputFormat

 

 

這個OutputFormat有什麼用的呢?其實就是指定回寫XML的格式和編碼格式。細心的朋友會發現,上面咱們在jaxp包下使用dom解析的Transformer類,把內存中的DOM樹更新到文件硬盤中,是沒有格式的!不信倒回去看看!這個OutputFormat就可讓咱們更新XML文檔時也能帶有格式

//建立帶有格式的對象
        OutputFormat outputFormat = OutputFormat.createPrettyPrint();

        //設置編碼,默認的編碼是gb2312,讀寫的編碼不一致,會致使亂碼的!
        outputFormat.setEncoding("UTF-8");

        //建立XMLWriter對象
        XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);

        //XMLWriter對象寫入的是document
        xmlWriter.write(document);

        //關閉流
        xmlWriter.close();
  • 下面咱們就爲在person節點下新建立一個name節點吧,完整的代碼以下:
@Test
    public void add() throws Exception {

        //獲取到解析器
        SAXReader saxReader = new SAXReader();

        //獲取到XML文件的流對象
        InputStream inputStream = dom4j11.class.getClassLoader().getResourceAsStream("1.xml");

        //經過解析器讀取XML文件
        Document document = saxReader.read(inputStream);

        //建立出新的節點,爲節點設置文本內容
        Element newElement = DocumentHelper.createElement("name");
        newElement.setText("ouzicheng");

        //獲取到根元素
        Element root = document.getRootElement();

        //把新建立的name節點掛在根節點下面
        root.add(newElement);

        //建立帶有格式的對象
        OutputFormat outputFormat = OutputFormat.createPrettyPrint();

        //設置編碼,默認的編碼是gb2312,讀寫的編碼不一致,會致使亂碼的!
        outputFormat.setEncoding("UTF-8");

        //建立XMLWriter對象
        XMLWriter xmlWriter = new XMLWriter(new FileWriter("2.xml"), outputFormat);

        //XMLWriter對象寫入的是document
        xmlWriter.write(document);

        //關閉流
        xmlWriter.close();


    }
  • 效果以下,是有格式的

 

在指定的位置增長節點!如今我想的就是在age屬性前面添加節點!

//建立一個新節點
        Element element = DocumentHelper.createElement("name");
        element.setText("ouzciheng");

        //獲取獲得person下全部的節點元素!
        List list = document.getRootElement().elements();

        //將節點添加到指定的位置上
        list.add(1, element);
  • 效果圖:

 

 

修改

  • XMLWriter和獲取Document對象的代碼我就不貼出來了,反正都是同樣的了!
//獲取獲得age元素
        Element age = document.getRootElement().element("age");
        age.setText("9999");
  • 效果以下:

 

 

刪除

  • XMLWriter和獲取Document對象的代碼我就不貼出來了,反正都是同樣的了!
//獲取獲得age節點
        Element age = document.getRootElement().element("age");

        //獲得age節點的父節點,使用父節點的remove刪除age節點!
        age.getParent().remove(age);
  • 效果:

 

 

XPATH

什麼是XPATH

XPath 是一門在 XML 文檔中查找信息的語言。XPath 用於在 XML 文檔中經過元素和屬性進行導航。

爲何咱們須要用到XPATH

上面咱們使用dom4j的時候,要獲取某個節點,都是經過根節點開始,一層一層地往下尋找,這就有些麻煩了

若是咱們用到了XPATH這門語言,要獲取獲得XML的節點,就很是地方便了!

快速入門

使用XPATH須要導入開發包jaxen-1.1-beta-7,咱們來看官方的文檔來入門吧。

  • XPATH的文檔很是國際化啊,連中文都有

 

 

  • XPATH文檔中有很是多的實例,很是好學,對着來看就知道了!

 

 

  • 咱們來用XPATH技術讀取XML文件的信息吧,XML文檔以下:

 

 

  • 以前,咱們是先獲取根節點,再獲取guangdong節點再獲取guangzhou節點,而後才能讀取tianhe節點或者luogang節點的,下面咱們來看一下使用XPATH能夠怎麼的便捷
//直接獲取到luogang節點
        org.dom4j.Node node =  document.selectSingleNode("//luogang");

        //獲取節點的內容
        String value = node.getText();

        System.out.println(value);
  • 效果:

 

 

獲取什麼類型的節點,XPATH的字符串應該怎麼匹配,查文檔就知道了,這裏就再也不贅述了。!

若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章的同窗,能夠關注微信公衆號:Java3y

相關文章
相關標籤/搜索