XML*


目錄

  • XML簡介
  • XML基本語法
  • XML解析
    ?* DOM解析
    ? ?* DOM解析原理及工具
    ? ?* DOM4J解析工具用法及示例
    ? ?* xPath技術
    ?* SAX解析
    ? ?* SAX解析工具
    ? ?* SAX解析原理
    ? ?* SAX解析工具用法及示例
    ?* SAX解析與DOM解析的區別
  • XML約束
    ?* 引入
    ?* XML約束技術
    ?* DTD約束
    ?* Schema約束

XML簡介

XML(Extend Markup Language)是一種標記語言,被用來格式化的傳輸數據
示例

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type = "text/css">
<!--this is content-->
<CATALOG>
  <CD id = "132">
    <TITLE>Empire Burlesque</TITLE>
    <ARTIST>Bob Dylan</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Columbia</COMPANY>
    <PRICE>10.90</PRICE>
    <YEAR>1985</YEAR>
  </CD>
</CATALOG>

其中:

  • <?xml version="1.0" encoding="ISO-8859-1"?>聲明了XML的版本(version)以及編碼方式(encoding)
  • <?xml-stylesheet type = "text/css"> 處理指令,告訴XML解析如何解析XML文件,type的值表示對應的css文件
  • < !--this is content-->是注釋
  • <CATALOG></CATALOG>是一對標簽它們的名字可以自己定義,其中<CATALOG>是開始標簽,</CATALOG>是關閉標簽
  • <CD id = "132"> id是CD的屬性
  • <PRICE>10.90</PRICE> 10.90是標簽的內容
  • xml描述了一種樹形結構 CATALOG是根,CD是CATALOG的子節點;TITLE,ARTIST,COUNTRY等是CD的子節點

XML基本語法

一、XML對大小寫敏感
二、所有XML標簽都必須有關閉標簽
三、頭尾標簽名應該一樣
四、屬性值必須加引號
五、在 XML 中,空格會被保留(XML中多個空格只會保留一個)
六、實體引用(轉義字符)

  • 在 XML 中,一些字符擁有特殊的意義。如果你把字符 "<" 放在 XML 元素中,會發生錯誤,這是因為解析器會把它當作新元素的開始。這樣會產生 XML 錯誤:
    解決辦法:


    實體引用.PNG
  • CDATA塊,讓一些需要進行原樣輸出的內容中的特殊字符原樣輸出。
<![CDATA[<html><head></head><body></body></html>]]>

DOM解析

1)DOM解析原理
DOM解析XML文檔時,XML解析器一次性吧整個XML文檔加載進內存,然后在內存中構建一棵Document對象樹,通過Document對象,可以得到下面的節點對象,通過節點對象訪問數據
2)DOM解析工具

  • JAXP (oracle-Sun公司官方)
  • JDOM工具(非官方)
  • Dom4J工具(非官方)(三大框架默認讀取xml的工具就是Dom4j)
DOM4J解析工具

需要導包使用

1)dom4j結構


domj4.png

2)dom4j讀取xml文件
節點:

  • Iterator Element.nodeIterator(); //獲取當前標簽節點下的所有子節點

標簽:

  • Element Document.getRootElement(); //獲取xml文檔的根標簽
  • Element ELement.element("標簽名") //指定名稱的第一個子標簽
  • Iterator<Element> Element.elementIterator("標簽名");// 指定名稱的所有子標簽
  • List<Element> Element.elements(); //獲取所有子標簽

屬性:

  • String Element.attributeValue("屬性名") //獲取指定名稱的屬性值
  • Attribute Element.attribute("屬性名");//獲取指定名稱的屬性對象
  • Attribute.getName() //獲取屬性名稱
  • Attibute.getValue() //獲取屬性值
  • List<Attribute> Element.attributes(); //獲取所有屬性對象
  • Iterator<Attribute> Element.attibuteIterator(); //獲取所有屬性對象

文本:

  • Element.getText(); //獲取當前標簽的文本
  • Element.elementText("標簽名") //獲取當前標簽的指定名稱的子標簽的文本內容

示例1:利用dom4j輸出一個xml文件

public class Demo1 {
    @Test
    public void test()throws Exception {
        SAXReader  reader = new SAXReader();
        Document document = reader.read(new File("./src/contact.xml"));
        //獲得根標簽
        Element element = document.getRootElement();
        StringBuffer sb = new StringBuffer();
        //用此方法遍歷整個xml文件(先根遍歷形式)
        getchild(element,sb);
        System.out.println(sb.toString());
        }

