IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML  >

技巧: 何时使用局部声明和全局声明

XML Schema 中的两类元素

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

Benoit Marchal (bmarchal@pineapplesoft.com), 顾问, Pineapplesoft

2003 年 3 月 01 日

W3C XML Schema 提供了许多用于构建和组织 XML 词汇表的功能强大的选项。在本技巧中,Benoit 比较了元素的全局声明和局部声明,并提供了什么时候该使用何种声明的提示。

由于 XML 开发人员需要克服 DTD 作为建模语言的限制,所以 W3C XML Schema 变得越来越流行了。XML Schema 的特别流行是由于它提供了更丰富的数据类型。使用 XML Schema,可以很容易地指定一个元素应该包含文本、数字、布尔值还是其他一些数据类型。

不过,XML Schema 提供了比数据类型更多的功能。它具有组织元素声明的选项,可以改进可读性和易维护性。在本技巧中,我将为您展示XML Schema 中的范围选项。

局部声明与全局声明

XML Schema 让您可以直接在 xs:schema 元素下面声明元素,或者作为另一个声明的一部分声明元素。直接出现在 xs:schema 元素下面的声明具有 全局范围,而其他声明具有 局部范围。全局声明并不是新东西 -- DTD 中就已经引入它们了 -- 但是局部声明是 XML Schema 所独有的。

元素的全局声明和局部声明最明显的区别是在其他声明中可以引用全局声明,而局部声明只能存在于它们自己的局部范围内。一个实际的副作用是全局声明必须是唯一的:任何两个全局声明都不能有相同的元素名。另一方面,局部声明如果是在不同的上下文中,则不会产生冲突。甚至可以在局部覆盖一个全局声明。

为什么想要覆盖声明呢?在设计大型模式、特别是设计从现有模式中导入声明的新模式时,这是很有用的。在后一种情况下,导入的模式确实可能具有会引起冲突的声明。

例如 ,一个模式可能定义一个 key 元素为用于密钥的 base64 数据,而另一个模式将 key 定义为一个用于储存数据库标识符的整数。在这里, key 元素有两个不同的定义,如果要创建所导入的前两者的第三个模式就会产生问题。





回页首


分析例子

清单 1中的 模式 全部使用全局声明。 <xs:element name="..."> construct 定义了一个新元素,它类似于 DTD 中的 <!ELEMENT ...> 语句。这些声明可能会通过 <xs:element ref="..."/> construct 引用其他声明。


清单 1. 全局声明
<?xml version="1.0"?>
<xs:schema targetNamespace="http://ananas.org/2003/tips/local"
           xmlns:tp="http://ananas.org/2003/tips/local"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
   <xs:complexType>
      <xs:sequence>
         <xs:element 
        ref="tp:movie" maxOccurs="unbounded"/>
      </xs:sequence>
   </xs:complexType>
</xs:element>
<xs:element name="movie">
   <xs:complexType>
      <xs:sequence>
         <xs:element 
        ref="tp:title"/>
         <xs:element 
        ref="tp:genre" maxOccurs="unbounded"/>
      </xs:sequence>
   </xs:complexType>
</xs:element>
<xs:element name="title" type="xs:string"/>
<xs:element name="genre" type="xs:string"/>
</xs:schema>
      

引用和名称空间

引用一个全局元素定义时,需要提供完全限定的名字,包括相应的名称空间前缀(如 ref="tp:title" )。不过,元素声明是一个非限定名( name="title" )。这种行为背后的逻辑(有些扭曲)是:模式中的每一个声明都自动进入目标名称空间。是的,这有些让人迷惑,但是至少警告过您了。

另一方面,清单 2尽可能地使用了局部声明。唯一的全局声明是用于文档的根的(文档的根必须是全局声明,因为根没有父元素)。所有其他声明都嵌入到根声明下面。大量的嵌套使这种方法得到了一个别名“俄罗斯娃娃”。


清单 2. 局部声明
<?xml version="1.0"?>
<xs:schema targetNamespace="http://ananas.org/2003/tips/local"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">
<xs:element name="list">
   <xs:complexType>
      <xs:sequence>
         
        <xs:element name="movie" maxOccurs="unbounded">
            <xs:complexType>
               <xs:sequence>
                  
        <xs:element name="title" type="xs:string"/>
                    <xs:element name="genre" maxOccurs="unbounded" 
                        type="xs:string"/>
               </xs:sequence>
            </xs:complexType>
         </xs:element>
      </xs:sequence>
   </xs:complexType>
</xs:element>
</xs:schema>
      

注意 elementFormDefault 属性的使用。在默认情况下,XML 文档中具有局部声明的元素是非限定的(它们没有名称空间前缀)。背后的推论是非限定的元素类似于属性,因为属性在默认情况下是非限定的。

清单3展示了非限定的局部元素。在这里, movietitle genre 元素没有名称空间前缀,假定它们与其父元素在同一个名称空间中。对于非限定的局部元素的使用尚无定论。SOAP 成功地使用了一些,但是大多数用户认为它们是让人困惑的。

一句警告:需要将 清单 2中的 elementFormDefaultqualified 改为 unqualified 以验证清单 3。


清单 3. 非限定的局部元素
<?xml version="1.0"?> <tp:list xmlns:tp="http://ananas.org/2003/tips/local"> <movie>
<title>Johnny English </title>
<genre>comedy </genre>
</movie>
<movie>
<title>Finding Nemo </title>
<genre>family </genre>
</movie> </tp:list>

显然,如果要在文档中使用非限定的元素,那么必须使用局部元素。





回页首


得出结论

那么,局部声明和全局声明哪一个更好呢? 唉,就像设计策略的常见情况一样,答案不是这么黑白分明的,大多数模式同时使用两者。局部声明之所以有意义是因为它们隔离了模式的一部分。局部名对于其他上下文是不透明的,这使命名冲突的风险降到了最低。

局部声明的另一项好处是它们明确地标识了文档中可能的根。

局部声明的主要缺点是它们不能重复使用。在 清单 2中(使用局部声明),不能在另一个上下文中重复使用 movie 元素。在 清单 1中(使用全局声明)这是很容易的。

结论是,哪一种选择是最好的取决于元素的本性:一个准备在模式中别的地方重复使用的自包含元素最好使用全局声明,而只在给定上下文中起作用的元素应该在局部声明。

假定 movie 是一个自包含的元素,那么清单 4是一种更好的模式,它很好地结合了局部和全局声明。


清单 4. 混合声明
<?xml version="1.0"?> <xs:schema targetNamespace="http://ananas.org/2003/tips/local" xmlns:tp="http://ananas.org/2003/tips/local" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="list"> <xs:complexType> <xs:sequence> <xs:element ref="tp:movie" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="movie"> <xs:complexType> <xs:sequence> <xs:element name="title" type="xs:string"/> <xs:element name="genre" type="xs:string" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>

尽管在本技巧中没有讨论,但是您还可以在全局和本地声明中使用类型定义以改进模式的可读性。



参考资料



关于作者

Author photo

Benoit Marchal 是一位比利时籍的顾问。他是 XML by Example 和其它几本 XML 图书的作者。Benoit 可以为您的 XML 项目提供帮助。可以通过 bmarchal@pineapplesoft.com 或者他的个人网站 marchal.com 与他联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款