1. 程式人生 > 實用技巧 >JAXP體驗(二). DTD是什麼?

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的格式約束有幾點:

  1. XML第一行是XML文件宣告,
  2. XML有且只能有一個根節點
  3. XML的標籤要麼開始標籤和結束標籤配對,要麼空標籤出現, 標籤不能出現混亂巢狀
  4. 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裡的內容做處理

  1. 允許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使用方式也是三種:

  1. 內部DTD
  2. 外部DTD
  3. 公共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語法,用不到呀。