天天看點

java通過schema校驗xml

之前在做項目時時常需要通過一些“小xml”傳輸或存儲一些資訊,然後就在讀取的時候需要先判斷xml資料是否符合要求,包括這次也是這樣,不同的是 這次我設計了一個比較複雜的xml,結果讀取xml資料 裡穿插着各種判斷,洋洋灑灑寫了一大坨代碼。然後我就想不是有schema這種xml描述語言嗎,那應該也可以在代碼裡用它進行校驗xml…

在實作使用schema校驗xml這個目标前,你首先得自己會根據自己的xml要求格式寫出對應的schema,我認為寫schema占實作校驗目标的七成,剩下的三成才是使用代碼去校驗。因為一旦有schema,通過架構去校驗就是一段很固定的寫法了,這也就是為什麼要提議使用schema,可以大大減少不必要的重複代碼工作,而可以專心于讀取資料處,處理關鍵邏輯。

一、幾個重要的标頭

顯示 schema 中用到的元素和資料類型來自命名空間 “http://www.w3.org/2001/XMLSchema“。同時它還規定了來自命名空間 “http://www.w3.org/2001/XMLSchema” 的元素和資料類型應該使用字首

xs:

指出該檔案的預設命名空間,在文檔中所有的名字前面如果沒有字首的,就是由預設命名空間進行定義和解析的。使用預設命名空間,可以不加空間字首。

标明節點下面所定義的類型都屬于這個命名空間。使用targetNamespace命名空間下的元素必須要加字首。

表示任何xml中使用本xsd中聲明的元素必須使用命名空間

這句話引用的這個命名空間是幹什麼呢(它和

xmlns:xs

一樣都是一個正常的引用語句,

xs

,

xi

都是一個别名),他和下面這句話有關:因為下面這句話需要指出你應用的命名空間的實際的文檔在放在哪。這個屬性就是schemaLocation,而這個屬性被定義在

http://www.w3.org/2001/XMLSchema-instance

關于

xmlns

targetNamespace

的意義區分

可重用元素的使用與命名空間

xmlns與targetNamespace

關于XML Schema命名空間中已經有xmlns卻還要targetnamespace的了解

我的了解:

一個元素節點添加了targetNamespace,那麼這個節點以及節點之下就是用來定義這個節點。如果要用這個節點 下的元素,那麼就得加上這個節點的targetNamespace,而且還必須j加上xmlns:xxx=ttt(這裡的ttt代表targetNamespace,xxx代表targetNamespace的别名,然後在調用的地方使用xxx:nnn),哪怕是在這個節點之中“調用”。是以,如果你寫的這個xsd并不打算讓别人調用,那麼就别寫什麼targetNamespace,這隻會給你增加麻煩:自己定義的類型,同一個檔案内調用還得加上命名空間,多麻煩

二、一些常用的知識

  1. 簡易類型:
    • xs:string
    • xs:decimal【十進制數】
    • xs:integer【也有int類型】
    • xs:boolean
    • xs:date
    • xs:time
  2. 字元串類型是我們在xml裡最常用的類型,但有時候 我隻希望使用者填寫固定的某幾個字元串,實作“枚舉類型”,那麼可以這麼寫
<xs:simpleType name="carType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="Audi"/>
    <xs:enumeration value="Golf"/>
    <xs:enumeration value="BMW"/>
  </xs:restriction>
</xs:simpleType> 
           

這就實作了個簡單的枚舉類型,首先是string類型的,然後限定在“Audi”,“Golf”,“BMW”裡面的其中一個。

下面是常用的幾種對字元串限定的方式

- enumeration (布爾資料類型無法使用此限制*)

- length (布爾資料類型無法使用此限制)

- maxLength (布爾資料類型無法使用此限制)

- minLength (布爾資料類型無法使用此限制)

三、注意幾個問題

  1. 如果你想 定義一個

    類型

    ,然後在其他地方重複引用,不要定義成

    元素

    正确:

<xs:element name="product" type="prodtype"/>

