JAXP體驗(二). DTD是什麼?
XML基本
XML全稱是Extensible Markup Language,可擴充套件標記語言,為啥不叫EML呢。 1993年誕生HTML,1998年出現XML。
HTML我們都熟,說說XML和HTML不一樣的特點:1。沒有預置標籤,2。可以定義新的標記語言,擴充套件好,3。區分大小寫,4。有語法要求
安利一款XML編輯器 XMLSpy。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <bean id="user" class="com.model.User" init-method="init"> </bean> </beans>
上述例子是我們大概率接觸到的spring的xml配置檔案,類似的還有mybatis的配置檔案。兩者都是XML,但是開頭寫法卻不一樣,其實這是XML的兩種語義約束,格式約束 以及 語義約束。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <!-- 配置資料庫連線資訊 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> <property name="username" value="root" /> <property name="password" value="" /> </dataSource> </environment> </environments> </configuration>
XML從一方面可以分為三種:
1。格式不行,存在明顯語法錯誤;
2。格式行,但是沒有按照框架(就是XML語義約束)來寫。
3。格式行,也按照語義約束來了。
這不就是我們高中寫議論文的分類嗎,高中語文老師都會給我們應試教育議論文的模板,先展示文采,話題發散,闡明觀點,承上啟下,例子證明,總結昇華觀點。
1花裡胡哨,不按照模板來;2按照模板來了,(比如例子證明,某某某歷史名人說過,多個朋友多條路?),這就不符合約束了;3按照模子,遵循約定。
從上可以得出結論:XML有兩點約束:1.格式約束 2. 語義約束
XML的格式約束
XML的格式約束有幾點:
- XML第一行是XML文件宣告,
- XML有且只能有一個根節點
- XML的標籤要麼開始標籤和結束標籤配對,要麼空標籤出現, 標籤不能出現混亂巢狀
- XML標籤的屬性不能單獨出現
1.XML文件宣告
XML第一行我們見都是<?xml version="1.0" ?>
這行的作用就是告訴這是一個XML文件,遵循XML文件規範的XML,version是必須的,通常都使用1.0
其實還有兩個屬性,
encoding: encoding只是告訴使用它的程式解碼用的字符集。 本身我們書寫XML還有一個編碼,比如本地可能你會使用UTF-8或者GB2312編碼,這個屬性只是告訴外部解碼該用什麼字符集。
standalone: 宣告該文件是否需要引用其他資源,只有yes|no。 這個我只見過。
2.XML的一個根節點
所謂一個根節點就是隻能有一個根元素。如果像如下,是肯定不可以的。XML可以解析成樹結構,如果多個根節點,那就是解析成森林了...
<?xml version="1.0" ?>
<Root>
......
</Root>
<Root2>
</Root2>
3.XML的標籤
1.XML嚴格區分大小寫。
2. <x name="11"></x>
XML的標籤屬性不能是空值,不能出現多個重名屬性,不能像這樣 <x name></x>
。這一樣也和前端區別挺大,寫前端的同學寫XML要尤為注意。
3.XML標籤中間的多個空格包括換行都會保留下來, 如果在XML標籤中書寫了特殊含義的字元(比如&),就會引起格式錯誤。比如<result> 1+1<2 </result>
XML遇到<號,認為是標籤頭,結果匹配不到結束標籤,這樣就格式錯誤了。 解決方案有兩種:
1. 轉義, <轉義成 <
2. CDATA標記, ,原因是XML不會對CDATA裡的內容做處理
- 允許XML處理指令,
XML的語義約束
XML的語義約束,作為java程式設計師肯定接觸過,以兩種框架來舉例,Mybatis配置檔案使用的就是DTD約束,Spring配置檔案使用的就是XML Schema約束。JAVA和XML聯絡真的很多,java開發大多都接觸過這兩框架,
大多都寫過這兩配置檔案。java跨平臺,xml也沒有平臺之分。
1.DTD約束
DTD,Document Type Definition,文件型別定義的意思。
DTD約束有幾層限制:文件可以出現的元素,文件的根元素型別,文件每個元素的順序、次數、內容、結構,文件各個元素的屬性(包括屬性名、屬性規則)
DTD約束主要用來驗證符合語義約束的XML,不符合語義約束的配置檔案沒法處理,不按套路出牌的XML 我們的java程式沒法解析。
1.1 DTD使用方式
DTD使用方式和JAVA超級像。JAVA引用變數方法,內部定義個static final變數,我們就能使用這個屬性;外部類定義public static final,其他類中我們也可以訪問到;
JAVA外部依賴定義的變數,比如web開發時候用到的各種常量,Spring中HttpMethod等。
DTD使用方式也是三種:
- 內部DTD
- 外部DTD
- 公共DTD
這裡的內部外部都是指我們書寫的DTD的位置,XML檔案內、XML檔案外(本地相對路徑或者 指向某個URI)。
DTD的語法是: <!DOCTYPE 根元素名稱[ 元素描述 ]>
,DTD內容需要跟在XML聲明後面
元素描述的語法是<!ELEMENT 元素名稱 類別>
標準DTD語法的網站上是 https://www.w3school.com.cn/dtd/dtd_elements.asp。
以下面我寫的DTD為例簡單講幾個DTD語法:
文件的根元素在第3行定為Root,Root根元素第4行限制為包含body、div、p、a、span等若干次(*代表若干次,0次或者更多次,這裡的body div是我隨便定義的,和HTML沒有任何關係),
#PCDATA
是專有寫法。第7行限制了a元素必須包含一個span標籤。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Root[
<!ELEMENT Root (body|div|p|a|span)*>
<!ELEMENT body (#PCDATA|div|p|a|span)*>
<!ELEMENT div (#PCDATA|div|p|a|span)*>
<!ELEMENT p (#PCDATA|div|p|a|span)*>
<!ELEMENT a (span)>
<!ELEMENT span (#PCDATA|a|span)*>
]>
<Root>
</Root>
1.2 內部DTD
將上面寫的語法緊跟在XML聲明後面就是內部DTD, 沒啥優點,缺點就是如果很多很多份XML要使用語義約束不太方便。
1.3 外部DTD
外部DTD的語法是:
<!DOCTYPE 根元素名 SYSTEM "URI"
此處的URI可以是絕對路徑,也可以是相對路徑。 外部DTD的寫法就和內部DTD不太一樣了。
上例中外部DTD改造成,可以看到去除了<!DOCTYPE Root[]>
這個描述,只保留了元素描述的內容。另外外部DTD檔案也有自己的XML宣告,
說明DTD外部可以指定對外編碼格式。
Root.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT Root (body|div|p|a|span)*>
<!ELEMENT body (#PCDATA|div|p|a|span)*>
<!ELEMENT div (#PCDATA|div|p|a|span)*>
<!ELEMENT p (#PCDATA|div|p|a|span)*>
<!ELEMENT a (span)>
<!ELEMENT span (#PCDATA|a|span)*>
引用Root.dtd檔案的地方寫法:這裡是因為xml和DTD檔案放在同一級目錄,相對路徑就能訪問到。如果不在一個目錄裡,URI可以使用檔案協議:
<!DOCTYPE Root SYSTEM "file:///f:/app/Root.dtd">
這樣也能訪問到DTD檔案的,其他多種協議http https更不用說。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Root SYSTEM "Root.dtd">
<Root>
</Root>
1.3 公共DTD
這種DTD相當於某個組織約定的,使用語法如下:
<!DOCTYPE 根元素 PUBLIC "DTD標識名" "DTD的URI"
,可以看到和外部DTD的區別僅僅是public替換system,以及多了個DTD標識名。
以我們最常見的Mybatis為例,根元素確實是configuration,就是DTD標識名感覺寫法獨特, URI也是可以下載的。mybatis-3-config.dtd檔案還挺長的,就不佔篇幅了。
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
以mybatis 一小段dtd為例:
mappers元素可以包含任意個mapper,任意個package,但是 mapper和package是按照順序來寫的,如果package在mapper之前,那是不行的。
mapper是個空元素,只有三個屬性 resource url class, #IMPLIED是屬性預設值意思,#IMPLIED就是非必要的。 這下是不是對mybatis配置檔案寫法有了更清楚的認識。
<!ELEMENT mappers (mapper*,package*)>
<!ELEMENT mapper EMPTY>
<!ATTLIST mapper
resource CDATA #IMPLIED
url CDATA #IMPLIED
class CDATA #IMPLIED
>
<!ELEMENT package EMPTY>
<!ATTLIST package
name CDATA #REQUIRED
>
DTD的語法有很多,W3S上就能學習到很多https://www.w3school.com.cn/dtd/dtd_attributes.asp,這裡就不畫蛇添足複製了,因為我們很少會開發DTD,需要我們去掌握DTD語法,用不到呀。