今日大綱
1、什么是xml、xml的作用
2、xml的語法
3、DTD約束xml
4、Schema約束xml
5、DOM解析xml
1、什么是xml、xml的作用
1.1、xml介紹
在前面學習的html語言,html是超文本標記語言,使用html語言規定好的標簽來封裝文本數據。而html使用的標簽html語言規定好的,每個標簽都有自己特定的功能。
xml語言,可擴展的標記語言,這門語言它沒有定義任何的標記,而標記是由使用者自己來定義,但是由於標簽名稱以及屬性名稱都由用戶自己來命名,導致別人在使用的時候很不方便。有給xml語言定義了一些約束文檔,這些約束文檔就專門用來約束當前這個xml中能夠書寫的具體的標簽以及屬性等信息。
1.2、xml的作用
xml作用: 1、存儲和傳輸復雜的關系模型數據 2、作為配置文件存在,xml中主要配置的一些具有復雜的層級關系的數據,Properties文件中主要配置的一些key和value這樣的數據。 在軟件系統中,作為配置文件使用 為提高系統的靈活性,它所啟動的模塊通常由其配置文件決定 例如一個軟件在啟動時,它需要啟動A、B兩個模塊,而A、B這兩個模塊在啟動時,又分別需要A1、A2和B1、B2模塊的支持,為了准確描述這種關系,此時使用XML文件最為合適不過。 <soft> <A> <A1></A1> <A2></A2> </A> <B> <B1></B1> <B2></B2> </B> </soft>
2、xml的語法
2.1、文檔聲明
來聲明當前的xml類型。 <?xml ?> 在這個尖括號中書寫標簽的屬性來聲明當前的xml類型限定。 屬性:版本號 字符編碼 是否是獨立存在的xml文檔 <?xml version=”1.0” encoding=”編碼表” standalone=”yes|no” ?> 例如: <?xml version=”1.0” encoding=”UTF-8” ?> 在定義xml的文檔聲明時 <?之間不能有空白的內容 ?> 它們之間也不能有空格 中間書寫的屬性使用空格隔開。
2.2、元素(標簽)
xml中的標簽也分成單標簽和雙標簽。注意在xml所有的標簽必須閉合。xml中的標簽區別大小寫。 <a1> <A1>表示2個不同的標簽。 xml中的標簽可以嵌套,但是不能交差嵌套。 <a1><b1></b1></a1> <a1><b1></a1></b1> xml的標簽只能有一個根標簽。同時xml標簽中的空白內容也會被解析成文本內容。 <網址>www.itcast.cn</網址> 標簽不能以數字開始,不建議以下划線開始,同時在標簽名中不要使用冒號。 標簽名可以是中文,但是一定指定能夠識別中文的碼表。但不建議書寫中文。
2.3、屬性
在定義標簽的時候,可以在標簽上書寫屬性,屬性是由key和alue值組成。屬性名書寫的時候也遵守標簽名的規則。屬性值也不能以數字開始。 屬性和值之間使用=連接,屬性值可以使用單引號也可以使用雙引號。 <user uid=”u001” name=”zhang’san”></user> 另外:在xml技術中,標簽屬性所代表的信息,也可以改為用子元素的形式來描述,如: <input><type>text</type></input>
2.4、注釋
xml中的注釋和html注釋相同。<!-- 這里書寫具體的注釋內容 --> 在eclipse中可以使用ctrl + shift + c 給每行添加注釋,也可以使用ctrl + shift + / 添加注釋 ctrl + shift + \ 取消注釋 注釋不能加在聲明中及聲明前。
2.5、文本和特殊字符
在編寫XML文件時,有些內容可能不想讓解析引擎解析執行,而是當作原始內容處理。 遇到此種情況,可以把這些內容放在CDATA區里,對於CDATA區域內的內容,XML解析程序不會處理,而是直接原封不動的輸出。 語法:<![CDATA[ 內容 ]]> <![CDATA[ <itcast> <br/> </itcast> ]]> 對於一些單個字符,若想顯示其原始樣式,也可以使用轉義的形式予以處理。
2.6、特殊指令
處理指令,簡稱PI (processing instruction)。處理指令用來指揮解析引擎如何解析XML文檔內容。 例如,在XML文檔中可以使用xml-stylesheet指令,通知XML解析引擎,應用css文件顯示xml文檔內容。 <?xml-stylesheet type="text/css" href="1.css"?> 處理指令必須以“<?”作為開頭,以“?>”作為結尾,XML聲明語句就是最常見的一種處理指令。
2.7、xml語法規則總結:
所有xml元素必須有閉合標簽;
Xml標簽區分大小寫;
Xml必須正確地嵌套順序;
Xml文檔必須有根元素(且只有一個);
Xml屬性值須加引號
特殊字符必須轉義——CDATA;
Xml中的空格、回車換行會被解析!
3、DTD約束xml
3.1、約束介紹
由於xml的標簽由用戶自己定義,因此在開發的時候,每個人都可以根據自己的需求來定義xml標簽,這樣導致項目中的xml難以維護,因此需要使用一定的規范機制來約束xml文件中的標簽書寫。
3.2、DTD約束快速入門
第一步:先自己定義一個xml文件
<?xml version="1.0" encoding="UTF-8"?> <users> <user> <name>zhangsan</name> <age>23</age> <addr>shanghai</addr> </user> <user> <name>lisi</name> <age>24</age> <addr>beijing</addr> </user> </users>
第二步:書寫DTD文件來約束xml文件
DTD文件在定義的時候,擴展名就是dtd。
在xml文件中有多少個標簽,就在dtd中書寫多少個ELEMENT標簽
<?xml version="1.0" encoding="UTF-8" ?> <!ELEMENT users (user+) > <!ELEMENT user (name,age,addr) > <!ELEMENT name (#PCDATA) > <!ELEMENT age (#PCDATA)> <!ELEMENT addr (#PCDATA)>
3.3、DTD引入方式
DTD主要用來約束xml文件,DTD可以單獨寫在文件中,也可以直接定義在xml中,可以在xml中引入第三方的公共DTD。 外部DTD的引入方式:外部DTD主要指的一個獨立的DTD文件。 首先要書寫DTD文件,然后在要被約束的xml文件中引入。 <!DOCTYPE 文檔根結點 SYSTEM "DTD文件的URL"> 文檔根結點 指的是當前xml中的根標簽。 SYSTEM 引入的系統中存在文件 "DTD文件的URL" DTD存放的位置 引入公共的DTD: <!DOCTYPE 文檔根結點 PUBLIC "DTD名稱" "DTD文件的URL"> 文檔根結點 指的是當前xml中的根標簽。 PUBLIC 表示當前引入的DTD是公共的DTD 在xml中直接書寫DTD <!DOCTYPE 根標簽名 [ 具體的標簽的約束 ]>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE users[ <!ELEMENT users (user+) > <!ELEMENT user (name,age,addr) > <!ELEMENT name (#PCDATA) > <!ELEMENT age (#PCDATA) > <!ELEMENT addr (#PCDATA) > ]> <users> <user> <name>zhangsan</name> <age>23</age> <addr>shanghai</addr> </user> <user> <name>lisi</name> <age>24</age> <addr>beijing</addr> </user> </users>
3.4、DTD的語法介紹
3.4.1、元素
當定義DTD約束xml時候,這時需要在DTD中使用ELEMENT來定義當前xml中可以出現的標簽名稱。 格式: <!ELEMENT 標簽名 約束> 約束來限定當前標簽中可以有的子標簽,或者當前標簽中可以書寫的內容 在定義標簽名的時候,約束中可以使用一些符號標簽具體出現次數 ? 零次或者一次 * 零次或者多次 + 一次或者多次 users (user+) 表示當前的users標簽下可以有一個或者多個user標簽 , 用來限定當前的子標簽出現的順序user (name,age,addr) user標簽下只能有name age addr 子標簽,並且必須按照name age addr的順序書寫 | user (name|age,addr) user下可以name或者age ,但必須有addr,並且addr必須name或age后面 #PCDATA 表明該元素可包含任何字符數據,但不能在其中包含任何子元素。只有 PCDATA 的元素通過圓括號中的 #PCDATA 進行聲明 EMPTY 表明該元素不能有任何子元素或文本,僅可以使用屬性。 ANY 表該元素中可以包含任何DTD中定義的元素內容 如:<!ELEMENT note ANY> <!ELEMENT age EMPTY > 當前的age標簽是個空標簽,它不能有文本內容。
3.4.2、屬性
在xml中的標簽上是可以書寫屬性的,在DTD中就需要對屬性進行約束。 格式: <!ATTLIST 標簽名 屬性名 屬性的類型 屬性的約束> 如果一個標簽上有多個屬性 <!ATTLIST 標簽名 屬性名 屬性的類型 屬性的約束 屬性名 屬性的類型 屬性的約束 屬性名 屬性的類型 屬性的約束 > <標簽名 屬性1=”” 屬性2=”” 屬性3=”” >
屬性的類型:
CDATA 屬性的value值可以是文本數據
(值1 | 值2 | 值3.... ) 表示當前的屬性的value值只能是當前括號中的值
ID 表示唯一。對當前標簽上的id屬性進行限定,並且同一個xml中id不能重復
類型 描述
CDATA 值為字符數據 (character data)
(en1|en2|..) 此值是枚舉列表中的一個值
ID 值為唯一的 id
IDREF 值為另外一個元素的 id
IDREFS 值為其他 id 的列表
NMTOKEN 值為合法的 XML 名稱
NMTOKENS 值為合法的 XML 名稱的列表
ENTITY 值是一個實體
ENTITIES 值是一個實體列表
NOTATION 此值是符號的名稱
xml: 值是一個預定義的 XML 值
屬性的約束: REQUIRED 屬性是必須書寫的 Implied 屬性是可選得 #fixed value 屬性的value是固定的值 “值” 代表屬性的默認值 user name CDATA fixed “zhangsan” <user name=”zhangsan”> user name CDATA “張三” <user />
屬性的類型和約束的組合:
CDATA REQUIRED
CDATA Implied
CDATA fixed
CDATA “值”
(值1 | 值2 | 值3.... ) REQUIRED
ID REQUIRED
3.4.3、實體
實體用於為一段內容創建一個別名,以后在XML文檔中就可以使用別名引用這段內容了。 在DTD定義中,一條<!ENTITY …>語句用於定義一個實體。 實體可以理解成Java中預先定義好的一個常量,然后xml文件中就可以引入當前這個定義的實體。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE users[ <!ELEMENT users (user+) > <!ELEMENT user (name,age,addr) > <!ELEMENT name (#PCDATA) > <!ELEMENT age EMPTY > <!ELEMENT addr (#PCDATA) > <!ATTLIST user id ID #REQUIRED > <!ENTITY abc "上海傳智播客123123"> ]> <users> <user id="u001"> <name>zhangsan</name> <age></age> <addr>&abc;</addr> </user> <user id="u002"> <name>lisi</name> <age/> <addr>&abc;</addr> </user> </users>
4、Schema約束xml
4.1、xml Schema介紹
Schema它也來約束xml文件的,DTD在約束xml的時候一個xml中只能引入一個DTD,同時DTD它無法對屬性以及標簽中的數據做數據類型的限定。
Schema它是用來代替DTD來約束xml。
Schema文件本身就是使用xml文件書寫的,同時它對需要約束的xml中的數據有嚴格的限定。學習Schema主要來學習W3C組織定義的如何在Schema中去約束xml的標簽以及屬性,還有屬性的數據類型,以及標簽中子標簽的順序。
要定義一個Schema文件,這時它的擴展名必須是.xsd。在這個文件中根元素必須是schema。
使用Schema來約束xml,Schema在書寫的時候,只需要使用W3C組織提前定義的限定標簽的,以及限定的屬性的那個標簽即可。
4.2、Schema快速入門
第一步:書寫xml文件
<?xml version="1.0" encoding="UTF-8"?> <books> <book> <name>JavaWEB</name> <author>老畢</author> <price>182</price> </book> <book> <name>SSH</name> <author>老於</author> <price>152</price> </book> </books>
第二步:定義schema文件
在定義Schema文件的時候,由於這個Schema文件本身就是xml,它也要受到別的約束。而這個約束是W3C組織提前定義好的, 在Schema文件中需要提前引入進來在根標簽中使用屬性進行進入: <schema xmlns="http://www.w3.org/2001/XMLSchema" 引入W3C定義的schema書寫的規范 targetNamespace="http://www.itcast.org/book" 給當前的Schema文件起名字(命名空間) 作用是當哪個xml要引入這個schema約束的時候,必須通過當前targetNamespace 后面書寫的uri地址來引入
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itcast.org/book" elementFormDefault="qualified"> <element name="books"> <complexType> <sequence> <element name="book"> <complexType> <sequence> <element name="name"></element> <element name="author"></element> <element name="price"></element> </sequence> </complexType> </element> </sequence> </complexType> </element> </schema>
第三步:在xml文件中引入當前的這個Schema
<books xmlns="http://www.itcast.org/book" 它是schema文件中的targetNamespace 屬性后面的值 xsi:schemaLocation="http://www.itcast.org/book book.xsd" 這個是在引入當前的schema文件的真實路徑 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 說明當前的xml是schema一個實例文檔 >
4.3、Schema的名稱空間
在定義Schema文件的時候,需要在<schema>根標簽中使用 targetNamespace 屬性定義當前schema定義名稱(只是一個分配的名字,根本沒有指向任何文件),在被約束的xml文件中先根據這個名稱引入當前的schema文件,然后在使用 xsi:schemaLocation=”” 引入具體的schema文件。(因為targetNamespace屬性定義的schema名稱,只是一個名稱而已,所以在xml文件中需要通過schemaLocation來聲明指定所遵循的Schema文件的具體位置) (xsi:schemaLocation 使用它引入某個schema時,先要使用名稱空間, 空格 ,文件名) 名稱空間主要功能是用於來 elementFormDefault="qualified|unqualified" 在schema中書寫qualified ,在限定xml中的定義的標簽名必須使用定義的名稱空間。 unqualified 要求根元素必須使用名稱空間,而子元素不能使用名稱空間。
4.4、Schema中的標簽解釋
Book2.xsd
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itcast2.org/book" elementFormDefault="qualified"> <element name="books"> <!--name代表當前的xml中可以書寫標簽名稱 type數據類型--> <complexType ><!-- complexType 當前的element聲明的標簽是復雜標簽時 ,需要使用complexType來聲明子標簽--> <sequence> <!-- 復雜標簽是指有屬性,或者有子標簽,或者有屬性有子標簽的標簽 簡單標簽是指只有文本內容的標簽 <name>zhangsan</name> 簡單標簽 <name id="u001"></name> 復雜標簽 sequence 代表當前子標簽的順序 --> <element name="book" maxOccurs="unbounded"> <complexType mixed="true"><!—mixed屬性值為true,book元素間就可以出現字符文本數據了--> <sequence> <element name="name"></element> <element name="author"></element> <element name="price" type="integer"></element> <any></any> </sequence> </complexType> </element> </sequence> </complexType> </element> </schema>
Name.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/name" elementFormDefault="qualified"> <element name="name"></element> </schema>
Book2.xml
<?xml version="1.0" encoding="UTF-8"?> <aa:books xmlns:aa="http://www.itcast2.org/book" xmlns:bb="http://www.example.org/name" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.itcast2.org/book book2.xsd http://www.example.org/name name.xsd" > <aa:book> aa:sjdlkfjlkdsjflk <aa:name >JavaWEB</aa:name> <aa:author >老畢</aa:author> <aa:price>182</aa:price> <bb:name>sdgs</bb:name> </aa:book> </aa:books>
5、DOM解析xml
5.1、Java中的解析技術介紹
w3c組織在定義xml的時候,就規范了如何去解析xml文件,其中就定義了使用dom技術來解析xml文件。
DOM:Document Object Medel。文檔對象模型。
w3c給出的dom解析,第一步是先把整個xml文件加載到內存,然后在內存中形成了一顆dom樹。
特點:
一次將所有數據全部加載到內存中;
對xml文檔中每個節點都當成一個Node對象處理。包括元素、文本、屬性。
缺點就是當文檔數據量很大時,對內存有占用很大,所以不適合解析大量的數據。
5.2、DOM解析
Xml文檔的屬性結構
DOM解析是把整個xml文檔加載到內存中,然后形成一個dom樹,這樣就可以獲取樹中的所有標簽,屬性,文本內容。
Java實現了相應的dom解析技術:
使用Java提供的Dom技術來解析xml文件
DocumentBuilderFactory:這個是一個工廠類,主要負責生產一個解析xml的解析器對象
newDocumentBuilder()靜態方法可以獲取到一個用於解析xml的解析器對象
DocumentBuilderFactory.newDocumentBuilder();
獲取到了DocumentBuilder對象
DocumentBuilder 這個類可以從xml中獲得DOM對象
使用parse方法解析一個文件路徑,就可以得到當前xml文件對象
解析xml文件首先要獲取到xml文件對象即就是Document對象
5.3、DOM獲取節點、屬性、文本數據
// 獲取DOM標簽的信息 @Test public void get() throws Exception { // 獲取工廠實例對象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // 獲取解析器對象 DocumentBuilder db = dbf.newDocumentBuilder(); // 解析xml獲取dom對象 Document dom = db.parse("book.xml"); // 獲取根元素: Node node = dom.getFirstChild(); // 獲取標簽的名字 System.out.println(node.getNodeName()); // 獲取到每個標簽對象,都是一個element的實例對象 Element root = (Element) node; // 獲取books下面的所有book標簽 NodeList nl = root.getElementsByTagName("book"); for (int i = 0; i < nl.getLength(); i++) { // 獲取到每個book標簽對象 Element book = (Element) nl.item(i); // NodeList book_child = book.getChildNodes(); Element name = (Element) book.getElementsByTagName("name").item(0); Element author = (Element) book.getElementsByTagName("author") .item(0); Element price = (Element) book.getElementsByTagName("price") .item(0); // 獲取name標簽下的文本值 System.out.println(name.getTextContent()); // 獲取標簽上的屬性值 System.out.println(name.getAttribute("id")); // 獲取author標簽下的文本值 System.out.println(author.getTextContent()); // 獲取price標簽下的文本值 System.out.println(price.getTextContent()); System.out.println("-------------------"); } }
5.4、修改xml中的數據
/* * 修改dom中標簽的信息 * 把books中的第二個book標簽中的price的值改為100 * */ @Test public void update() throws Exception { // 獲取工廠實例對象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); // 獲取解析器對象 DocumentBuilder db = dbf.newDocumentBuilder(); // 解析xml獲取dom對象 Document dom = db.parse("book.xml"); //使用dom樹直接根據標簽名獲取對應的標簽對象 Element book = (Element) dom.getElementsByTagName("book").item(1); //獲取price標簽 Element price = (Element) book.getElementsByTagName("price").item(0); price.setTextContent("100"); System.out.println(price.getTextContent()); //把修改的整個dom樹重新寫到文件中 TransformerFactory tff = TransformerFactory.newInstance(); //獲取轉換器 Transformer transformer = tff.newTransformer(); //和文件關聯出去結果對象 StreamResult sr = new StreamResult("book.xml"); //把dom轉成原始數據對象 DOMSource ds = new DOMSource(dom); //保存數據 transformer.transform(ds, sr); }
當要把修改后的xml中的數據保存到xml中需要使用Transformer 類中的transform方法
TransformerFactory這個工廠負責生產一個把dom樹寫到文件中的對象
Transformer 負責把一個dom寫到文件中。
總結:
Java提供的dom操作方式:
第一步:需要獲取到相應的工廠
第二步:根據工廠獲取相應的工具或者解析器對象
第三步:根據解析器獲取dom對象,再操作dom樹中的節點,或者是獲取到相應的工具,然后使用工具對dom樹進行保存等操作