    private void getchild(Element element, StringBuffer sb) {
        // TODO Auto-generated method stub
        sb.append("<"+element.getName());
        //獲得標簽的所有屬性
        List<Attribute> attrs = element.attributes();
        //輸出標簽屬性
        if(attrs!=null) {
            for (Attribute attribute : attrs) {
                sb.append(" "+attribute.getName()+"=\""+attribute.getValue()+"\"");
            }
        }
        sb.append(">");
        //獲得當前標簽下的所有子標簽
        Iterator<Node> iterator= element.nodeIterator();
        while(iterator.hasNext()) {
            Node node = iterator.next();
            //輸出標簽
            if(node instanceof Element) {
                Element e = (Element)node;
                getchild(e,sb);
            }
            //輸出文本
            if(node instanceof Text) {
                Text text = (Text)node;
                sb.append(node.getText());
            }
        }
        sb.append("</"+element.getName()+">");  
    }
}

示例2:把xml獲取的信息封裝到對象內

/**
 * 把xml封裝到對象中
 *
 */
public class Demo2 {
    @Test
    public void test2() throws Exception{
        SAXReader reader = new SAXReader();
        Document doc = reader.read(new File("./src/contact.xml"));
        Element elem = doc.getRootElement();
        Iterator<Element> it = elem.elementIterator();
        ArrayList<Contact> contacts = new ArrayList();
        while(it.hasNext()) {
            Contact contact = new Contact();
            Element element = it.next();
            contact.setId(element.attributeValue("id"));
            contact.setAge(element.elementText("age"));
            contact.setPhone(element.elementText("phone"));
            contact.setEmail(element.elementText("email"));
            contact.setQq(element.elementText("qq"));
            contacts.add(contact);
        }
        
        for(Contact contact:contacts) {
            System.out.println(contact);
        }
    }
}

3) 修改xml文件
增加:

  • DocumentHelper.createDocument() 增加文檔
  • addElement("名稱") 增加標簽
  • addAttribute("名稱",“值”) 增加屬性

修改:

  • Attribute.setValue("值") 修改屬性值
  • Element.addAtribute("同名的屬性名","值") 修改同名的屬性值
  • Element.setText("內容") 修改文本內容

刪除

  • Element.detach(); 刪除標簽
  • Attribute.detach(); 刪除屬性

寫入

  • OutputFormat.createPrettyPrint() 創建易讀的xml文件
  • OutputFormat.createCompactFormat() 創建緊湊的xml文件
  • format.setEncoding("編碼方式");設置編碼方式
  • XMLWriter(OutputStream out,OutPutformat format) 設置寫入方式
  • XMLWriter.write 寫入內容

寫入基本流程:首先創構建一個空的Document對象,然后向其中按照節點關系添加標簽(根標簽只能有一個),然后創建文件輸出流,指定輸出格式,利用XMLWriter對象設置格式和寫入內容,最后關閉writer對象。

示例3:創建文件并寫入一個簡單的XML文檔:


************
/**
 * 生成xml文檔
 *
<Students>
<Student id="1">
    <name>張三</name>
    <gender>男</gender>
    <grade>計算機1班</grade>
    <address>廣州天河</address>
</Student>
<Student id="2">
    <name>李四</name>
    <gender>女</gender>
    <grade>計算機2班</grade>
    <address>廣州越秀</address>
</Student>
</Students>
 *
 */
public class Demo3 {
    @Test
    public void test() throws Exception {
        //在內存創建Document文檔
        Document doc = DocumentHelper.createDocument();
        //寫入內容
        Element rootElement = doc.addElement("Students");
        //增加第二層標簽
        Element studentElem = rootElement.addElement("Student");
        //增加屬性
        studentElem.addAttribute("id", "1");
        //添加第三層標簽
        studentElem.addElement("name").setText("張三");
        studentElem.addElement("gender").setText("男");
        studentElem.addElement("grade").setText("計算機一班");
        studentElem.addElement("address").setText("廣州天河");
        //增加第二個二層標簽
        Element studentElemnt2 = rootElement.addElement("Student");
        studentElemnt2.addAttribute("id", "2");
        //為第二個二層標簽添加子標簽
        studentElemnt2.addElement("name").setText("李四");
        studentElemnt2.addElement("gender").setText("女");
        studentElemnt2.addElement("grade").setText("計算機二班");
        studentElemnt2.addElement("address").setText("廣州越秀");
        
        //將內容寫出到文件
        //創建輸出流
        FileOutputStream out = new FileOutputStream(new File("f:/student.xml"));
        //指定輸出方式
        OutputFormat format = OutputFormat.createPrettyPrint();
        //指定編碼方式
        format.setEncoding("utf-8");
        XMLWriter writer = new XMLWriter(out,format);
        //寫出內容
        writer.write(doc);
        //關閉資源
        writer.close();
    }
}

