从DTD迁移到XSD,由于某种原因,转换是一个颠簸的过渡。我了解如何在<xs:schema>
根标记内部定义模式,但是过了标题&amp;命名空间声明的东西对我来说尤其令人困惑。
我一直在努力遵循W3S上精心布置的教程,但即使是那个教程也似乎预先承担了很多知识。
我想我正在寻找的是国王的英语解释,说明哪些属性做了什么,他们去哪里,为什么:
在某些情况下,我会看到这些元素/属性的不同变体,例如xsi
,它似乎有两个不同的符号,如xsi:schemaLocation="..."
和xs:import schemaLocation="..."
我想在所有这些微小的变化中,我似乎无法对这些变化做出正面或反面。提前感谢为这种混乱带来任何清晰度!
答案 0 :(得分:61)
您需要了解的第一件事是XML命名空间。如果您有时间浪费,可以阅读the specification。我发现这是与XML相关的更清晰的规范之一。如果你不理解它所说的一切并不重要,它是一个很好的基础。但这是一个快速的破坏。
XML元素和属性有一个名称。当您看到<test att="hello"/>
时,您正在查看名称为&#34; test&#34;的元素,其中我们有一个名称为&#34; att&#34;的属性。但这并不是整个故事......
XML是一种语法,允许您混合来自不同标记语言的内容。例如,当使用XSLT将XML文档转换为XHTML页面时,您将至少处理XML中定义的三种标记语言:输入文档,XSLT和XHTML。如果每个人保留自己的元素/属性名称并且不允许任何冲突,这样的混合将变得相当困难。
输入XML命名空间。 XML命名空间定义了一个&#34;球体&#34;元素和属性名称具有实际语义。元素&#34;模板&#34;在XSLT命名空间中具有明确定义的含义。元素&#34; complexType&#34; XML Schema名称空间中具有明确定义的含义。如果您希望使用自己的标记语言使用XML,那么只要您在不同的命名空间中这样做,就可以这样做。
为了确保命名空间是唯一的,您需要提供一些唯一标识符。该规范决定了URI的使用,通常以HTTP URL的形式。原因很简单:这样的URL往往是很好的唯一标识符。但它也是导致混淆的一个非常常见的原因,因为人们认为URL确实具有意义,或者在XML处理期间将通过网络访问。 非常清楚情况并非如此!此URL不需要指向任何现有资源。它不会经历任何转换或被解析为网络地址。即使两个URL指向完全相同的东西,当它们相差一个字符时,它们也被视为不同的名称空间。命名空间标识符只是一个字符串,并且区分大小写。没什么。
随着名称空间的引入,XML元素或属性的名称突然由两部分组成:名称空间和本地名称。那&#34;测试&#34; <test/>
中只有本地名称。所谓的完全合格的名字&#34;由命名空间和本地名称的一种不可见的组合组成。有时会使用符号{namespace URI}local-name
,但这只不过是惯例。
所以现在我们需要能够在XML文档中使用名称空间。为了声明命名空间,XML具有硬编码机制。它使用特殊字符串xmlns
来允许进行名称空间声明。它可以通过以下两种方式之一完成:将命名空间绑定到前缀,或将其声明为默认命名空间。
绑定到前缀时,表单如下:xmlns:prefix="namespace URI"
。这是XML文档中的一个示例:
<foo:root xmlns:foo="http://www.foo.com">
<foo:test />
</foo:root>
我们现在将名称空间http://www.foo.com
绑定到前缀foo
。只要将此前缀放在元素或属性的名称前面,我们就会声明他们已成为该命名空间的一部分。
这里需要注意的是,实际前缀绝对没有任何意义。以下XML文档在语义上完全相同:
<bar:root xmlns:bar="http://www.foo.com">
<bar:test />
</bar:root>
前缀只是表示命名空间的便捷方式。它使我们不必每次都完全使用URI。
Next up是默认命名空间。可以使用xmlns="namespace URI"
声明默认命名空间。您可以抽象地将此视为将命名空间绑定到空前缀。再次使用相同的XML文档,但这次没有前缀:
<root xmlns="http://www.foo.com">
<test />
</root>
使用起来更方便一些。那为什么要有前缀呢?当我们混合来自不同名称空间的内容时,他们开始发挥作用:
<root xmlns="http://www.foo.com">
<so:test xmlns:so="http://stackoverflow.com" />
</root>
这次它是一个不同的XML文档。我们的root
元素位于http://www.foo.com
命名空间中,但test
元素位于http://stackoverflow.com
,因为我们已经绑定了so
前缀并使用了test
它在<root xmlns="http://www.foo.com">
<test />
<so:test xmlns:so="http://www.stackoverflow.com" xmlns="http://www.bar.com">
<test />
</so:test>
</root>
。
您还注意到,可以在XML文档中的任何元素上声明名称空间。该声明的范围(以及绑定到前缀,如果适用)则成为该元素及其内容。
这有时会变得令人困惑,甚至更多,因为声明可能会互相覆盖。查看此文档:
root
花点时间弄清楚每个元素的命名空间......这是一个很好的练习。
http://www.foo.com
位于命名空间test
中。第一个test
元素也在该命名空间中,因为我们还没有使用前缀,但我们在该默认命名空间的范围内。前缀为so
的第二个http://www.stackoverflow.com
元素位于命名空间test
中,因为它是我们绑定前缀的内容。
那么那里是第三个最里面的http://www.bar.com
元素。它的名称空间是什么?它没有前缀,因此它必须位于默认命名空间中。但是,我们在第二个测试元素中更改了默认命名空间!所以现在最里面的元素属于http://www.foo.com
命名空间,而不是http://www.w3.org/2001/XMLSchema
。
困惑了吗?请记住以下内容:
呼。现在,进入W3C XML Schema。所有这些与它有什么关系?
嗯,对于初学者来说,XML Schema本身是XML中定义的标记语言。所以它有理由得到它自己的命名空间。该命名空间正式为S
。如果你将<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</xsd:schema>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
</xs:schema>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
</schema>
写成小写,那就错了。开始明白为什么有些人真的讨厌命名空间?
以下三个文件完全相同:
xs
重要的是我们正在使用来自XML Schema名称空间的东西。但是,作为惯例,人们倾向于在XML Schema中使用前缀xsd
或http://www.w3.org/2001/XMLSchema-instance
。
当我们有XML文档时,我们可能希望指定它的架构所在的位置。多个模式可以与XML文档相关,因为我们已经声明语言可以混合在XML中。为了说XML文档是模式的实例,再次提供了一个特殊的命名空间:xsi
。按照惯例,我们倾向于将此命名空间绑定到前缀schemaLocation
。但同样,这不是强制性的。
在该架构实例命名空间中定义了几个属性。其中包括noNamespaceSchemaLocation
和<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.foo.com/schema">
</root>
。看一下这个文件:
xsi
那里发生了什么?首先,我们声明我们将前缀http://www.w3.org/2001/XMLSchema-instance
绑定到命名空间noNamespaceSchemaLocation
。然后我们在该命名空间中使用了一个属性:<root xmlns:huh="http://www.w3.org/2001/XMLSchema-instance" huh:noNamespaceSchemaLocation="http://www.test.com/schema">
</root>
。该属性告诉我们模式的位置,以验证文档中不在任何特定名称空间中的那些部分。以下XML文档在语义上完全相同:
noNamespaceSchemaLocation
请记住,前缀名称没有任何意义。他们是占位符。那么,noNamespaceSchemaLocation
属性的含义是什么?基本上,它告诉我们在哪里可以找到模式。现在与名称空间URI相反,这绝对是可用于从网络或本地存储中获取内容的东西。验证文档中声明的模式的XML处理器可能会尝试获取它。
然后有一个名为noNamespaceSchemaLocation
的事实。模式定义了一个&#34;目标命名空间&#34;。这样做是说明它定义的元素和属性的命名空间是什么。但是可以省略目标命名空间。在这种情况下,我们已经获得了没有命名空间的XML文档的模式。这种模式可以用http://www.w3.org/2001/XMLSchema-instance
来引用。
在许多情况下,架构实际上会定义命名空间。为了说明哪个架构属于哪个命名空间,我们可以使用schemaLocation
命名空间中的另一个属性:http://www.foo.com
。该属性可以包含名称空间URI和模式URI的对(由空格分隔)。假设我们有位于http://www.myschemas.com/foo-schema
的名称空间<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.foo.com http://www.myschemas.com/foo-schema">
</root>
的模式。然后我们可以说明如下:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.foo.com http://www.myschemas.com/foo-schema http://www.bar.com http://www.randomschemas.com/bar-schema">
</root>
这是一个包含多个命名空间位置对的示例:
http://www.w3.org/2001/XMLSchema-instance
这里需要记住的是http://www.w3.org/2001/XMLSchema
内容用于作为模式实例的XML文档。名称空间xs:import
是用于定义模式本身的名称空间。
所以到现在为止,我们依靠URI和具有特殊含义的怪异属性。这就是命名空间的问题:它们看起来非常复杂,直到你弄清楚它们有多简单。只需密切关注哪个前缀绑定到哪个名称空间URI,并知道该URI定义了什么。
我需要针对您的问题解决另外两个模式:xs:include
和xs
。请注意我在这里如何使用xmlns
前缀约定,因为我们正在谈论W3C XML Schema。
include元素可用于将模式与相同的目标名称空间组合。基本上它允许我们将模式模块化为更小的部分并将它们组合在一起。
import元素的排序方式相同,但对于具有不同目标名称空间的模式。这允许我们组合不同标记语言的模式。
所以回顾一下:
xmlns:prefix
:用于指定默认命名空间。prefix
:用于将命名空间绑定到http://www.w3.org/2001/XMLSchema
。xs
:XML Schema的命名空间。按惯例,通常绑定到http://www.w3.org/2001/XMLSchema-instance
前缀,但这不是强制性的,也不是自动完成的。xsi
:定义一系列有用的名称空间,用于声明XML文档如何作为模式实例的详细信息。按惯例,通常绑定到targetNamespace
前缀,但这不是强制性的,也不是自动完成的。schemaLocation
:可以在XML Schema(在根元素上)中使用的属性,用于指定这是一个模式定义的命名空间。http://www.w3.org/2001/XMLSchema-instance
:命名空间{{1}}定义的属性之一,用于指示可以为一个或多个命名空间找到一个或多个模式的位置。我的最后建议:找到一些方便的方法来验证文档对模式并稍微玩一下。试验命名空间,包含和导入。使用多个名称空间创建文档并尝试使用范围。
之后,检查XML本身,XML名称空间和XML Schema的规范。它是硬核阅读,但如果你顺利通过它,你将会理解许多人在使用XML多年后似乎仍然想念它。最终它都有意义。
祝你好运!答案 1 :(得分:2)
回答您的疑问:
xmlns
- 实例文档中使用的唯一值,用于指示XML是哪个架构的实例(或者它将验证哪个架构)。即使命名空间未标识实际的模式文件,也应该有一个模式来定义此命名空间。 xmlns:xs
- 称为名称空间前缀,并按照实例文档中使用的惯例来指示XML中使用的类型来自何处。您可以将此视为C#中的using
或VB中的imports
。例如,xmlns:xs="http://mySharedTypes"
表示在这个XML中,我的一些类型来自命名空间“http:// mySharedTypes”,这些类型将以“xs”为前缀。xmlns:xsi
- 如上所述。事实上,在引用W3C模式名称空间http://www.w3.org/2001/XMLSchema和http://www.w3.org/2001/XMLSchema-instance时,按惯例使用xs和xsi前缀。然而,这些名称空间前缀只是约定,实际上可以是任何东西。 targetNamespace
- 您在架构定义中放入的唯一值,它为您在架构中定义的命名空间提供了类型。因此,如果有人想要使用模式中的类型,那么它们必须包含与targetNamespace具有相同值的xmlns
属性。 xs:import schemaLocation
- 这通常是另一个架构的相对路径,但并非所有xml处理器都能识别它。因此,您可以选择链接到xs:import
中的另一个架构,作为架构文件本身的一种快捷方式。导入中的另一个属性是schema targetNamespace,这是必需的。 xsi:schemaLocation
- 虽然它与import属性的名称相同,但它的定义不同。按照惯例,xsi名称空间前缀引用http://www.w3.org/2001/XMLSchema-instance名称空间中的类型,这些类型在实例文档中使用,而不是在模式文档中使用。对不起,如果上述内容不明确,那就是一个开放式的问题,你可以为这些点中的任何一个写出大量材料。如果您需要明确任何一点,请询问 - 我很乐意提供,或者创建一个范围更窄的新问题。