XML命名空间和属性

48

我正在尝试理解XML中命名空间的工作原理。当我有一个像foo:bar这样的元素时,属性通常不会有命名空间。但有时会有。即使声明了默认命名空间,属性也属于元素的命名空间吗?从xhtml的xsd中查看,似乎属性是模式的一部分,应该在xhtml的命名空间中,但它们从未以这种方式呈现...

4个回答

68
大多数情况下,属性不会有任何命名空间。《命名空间规范》(文中有强调)说:
默认命名空间声明适用于其范围内所有未加前缀的元素名称。默认命名空间声明不直接适用于属性名称; 未加前缀的属性的解释由它们所在的元素确定。
大多数XML词汇表使用非命名空间属性有一个原因:
当您的元素具有命名空间并且这些元素具有属性时,就不会存在混淆:属性属于您的元素,该元素属于您的命名空间。将命名空间前缀添加到属性只会使一切更加冗长。
那么为什么会存在命名空间属性呢?
因为一些词汇表主要通过属性来执行有用的工作,并且可以与其他词汇表混合使用。最著名的例子是XLink
最后,W3C XML模式有一种非常简单的方法(<schema attributeFormDefault="qualified">),可以声明您的属性属于一个命名空间,即使您使用默认命名空间,在您的文档中也强制您为其添加前缀。

1
这是一个非常有见地的回答,考虑到你在这里所说的,你是否认为这个陈述是错误的:“无论在哪里,所有属性都必须加前缀才能属于命名空间”?(上下文:http://stackoverflow.com/questions/10917416/configuring-an-xml-namespace/10917629#comment14238724_10917629 (Panda的回答)) - Doug Molineux
@Bart Schuller:这些属性很可能属于您的元素,但并不一定非要如此。 - Stefan Steiger
1
大多数XML词汇使用非命名空间属性,可能应该是“大多数XML词汇使用非前缀属性”,因为正如您正确所说,它们继承了命名空间,因此它们是“有命名空间的”,但只是没有前缀。 - Thomas Weller
不,它们不继承命名空间,因此它们没有命名空间,就像Bart所解释的那样。在查看属性时,可以得出结论:没有前缀=>默认命名空间。 - Thomas F.
1
@ThomasF。当查看属性时,可以安全地得出结论:没有前缀 => 没有命名空间。 - Robin A. Meade

17

XML 1.1中的命名空间(第二版)指出:“未加前缀的属性名称的命名空间名称始终没有值”,并且“未加前缀的属性的解释取决于它们所在的元素”

以下是使用Clark符号表示法来说明这一点的示例,其中命名空间前缀用花括号中的命名空间URL替代:

<bar xmlns:foo="http://www.example.com/"
    foo:baz="baz"
    qux="qux"/>
<bar xmlns="http://www.example.com/" xmlns:foo="http://www.example.com/"
    foo:baz="baz"
    qux="qux"/>
<foo:bar xmlns="http://www.example.com/" xmlns:foo="http://www.example.com/"
    foo:baz="baz"
    qux="qux"/>

<{}bar
    {http://www.example.com/}baz="baz"
    {}qux="qux"/>
<{http://www.example.com/}bar
    {http://www.example.com/}baz="baz"
    {}qux="qux"/>
<{http://www.example.com/}bar
    {http://www.example.com/}baz="baz"
    {}qux="qux"/>

6
第二和第三个例子中,qux 属性为什么没有继承元素的默认命名空间 http://www.foo.com/,你该如何解释? - dma_k
2
XML 1.1中的命名空间(第二版)说明:“未带前缀的属性名称的命名空间名称始终没有值”。 - jelovirt

11

今天在处理XSD时,有关属性和命名空间的问题让我花了一些时间才理解。在此,我将与大家分享这个经验,以防其他人也遇到同样的问题。

我正在处理的模式文档中,有几个全局属性被某些元素引用。简化起见,假设我所说的这个XSD是关于一个客户的。

让我们称其中一个全局属性为Id。使用它的根元素为Customer

我的XSD声明如下:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema  xmlns="http://schemas.mycompany.com/Customer/V1" 
targetNamespace="http://schemas.mycompany.com/Customer/V1" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">

我的Id属性声明看起来像这样:

<xs:attribute name="Id" type="xs:positiveInteger"/>

我的客户元素使用了以下属性:

<xs:element name="Customer">
   <xs:complexType>
      <xs:attribute ref="Id" use="required"/>
      <!-- some elements here -->
    </xs:complexType>
</xs:element>

现在,假设我想声明一个像下面这样的客户(Customer) XML文档:

<?xml version="1.0" encoding="utf-8"?>
<Customer Id="1" xmlns="http://schemas.mycompany.com/Customer/V1">
  <!-- ... other elements here -->
</Customer>

我发现当属性被全局声明时,它的命名空间与引用它的元素不在同一个命名空间中。

我想出了唯一的解决方案:像这样两次声明命名空间:一次不带前缀,使其成为元素的默认命名空间,另一次带有前缀,以便在属性中使用。因此,它应该看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<Customer cus:Id="1" xmlns="http://schemas.mycompany.com/Customer/V1"
 xmlns:cus="http://schemas.mycompany.com/Customer/V1">
  <!-- ... other elements here -->
</Customer>

这种做法非常不实用,所以我决定摆脱所有的全局属性并将它们声明为本地属性。在我给出的示例中,这样做会像这样:

这么做非常不切实际,所以我决定摆脱所有的全局属性,将它们声明为本地属性。在我给出的示例中,这样看起来:

<xs:element name="Customer">
   <xs:complexType>
       <xs:attribute name="Id" type="xs:positiveInteger" use="required"/>
       <!-- some elements here -->
   </xs:complexType>
</xs:element>

在网上很难找到关于我所谈论的内容的一些参考资料。最终我在Stylus XSD论坛中找到了这篇文章,其中一个叫Steen Lehmann的人建议要么将属性局部声明,要么在属性组内声明它以使属性声明不再是全局的。

"这样属性声明本身就不再是全局的"

这个最后的解决方案有点“hacky”,所以我决定坚持第一种解决方案并将所有属性都声明为局部的。


我发现在全局和局部元素声明中存在相同的问题:嵌套元素声明不会继承父命名空间。至于属性,如果它们不是全局的,那么我必须重复编写文档,这是我想要避免的。您能否提供一下使用全局属性的示例呢? - dma_k
真是XSD语言中一些非常奇怪/令人惊讶的规则。非常感谢您的解释。 - Matthew James Briggs

2
在w3c的6.1 命名空间作用域6.2 命名空间默认值中阅读。
基本上:
命名空间声明前缀的作用域从它出现的开始标记的开头一直延伸到相应的结束标记的结尾。
然而,这里的文本似乎没有解释<a>是指foo:a还是上下文中的默认命名空间。我认为它不是指foo:a,而是文档的默认命名空间a。考虑至少这个引用:
这样的命名空间声明适用于其作用域内所有元素和属性名称,其前缀与声明中指定的前缀匹配。
也就是说,命名空间"foo:"仅适用于以foo:为前缀的元素。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接