示例4:修改、刪除xml文件

/**
 * 修改id為2的學生的姓名+刪除id為2的學生標簽
 *
 */
public class Demo3 {
    @Test
    public void test() throws Exception {
        //將XML文件載入為document對象
        Document document = new SAXReader().read(new File("f:/student.xml"));
        //獲取所有Student標簽
        Iterator<Element> it = document.getRootElement().elementIterator("Student");
        //查詢id為2的學生
        while(it.hasNext()) {
            Element elem = it.next();
            System.out.println(elem.attribute("id").getValue());
            if(elem.attributeValue("id").equals("2")) {
                //修改姓名
                //elem.element("name").setText("王麗");
                //刪除該學生標簽
                elem.detach();
                break;
            }
        }
        
        FileOutputStream out = new FileOutputStream("f:/student.xml");
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("utf-8");
        XMLWriter writer = new XMLWriter(out,format);
        writer.write(document);
        writer.close();
    }
}

4)xPath技術

當使用dom4j查詢比較深的層次節點時比較麻煩,xPath技術可以使我們快速獲得深層次節點
使用xPath的方法需要導入dom4j文件夾下的jaxen-1.1-beta-6.jar包。

xPath語法:
Xpath語法類似于在一個文件系統中定位文件
W3C的Xpath語法教程:http://www.w3school.com.cn/xpath/xpath_syntax.asp

  • / 絕對路徑 表示從xml的根位置開始或子元素(一個層次結構)
  • // 相對路徑 表示不分任何層次結構的選擇元素。
  • * 通配符 表示匹配所有元素
  • [] 條件 表示選擇什么條件下的元素
  • @ 屬性 表示選擇屬性節點
  • and 關系 表示條件的與關系(等價于&&)
  • text() 文本 表示選擇文本內容

在DOM4J中的使用方法:

  • List<Node> selectNodes("xpath表達式"); 查詢多個節點對象
  • Node selectSingleNode("xpath表達式"); 查詢一個節點對象

SAX解析

1)SAX解析工具
SAX解析工具- Sun公司提供的。內置在jdk中。org.xml.sax.*
2)SAX解析原理
加載一點,讀取一點,處理一點。對內存要求比較低。

核心的API:
SAXParser類: 用于讀取和解析xml文件對象

  • parse(File file,DefautHandler);
    參數一: File:表示 讀取的xml文件。
    參數二: DefaultHandler: SAX事件處理程序。需要自己實現它的子類,覆蓋相應方法進行解析

DefaultHandler類的API:

  • void startDocument() : 在讀到文檔開始時調用
  • void endDocument() :在讀到文檔結束時調用
  • void startElement(String uri, String localName, String qName, Attributes attributes) :讀到開始標簽時調用
  • void endElement(String uri, String localName, String qName) :讀到結束標簽時調用
  • void characters(char[] ch, int start, int length) : 讀到文本內容時調用

3)示例,利用SAX解析輸出完整xml文檔內容
1.主函數:

/**
 * 讀取contact.xml文件,完整輸出文檔內容
 *
 */
public class Demo2 {

    public static void main(String[] args)throws Exception {
        //1.創建SAXParser
        SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
        //2.讀取xml文件
        MyDefaultHandler2 handler = new MyDefaultHandler2();
        parser.parse(new File("./src/contact.xml"), handler);
        String content = handler.getContent();
        System.out.println(content);
    }
}

2.MyDefaultHandler2類

/**
 * SAX處理器程序
 */
public class MyDefaultHandler2 extends DefaultHandler {
    //存儲xml文檔信息
    private StringBuffer sb = new StringBuffer();
    
