xsd
  • schema
  • complextype
  • 2013-02-01 76 views 1 likes 
    1

    我想根據模式驗證自定義XML文檔。 本文檔將包含具有任意數量元素的結構,每個元素都具有特定的屬性。事情是這樣的:是否可以使用任意名稱定義具有特定屬性的XSD元素

    <Root xmlns="http://tns"> 
        <Records> 
        <FirstRecord attr='whatever'>content for first record</FirstRecord> 
        <SecondRecord attr='whatever'>content for first record</SecondRecord> 
        ... 
        <LastRecord attr='whatever'>content for first record</LastRecord> 
        </Records> 
    </Root> 
    

    的XML文檔的作者可以包括任何數量的記錄,每一個與他或她所選擇的任意名稱。這怎麼可能根據XML Schema來驗證?

    我試圖在一個模式來指定合適的結構類型,但我不知道如何引用它在適當的位置:

    <xs:schema xmlns="http://tns" targetNamespace="http://tns" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    
        <xs:complexType name="RecordType"> <!-- This is my record type --> 
         <xs:simpleContent> 
          <xs:extension base="xs:string"> 
          <xs:attribute name="attr" type="xs:string" use="required" /> 
          </xs:extension> 
         </xs:simpleContent> 
        </xs:complexType> 
    
        <xs:element name="Root"> 
         <xs:complexType> 
          <xs:sequence> 
           <xs:element minOccurs="1" maxOccurs="1" name="Records"> 
            <!-- This is where records should go --> 
            <xs:complexType /> 
           </xs:element> 
          </xs:sequence> 
         </xs:complexType> 
        </xs:element> 
    
    </xs:schema> 
    

    回答

    2

    您所描述的在XSD 1.1中是可能的,而在XSD 1.0中可能有類似的東西,這並不是說這是一個可取的設計。

    在XML詞彙表中,元素類型通常傳達有關信息類型的相關信息,它是用於在大多數XML模式語言中驅動驗證的元素類型的名稱;你所描述的設計(有些人會說)有點像問我是否可以用Java定義一個對象類,或者是一個C中的結構,它遵從成員可以擁有任意名稱的約束,只要其中一個是一個值爲42的整數。或者類似的東西可能是可能的,但大多數有經驗的設計師會強烈地感覺到,這幾乎肯定不是解決任何正常問題的正確方法。

    另一方面,使用系統執行異常和尷尬的事情有時可以幫助學習如何有效地使用系統。 (你永遠不會知道一個系統,我的一個朋友說過,直到你徹底濫用了它。)所以我的答案有兩個部分:如何儘可能接近你在XSD中指定的設計,以及你可能考慮的選擇代替。

    指定你似乎在XSD 1.1至所需的語言最簡單的方法是將其說,記錄元素定義的斷言(1)記錄每個孩子的「ATTR」屬性;(2)沒有兒童的記錄有任何孩子。你會是這樣的:

    ... 
    <xs:element minOccurs="1" maxOccurs="1" name="Records"> 
        <xs:complexType> 
        <xs:sequence> 
         <xs:any/> 
        </xs:sequence> 
        <xs:assert 
         test="every $child in * satisfies $child/@attr"/> 
        <xs:assert 
         test="not(*/*)"/>  
        </xs:complexType> 
    </xs:element> 
    ... 
    

    正如你所看到的,這是非常相似,InfantPro'Aravind」描述了;它避免了InfantPro'Aravind'通過使用斷言而不是類型賦值來強加您施加的限制的問題。

    在XSD中1。0,斷言是不可用的,我可以想到的接近您描述的設計的唯一方法是定義一個抽象元素,我將其稱爲Record,作爲Records的子元素,並要求實際的元素出現在Record的子元素被聲明爲可以替代這個抽象類型(這又要求它們的類型是從RecordType類型派生的)。你的模式可能會說這樣的事情:

    <xs:element name="Root"> 
        <xs:complexType> 
        <xs:sequence> 
         <xs:element name="Records"> 
         <xs:complexType> 
          <xs:sequence> 
          <xs:element name="Record"/> 
          </xs:sequence> 
         </xs:complexType> 
         </xs:element>   
        </xs:sequence> 
        </xs:complexType> 
    </xs:element> 
    
    <xs:complexType name="RecordType"> 
        <xs:simpleContent> 
        <xs:extension base="xs:string"> 
         <xs:attribute name="attr" 
            type="xs:string" 
            use="required" /> 
        </xs:extension> 
        </xs:simpleContent> 
    </xs:complexType> 
    
    <xs:element name="Record" 
          type="RecordType" 
          abstract="true"/> 
    

    在亞洲其他架構(可能在一個單獨的模式文檔),您將需要聲明FirstRecord等,並指定他們的替代記錄,因此:

    <xs:element name="FirstRecord" substitutionGroup="Record"/> 
    <xs:element name="SecondRecord" substitutionGroup="Record"/> 
    <xs:element name="ThirdRecord" substitutionGroup="Record"/> 
    ... 
    

    在一定程度上,這符合你的描述,但我懷疑你不想不得不宣佈FirstRecord,SecondRecord等

    已經描述的方法,使XSD可以做你的描述,我也說我不會推薦nd任何一種方法。相反,我會設計XML詞彙表以更自然地用XSD工作。

    在您指定的設計中,每條記錄看起來都具有相同的類型,但除了元素的內容之外,它們還允許通過具有不同的名稱來傳達額外的一定數量的信息(FirstRecord,SecondRecord等)。這些附加信息可以很容易地在屬性中傳達,這可以讓您將Record指定爲具體元素,而不是抽象元素,從而爲其提供額外的「備用名稱」屬性。然後,您的樣本數據會採用這樣的形式是這樣的:

    <Root xmlns="http://tns"> 
        <Records> 
        <Record 
         alternate-name="FirstRecord" 
         attr='whatever'>content for first record</Record> 
        <Record 
         alternate-name="SecondRecord" 
         attr='whatever'>content for first record</Record> 
        ... 
        <Record 
         alternate-name="LastRecord" 
         attr='whatever'>content for first record</Record> 
        </Records> 
    </Root> 
    

    這將取決於是否您或您的工具鏈您的數據提供程序或工具附加一些神祕或其他意義有字符串或多或少可以接受「 FirstRecord「是元素類型名稱而不是屬性值。

    或者,可以說設計的重點在於允許記錄包含任意結構元素的任意序列(在此帳戶中,對xs:string的限制只是您的示例中的一個人爲因素,並不是真正需要的實際上),只要我們對每條記錄都有'attr'屬性中記錄的信息。容易夠到指定此:定義「錄製」作爲與「ATTR」屬性的混凝土元件,接受一個子可以是任何XML元素:

    <xs:element name="Record"> 
        <xs:complexType> 
        <xs:sequence> 
         <xs:any processContents="lax"/> 
        </xs:sequence> 
        <xs:attribute name="attr" 
            use="required" 
            type="xs:string"/> 
        </xs:complexType> 
    </xs:element> 
    

    的「的processContents」屬性的值可以被改變以'嚴格'或'跳過'或保持'寬鬆',這取決於你是否希望FirstRecord,SecondRecord等被驗證(和聲明)。

    +0

    這是一個非常詳細的答案,非常感謝。據我所知,我無法訪問.net世界中的符合XSD 1.1的解析器,所以我無法測試它。至於XSD 1.0的解決方法,這是接近但不完全,所以我不能使用它。然後,它將使用一個簡單的無類型序列。額外的驗證必須在應用程序級別執行。 –

    +0

    感謝您的替代建議,雖然沒有在我的情況下做到這一點,其中包括實現一個基本的插件機制,由此每個插件將其屬性保存在PropertyBag中,該PropertyBag被序列化爲XML結構。在這種情況下,「記錄」被替換爲「屬性」,「@attr」替換爲「@vt」來指定屬性的「變體類型」。每個插件可以具有任何數量的屬性,每個屬性都由@vt屬性指定。解析器託管在我的框架中,而不是在每個插件中......因此需要一個固定的結構。 –

    +0

    XSD 1.0解決方案:比聲明NOT POSSIBLE好得多:) –

    0

    我想這是不可能單獨XSD!

    當你說

    任意數量的記錄,每一個與他或她所選擇的任意名稱。

    這迫使我們使用<xs:any/>元素,但!聲明爲any的元素不允許您驗證其屬性。

    所以..答案是NO!

    +0

    確實不可能用XSD 1.0,看來。根據C. M. Sperberg-McQueen的回答,似乎XSD 1.1是可能的,儘管我無法在.net世界中驗證,因爲據我所知,Microsof的解析器不支持它。 –

    +0

    @MaximeLabelle,.Net不支持XSD 1.1!但是撒克遜人,而.Net支持撒克遜! –

    相關問題