Schema中命名空間對一致性約束的影響

Schema中命名空間對一致性約束的影響

Schema中有3種一致性約束:key約束、keyref約束和unique約束,這3種約束對命名空間的支持有點小問題,假設有以下Schema:
<!--key.xsd-->
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns="http://www.xml.org/schema"
  targetNamespace="http://www.xml.org/schema">
  
  <xs:complexType name="item_type">
    <xs:complexContent> 
      <xs:restriction base="xs:anyType">
        <xs:sequence>
          <xs:element name="id" type="xs:int"/>
          <xs:element name="name" type="xs:token"/>
        </xs:sequence>
      </xs:restriction>
    </xs:complexContent>    
  </xs:complexType>
  
  <xs:element name="item" type="item_type"/>
    
  <xs:element name="test">
    <xs:complexType>
      <xs:complexContent>
        <xs:restriction base="xs:anyType">
          <xs:sequence>
            <xs:element ref="item"  maxOccurs="unbounded"/>
          </xs:sequence>        
        </xs:restriction>
      </xs:complexContent>
    </xs:complexType>  
    <xs:key name="idKey">
      <xs:selector xpath="item"/>    <!--①-->
      <xs:field xpath="id"/>         <!--②-->
    </xs:key>
  </xs:element>
  
</xs:schema>
上面的Schema是在<test.../>元素(根元素)以內定義了惟一約束,定義test/item之下的<id.../>元素的值必須遵照惟一約束。對於以下XML文檔:
<!--key.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.xml.org/schema"
  xsi:schemaLocation="http://www.xml.org/schema key.xsd">
  
  <item>
    <id>1</id>
    <name>dell</name>  
  </item>  
  
  <item>
    <id>1</id>
    <name>sony</name>  
  </item>
  
</test>
上面的XML文檔中兩個<item.../>元素裏的<id.../>子元素的值徹底相同,這顯然不符合惟一約束的要求,但這份XML文檔依然是有效的。這是爲何呢?

發生這個問題是由於一致性約束對命名空間的支持有點小問題,上面的key.xsd定義一致性約束時在①、②號代碼處直接使用了item、id兩個元素,而沒有任何前綴。本質上它們依然處於http://www.xml.org/schema命名...,只是因爲指定了xmlns="http://www.xml.org/schema",所以在key.xsd中使用時無須添加限定短名做爲前綴。但一致性約束不這麼處理,它的處理規律是:只要該元素沒有添加任何限定短名,它就認爲該元素不處在任何命名空間下。也就是說,它約束的並非http://www.xml.org/schema命名...,而是對不在任何命名空間下的id進行約束,所以上面的key.xml文檔天然也就有效了。編程

爲了解決這個問題,當須要在Schema中對指定命名空間下的元素添加一致性約束時,必須爲其添加限定短名做爲前綴。能夠把key.xsd該爲以下形式:spa

<!--updated_key.xsd-->
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
  xmlns:sos="http://www.xml.org/schema"
  targetNamespace="http://www.xml.org/schema">
  
  <xs:complexType name="item_type">
    <xs:complexContent> 
      <xs:restriction base="xs:anyType">
        <xs:sequence>
          <xs:element name="id" type="xs:int"/>
          <xs:element name="name" type="xs:token"/>
        </xs:sequence>
      </xs:restriction>
    </xs:complexContent>    
  </xs:complexType>
  
  <xs:element name="item" type="sos:item_type"/>
    
  <xs:element name="test">
    <xs:complexType>
      <xs:complexContent>
        <xs:restriction base="xs:anyType">
          <xs:sequence>
            <xs:element ref="sos:item"  maxOccurs="unbounded"/>
          </xs:sequence>        
        </xs:restriction>
      </xs:complexContent>
    </xs:complexType>  
    <xs:key name="idKey">
      <xs:selector xpath="sos:item"/>    <!--①-->
      <xs:field xpath="sos:id"/>         <!--②-->
    </xs:key>
  </xs:element>
  
</xs:schema>
上面的updated_key.xsd中爲item、id元素定義約束時指定了sos前綴,因而一致性約束就會根據該前綴找到對應的命名空間,完成對 http://www.xml.org/schema命名...。若是上面的key.xml改成使用updated_key.xsd這份Schema做爲語義約束,那它就違反了惟一約束,天然也就是無效文檔了。

總結:
當須要在Schema中對指定命名空間下的元素(或屬性)添加像key、keyref或unique約束時,必須爲其添加限定短名做爲前綴,不然一致性約束會認爲只是對無命名空間的元素(或屬性)添加約束。rest


參考:
瘋狂XML講義
XML高級編程code

相關文章
相關標籤/搜索