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该为如下形式:

<!--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约束时,必须为其添加限定短名作为前缀,否则一致性约束会认为只是对无命名空间的元素(或属性)添加约束。


参考:
疯狂XML讲义
XML高级编程


Lierba
16 声望0 粉丝

引用和评论

0 条评论