    //獲取xml信息
    public String getContent(){
        return sb.toString();
    }
    

    /**
     * 開始標簽
     */
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        sb.append("<"+qName);
        //判斷是否有屬性
        if(attributes!=null){
            for(int i=0;i<attributes.getLength();i++){
                //得到屬性名稱
                String attrName = attributes.getQName(i);
                //得到屬性值
                String attrValue = attributes.getValue(i);
                sb.append(" "+attrName+"=\""+attrValue+"\"");
            }
        }
        sb.append(">");
    }
    
    /**
     * 文本內容
     */
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        //得到當前讀取的文本
        String content = new String(ch,start,length);
        sb.append(content);
    }
    
    /**
     * 結束標簽
     */
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        sb.append("</"+qName+">");
    }
}

SAX解析與DOM解析的區別

DOM解析 SAX解析
原理: 一次性加載xml文檔,不適合大容量的文件讀取 原理: 加載一點,讀取一點,處理一點。適合大容量文件的讀取
DOM解析可以任意進行增刪改查 SAX解析只能讀取
DOM解析任意讀取任何位置的數據,甚至往回讀 SAX解析只能從上往下,按順序讀取,不能往回讀
DOM解析面向對象的編程方法(Node,Element,Attribute),Java開發者編碼比較簡單。 SAX解析基于事件的編程方法。java開發編碼相對復雜。

XML約束

1)引入
XML語法是由w3c組織制定的規范xml文件的基本編寫規則,而XML約束是開發者自定義規則以使XML符合自己的規范的約束。

2)XML約束技術
DTD約束:語法相對簡單,功能也相對簡單。學習成本也低。
Schema約束:語法相對復雜,功能也相對強大。學習成本相對高!!!(名稱空間)

3)DTD約束
1.導入DTD方式

  • 內部導入
<?xml version="1.0"?>
<!DOCTYPE note [//定義此文檔是 note 類型的文檔。
  <!ELEMENT note (to,from,heading,body)>     //定義 note 元素有四個元素:"to、from、heading,、body"
  <!ELEMENT to      (#PCDATA)>               //元素為 "#PCDATA" 類型
  <!ELEMENT from    (#PCDATA)>               //元素為 "#PCDATA" 類型
  <!ELEMENT heading (#PCDATA)>               //元素為 "#PCDATA" 類型
  <!ELEMENT body    (#PCDATA)>              //元素為 "#PCDATA" 類型
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>
  • 外部導入
    本地文件系統:<!DOCTYPE note SYSTEM "note.dtd">
    公共的外部導入:<!DOCTYPE 根元素 PUBLIC "http://gz.itcast.cn/itcast.dtd">

2.DTD語法

  • 約束標簽 <!ELEMENT 元素名稱 類別> 或 <!ELEMENT 元素名稱 (元素內容)>
    類別:
    ??空標簽: EMPTY。 表示元素一定是空元素。
    ??普通字符串: (#PCDATA)。表示元素的內容一定是普通字符串(不能含有子標簽)。
    ??任何內容: ANY。表示元素的內容可以是任意內容(包括子標簽)

順序問題:
<!ELEMENT 元素名稱 (子元素名稱 1,子元素名稱 2,.....)>: 表示子標簽必須按順序出現
次數問題:
標簽名 : 表示標簽必須出現且只出現1次。
標簽名+ : 至少出現1次
標簽名* : 0或n次。
標簽名? : 0 或1次。

  • 約束屬性 <!ATTLIST 元素名稱 屬性名稱 屬性類型 默認值>
    默認值:
    ????#REQUIRED ?表示屬性是必需的
    ????#IMPLIED ?表示屬性不是必需的
    ????#FIXED value ?表示屬性不是必須的,但屬性值是固定的
    屬性類型:控制屬性值的
    ????CDATA :?表示普通字符串
    ????(en1|en2|..):? 表示一定是任選其中的一個值
    ????ID:?表示在一個xml文檔中該屬性值必須唯一。值不能以數字開頭

4)Schema約束
名稱空間:告訴xml文檔的哪個元素被哪個schema文檔約束。 在一個xml文檔中,不同的標簽可以受到不同的schema文檔的約束。
1.一個名稱空間受到schema文檔約束的情況
2.多個名稱空間受到多個schema文檔約束的情況
3.默認名稱空間的情況
4.沒有名稱空間的情況

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。