2011-11-22 21 views
15

從DTD遷移到XSD,出於某種原因遷移是顛簸的。我知道如何定義架構,一旦我進入<xs:schema>根標籤,但通過頭文件&命名空間聲明的東西證明對我來說尤其令人困惑。XML Schema標題和命名空間配置

我一直在試圖按照W3S上的精心製作的教程,但即使這個教程似乎承擔了大量的知識。

我猜我尋找的是一個國王的英語解釋它的屬性做什麼,他們去哪裏,以及爲什麼:

  • 的xmlns
  • 的xmlns:XS
  • 的xmlns:XSI
  • 的targetNamespace
  • XSI:的schemaLocation

而且在一些情況下,我看到這些元素/屬性的不同變體,例如xsi,其似乎具有兩種不同的符號,如xsi:schemaLocation="..."xs:import schemaLocation="..."

我想所有這些輕微的變化之間,我似乎無法做出每個這些做的正面或反面。預先感謝您爲這種混淆帶來的任何清晰!

回答

56

你需要了解的第一件事是XML命名空間。如果你有一些時間浪費,你可以閱讀the specification。我發現這是與XML有關的更清晰的規範之一。不要緊,如果你不明白它所說的一切,這是一個很好的基礎。但是這裏有一個快速的概要。

XML元素和屬性有一個名稱。當您看到<test att="hello"/>時,您正在查看名稱爲「test」的元素,其中我們有一個名稱爲「att」的屬性。但這並不是真正的整個故事......

XML是一種語法,允許您混合來自不同標記語言的內容。例如,使用XSLT將XML文檔轉換爲XHTML頁面時,至少要處理三種以XML定義的標記語言:輸入文檔的XSLT和XHTML。如果每個人保留自己的元素/屬性名稱並且不允許任何衝突,那麼這種混合會變得相當困難。

輸入XML名稱空間。 XML名稱空間定義了一個「球體」,其中元素和屬性名稱具有實際的語義。元素「template」在XSLT名稱空間中有明確的含義。元素「complexType」在XML Schema名稱空間中有明確的含義。如果您希望以自己的標記語言使用XML,那麼可以在不同的名稱空間中這樣做。

爲了確保名稱空間是唯一的,您需要提供一些唯一標識符。規範以URI的使用爲基礎,最常見的形式是HTTP URL。原因很簡單:這些URL往往是很好的唯一標識符。但這也是導致混淆的一個常見原因,因爲人們認爲URL在XML處理過程中真正具有含義或將通過網絡訪問。 非常清楚,事實並非如此! URL不需要指向任何現有資源。它不會經過任何轉換或解析爲網絡地址。即使兩個URL指向完全相同的東西,但當它們相差一個字符時,它們被認爲是不同的名稱空間。名稱空間標識符只是一個字符串,並且區分大小寫。而已。