<xs:complexType name="prodtype">
  <xs:attribute name="prodid" type="xs:positiveInteger"/>
</xs:complexType>
           

錯誤:

<xs:element name="product" type="prodtype"/>

<xs:element name="product" type="prodtype"/>
    <xs:complexType>
      <xs:attribute name="prodid" type="xs:positiveInteger"/>
    </xs:complexType>
</xs:element>
           
  1. 當使用all訓示器的時候,minOccurs可以選0或1,maxOccurs隻能選1。即任意排序裡的“子元素組”隻能有1組。否則會報錯的!
  2. Order訓示器和Group訓示器的預設子元素個數都是1,你如果想允許xml裡可以寫多個元素,隻能自己修改minOccurs、maxOccurs
  3. 為了避免使用者在填寫xml的内容是出現不必要的空格,我建議string類型改為token類型,它可以去掉前後空格及tab(很多網上的解釋感覺很有歧義:也不知道這個類型的意思是可以去掉空格,還是不能包含空格 否則報錯;試驗一下就知道了,在填寫xml的string類型時加上空格tab并不報錯,是以它的意思是幫你在讀取的時候過濾掉空格)

四、使用代碼校驗xml

設計好xml,寫好schema後就可以寫程式進行校驗了

有個問題:xml可以用schema來校驗,那schema自己的對錯怎麼檢驗呢

其實很簡單,把schema粘到eclipse裡就行了,對于文法上的錯誤,比如一開始說的那個,使用了targetNamespace,結果在下面引用了 這個schema裡定義的類型,還沒有加 命名空間。寫到eclipse裡就會報錯了。當然,eclipse也隻能檢驗文法錯誤,“邏輯”錯誤誰也沒轍。

  1. 如果想寫完schema就看看效果, 就把xml和他對應的sxd檔案都放在eclipse的同一個工程的同一個目錄下,然後在xml的标頭裡加上
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ddddd.xsd"
           

還記得一開始說的XMLSchema-instance裡的

schemaLocation

屬性嗎,它需要寫成這樣

前一個值是命名空間名稱,後一個才是schema所處的真正位置。而它的同胞

noNamespaceSchemaLocation

從名字上就可以看出,這個不需要命名空間名稱,而隻需要真實位址就行了,是以我直接寫上schema的位置,在eclipse裡就可以“實時”看看效果了,xml格式不符合xsd要求的時候,xml就會報錯。可以通過這種簡單的方式對xml和schema檔案進行互相檢驗

  1. 最終還是要落實到代碼上

    因為代碼很固定,即使使用的架構不同,但最終都是一段差不多固定的代碼,就不再重複,給兩個還不錯的連結:

    Java通過XML Schema校驗XML

    Schema和XMLErrorHandler問題

    就說一點,和第二個連結有關:我們是否需要把xml校驗的錯誤結果給出很“人性化,通俗”的錯誤回報?

    我的個人想法:既然我們用了xml來傳輸資料,那麼對方一般就不是什麼都不懂的“外行人”。對于“程式對程式”的傳輸,傳輸方就根本不應該出現 xml格式錯誤的問題:我們既然寫了schema,就是對外公開的,你在發送之前就得保證自己是按照schema的格式要求寫的。 對于“人對程式”,把這樣的錯誤資訊:

<errors>
  <error column="35" line="17" systemID="file:///E:/workspace-jzgk/loginUtil/web-enter.xml">cvc-enumeration-valid: Value 'ID1' is not facet-valid with respect to enumeration '[ID, NAME, CLASS, LINK_TEXT, PARTIAL_LINK_TEXT, XPATH, CSS_SELECTOR]'. It must be a value from the enumeration.</error>
  <error column="35" line="17" systemID="file:///E:/workspace-jzgk/loginUtil/web-enter.xml">cvc-type: The value 'ID1' of element 'fix-type' is not valid.</error>
</errors>
           

回報給使用者,基本已經夠 一個會配置xml的人了解是什麼錯誤了,再解釋 也無非把那幾個英文單詞翻譯一下