隨着名稱空間的引入,XML元素或屬性的名稱突然由兩部分組成:名稱空間和本地名稱。 <test/>中的「測試」只是本地名稱。所謂的「完全限定名稱」由名稱空間和本地名稱的一種不可見組合組成。有時使用符號{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。

接下來是默認的命名空間。默認名稱空間可以用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上使用它。

您還會注意到,可以在XML文檔的任何元素上聲明名稱空間。該聲明的範圍(並且如果適用,則綁定到前綴)然後變成該元素及其內容。

這有時會變得令人困惑,甚至更多,因爲聲明可能互相覆蓋。查看此文檔:

<root xmlns="http://www.foo.com"> 
    <test /> 
    <so:test xmlns:so="http://www.stackoverflow.com" xmlns="http://www.bar.com"> 
     <test /> 
    </so:test> 
</root> 

花點時間弄清楚每個元素在哪個命名空間中......這是一個很好的練習。

root在命名空間http://www.foo.com中。第一個test元素也位於該名稱空間中,因爲我們尚未使用前綴,但我們處於該默認名稱空間的範圍內。第二個test元素的前綴爲so位於命名空間http://www.stackoverflow.com中,因爲這是我們將前綴綁定到的內容。

所以接下來是第三個最內層的test元素。它是什麼名字空間?它沒有前綴,因此它必須位於默認名稱空間中。但是,我們已經改變了第二個測試元素中的默認命名空間!所以現在最裏面的元素屬於http://www.bar.com命名空間,而不是http://www.foo.com

困惑了嗎?請記住以下幾點:

  • 命名空間只是一個字符串。 URI用作具有唯一標識符的便捷方式。
  • 前綴用於表示名稱空間,但其名稱不含任何含義。把它想象成一個佔位符。
  • 您可以設置默認名稱空間。其範圍內沒有前綴的所有元素都將成爲它的一部分。

Phew。現在,到W3C XML Schema。所有這些與它有什麼關係?

那麼,對於初學者來說,XML Schema本身就是一種用XML定義的標記語言。所以它有理由說它有自己的命名空間。那個名字空間正式爲http://www.w3.org/2001/XMLSchema。如果您將小寫字母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> 

所有的事情是,我們正在使用的東西的XML架構命名空間。然而,按照慣例,人們傾向於在XML模式中使用前綴xsxsd

當我們有一個XML文檔時,我們可能希望指定它的模式所在的位置。不止一個模式可以與XML文檔相關,因爲正如我們所說的,語言可以在XML中混合使用。爲了說XML文檔是模式的一個實例,再次有一個特殊的命名空間可用:http://www.w3.org/2001/XMLSchema-instance。按照慣例,我們傾向於將此名稱空間綁定到前綴xsi。但是,這不是強制性的。

在該模式實例名稱空間中定義了一些屬性。其中有schemaLocationnoNamespaceSchemaLocation。看看這個文件:

<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。該屬性告訴我們模式的位置,以驗證文檔中不在任何特定名稱空間中的那些部分。以下XML文檔在語義上完全相同:

<root xmlns:huh="http://www.w3.org/2001/XMLSchema-instance" huh:noNamespaceSchemaLocation="http://www.test.com/schema"> 
</root> 

請記住,前綴名稱沒有任何意義。他們是佔位符。那麼,那noNamespaceSchemaLocation屬性是什麼?基本上,它告訴我們我們可以在哪裏找到一個模式。現在,與名稱空間URI相反,這絕對是可以用來從網絡或本地存儲中獲取內容的東西。針對在文檔中聲明的模式進行驗證的XML處理器可能會嘗試獲取它。

然後有一個事實,它被稱爲noNamespaceSchemaLocation。模式定義了「目標名稱空間」。它所做的是聲明它定義的元素和屬性是哪個名稱空間的一部分。但是目標命名空間可能被省略。在這種情況下,我們得到了一個沒有命名空間的XML文檔模式。這種模式可以參考noNamespaceSchemaLocation

在很多情況下,模式實際上會定義一個名稱空間。爲了說哪個模式屬於哪個命名空間,我們可以使用http://www.w3.org/2001/XMLSchema-instance命名空間的另一個屬性:schemaLocation。該屬性可以包含名稱空間URI和模式URI的對(由空格分隔)。假設我們有位於http://www.myschemas.com/foo-schema的名稱空間http://www.foo.com的模式。然後,我們可以說,如下:

<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東西是用在那些XML文檔模式的實例。名稱空間http://www.w3.org/2001/XMLSchema是用於自己定義模式的名稱空間。


所以現在我們達到我們的URI和具有特殊含義看起來怪怪的屬性脖子。這是命名空間的事情:它們看起來非常複雜,直到你弄清楚它們是多麼簡單。只要密切關注哪些前綴綁定了哪些名稱空間URI,並知道該URI定義了什麼。

還有兩件事情需要解決您的問題:xs:importxs:include。注意我在這裏使用了xs前綴約定,因爲我們正在討論W3C XML Schema。

include元素可用於將模式與相同的目標名稱空間結合使用。基本上它允許我們將模式模塊化成更小的部分並將它們放在一起。

導入元素確實排序相同,但對於具有不同目標命名空間的模式。這使我們可以將模式組合爲不同的標記語言。


因此,要回顧:

  • xmlns:用來指定一個默認的命名空間。
  • xmlns:prefix:用於將命名空間綁定到prefix
  • http://www.w3.org/2001/XMLSchema:XML架構的名稱空間。根據約定,通常綁定在前綴xs,但這不是強制性的,也不是自動完成的。
  • http://www.w3.org/2001/XMLSchema-instance:這個命名空間定義了一些對於聲明XML文檔是如何作爲模式實例的細節有用的東西。根據約定,通常綁定在前綴xsi,但這不是強制性的,也不是自動完成的。
  • targetNamespace:可用於XML架構(在根元素上)的屬性,用於指定哪個名稱空間是模式定義。
  • schemaLocation:由名稱空間http://www.w3.org/2001/XMLSchema-instance定義的屬性之一,用於指示可以爲一個或多個名稱空間找到一個或多個模式的位置。

我最終的建議:找到一些方便的方法來驗證文檔對抗模式並玩一下。嘗試命名空間,包括和導入。使用多個名稱空間創建文檔並嘗試範圍界定。

之後,檢查XML本身,XML名稱空間和XML Schema的規範。這是硬核閱讀,但如果你通過它的方式,你會得到一個理解,許多人仍然似乎錯過多年的XML使用。最終它都會有意義。

祝你好運!

+3

這是史詩 - 應該是這類問題的權威答案,如果堆棧溢出支持此功能。感謝張貼這個我學到了很多東西,可以看到我的答案確實有限的原因。 –

+0

@hugh它甚至不完整...對於屬性,前綴有一些偏離規則。他們默認情況下不合格。但我不完全確定是否將它們放入元素的名稱空間中,因此我非常小心地對其進行說明。還有更多我可以提到的東西,但事實是隻有規格才能提供明確的答案。 –

+0

G_H很少有人花時間回答這個問題。謝謝! – IAmYourFaja

2

在回答你的疑問:

  1. xmlns - 在實例文檔中用於指示模式的XML獨特的價值是(或將驗證什麼架構反對)的實例。即使名稱空間沒有標識實際的模式文件,也應該有一個定義此名稱空間的模式。
  2. xmlns:xs - 所謂命名空間前綴並通過實例文檔用於表明在XML使用的類型都來自約定。你可以把它想成C#中的using或VB中的imports。例如,xmlns:xs="http://mySharedTypes"表示在這個XML中,我的一些類型來自命名空間「http:// mySharedTypes」,並且這些類型將以「xs」作爲前綴。
  3. xmlns:xsi - 如上所述。事實上,在引用W3C模式名稱空間http://www.w3.org/2001/XMLSchemahttp://www.w3.org/2001/XMLSchema-instance時,通常會使用xs和xsi前綴。然而,這些名稱空間前綴只是慣例,實際上可以是任何東西。
  4. targetNamespace - 您放入架構定義中的一個獨特值,它提供了您在架構中定義的類型的名稱空間。因此,如果有人想在模式中使用這些類型,那麼他們必須包含一個xmlns屬性,其值與targetNamespace的值相同。
  5. xs:import schemaLocation - 這通常是一個到另一個模式的相對路徑,儘管並不是所有的xml處理器都能識別它。因此,您可以選擇鏈接到您的xs:import中的另一個架構,作爲架構文件本身的一種快捷方式。導入中的另一個屬性是模式targetNamespace,這是強制性的。
  6. xsi:schemaLocation - 儘管這種共享相同的名稱import屬性是不相同的定義。按照慣例,xsi命名空間前綴引用來自http://www.w3.org/2001/XMLSchema-instance命名空間的類型,它們在實例文檔中使用,而不是模式文檔。

對不起,如果上述不明確,這是一個開放式問題的一點點,並有大量的材料,你可以寫任何一個點。如果您需要澄清任何一點,請提問 - 我會很樂意提供,或者創建一個範圍較窄的新問題。

+0

此信息不完全準確。 'xmlns'表示一個默認的命名空間,它沒有任何關於指示模式的事情。還有其他一些錯誤。它們可能很小,但是對於名稱空間和XML Schema而言,最小的事情可能會很快變得混亂。 –

+0

非常感謝你的休息;這是我遇到過的最好,最徹底,最容易理解的解釋。最後一個想法是:如果您正在構建符合架構的XML(如內存中的字符串),那麼該怎麼辦?您是否總是需要將這些xmlns,xs,xsi等東西放入「實例字符串」爲了驗證它,或者是否可以告訴解析器什麼模式來驗證XML;然後在模式中包含所有這些defs? – IAmYourFaja

+0

@G_H感謝您的評論。請隨時編輯我的答案,或請指出其他不準確的地方,我將納入我的答案。 –

0
  • xmlns="uri1"xmlns:whatever="uri2"是命名空間節點而不是屬性。他們的作用是說當你在名爲whatever:myElement的XML文檔中看到元素時,那麼元素屬於「whatever」命名空間。這個「任何名字空間」由名稱空間節點中聲明的URI標識。
  • targetNamespace是屬性。它包含一個URI,用於標識您在模式中定義的元素,類型和組。
  • xsi:schemaLocation完全不同。這是一個允許XML解析器查找附加到XML實例的模式的屬性。模式中不需要它。
  • 隨着xs:import你可以從不同的命名空間導入架構利用自己的元素和類型在你自己的模式。使用xs:import時,導入的模式和導入模式必須具有不同的名稱空間。如果它是相同的名稱空間,則使用xs:include