2014-04-02 73 views
2

我想要一個具有內容或某個屬性但不是兩者的元素。 元素可以是這樣的:XSD:元素和屬性之間的選擇

<Location ref="blah"/> 

或本:

<Location> <aaaLocation>...</aaaLocation> <Location> 

但不喜歡這樣:

<Location ref="blah"> <aaaLocation>...</aaaLocation> <Location> 

我想這somee變化:

<xs:complexType name="FatherOfLocatiion"> 
     <xs:choice> 
      <xs:element name="Location"> 
       <xs:complexType> 
        <xs:sequence> 
         <xs:element name ="aaaLocation" type="Alocation"/> 
        </xs:sequence> 
       </xs:complexType> 
      </xs:element> 
      <xs:element name="Location"> 
       <xs:complexType> 
        <xs:attribute name="ref" type="xs:string" /> 
       </xs:complexType> 
      </xs:element> 
     </xs:choice> 
     <xs:attribute name="name" type="xs:string" use="required"/> 
    </xs:complexType> 

架構是在XML間諜工具中有效,但是當我試圖使用jaxb從它生成對象時,出現以下錯誤:

名稱爲「位置」且具有不同類型的多個元素出現在模型組中。

有沒有其他的方式來執行它?

回答

4

有一種方法可以做到這一點在XSD 1.0,其中涉及使用xsi:type的屬性; xsi:類型是XML屬性,但是,XSD感知型XML處理器會根據您的需要以不同的方式對待它。 (爲了完整起見,這種方法是XSD 1.1中替代類型的先驅,這是實現您想要的另一種方式)。

給出的以下XSD 1.0:

<?xml version="1.0" encoding="utf-8" ?> 
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) --> 
<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <xsd:element name="Location"/> 
    <xsd:complexType name="LocationWithRef"> 
     <xsd:attribute name="ref" type="xsd:string" use="required"/> 
    </xsd:complexType> 
    <xsd:complexType name="LocationWithContent"> 
     <xsd:sequence> 
      <xsd:element name="a"/> 
     </xsd:sequence> 
    </xsd:complexType> 
</xsd:schema> 

以下個XML將是有效的,但沒有其他組合;與屬性:

<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) --> 
<Location xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LocationWithRef" ref="a"/> 

隨着元素:

<?xml version="1.0" encoding="utf-8" standalone="yes"?> 
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) --> 
<Location xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LocationWithContent"><a/></Location> 

以上足以模型,你已經表明什麼XML世界;但是,對於XSD來編寫綁定技術,您需要採取額外步驟使其更友好,即JAXB(或.NET)。關鍵是將它們與一個抽象基類型(在ALocation下面)連接起來。

<?xml version="1.0" encoding="utf-8" ?> 
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) --> 
<xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <xsd:element name="Location" type="ALocation"/> 
    <xsd:complexType name="ALocation" abstract="true"/> 
    <xsd:complexType name="LocationWithRef"> 
     <xsd:complexContent> 
      <xsd:extension base="ALocation"> 
       <xsd:attribute name="ref" type="xsd:string" use="required"/>     
      </xsd:extension> 
     </xsd:complexContent> 
    </xsd:complexType> 
    <xsd:complexType name="LocationWithContent"> 
     <xsd:complexContent> 
      <xsd:extension base="ALocation"> 
       <xsd:sequence> 
        <xsd:element name="a"/> 
       </xsd:sequence>    
      </xsd:extension> 
     </xsd:complexContent> 
    </xsd:complexType> 
</xsd:schema> 

上述的優點是,它給你問:基於由幾乎所有的XSD處理器支持的技術(唉,XSI類型可能不是你的,還是其他民族,喜歡)那裏有。

不幸的是,XSD 1.1的支持是非常有限的,如果我不得不猜測,它需要一段時間才能被JAXB支持(你似乎感興趣),更不用說其他的XSD代碼了綁定解決方案...

0

唉,你想限制一個元素的內容基於它的一個屬性。使用Relax NG等其他模式語言可以實現這一點,但W3C XML模式則不然。奇怪的是,XML間諜沒有提出任何錯誤。

通常的解決方法是使用2個不同的元素名稱,例如LocationLocationWithRef

+0

但我必須使用完全相同的名稱。是否有沒有辦法做到這一點? – axelrod

+0

爲什麼你*有*使用完全相同的名稱? –

1

您無法通過XSD 1.0實現此功能,但您可以使用XSD 1.1

要告訴你的解析器,你的XSD 1.1,這些屬性添加到您的xs:schema元素:

xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"

如果您的解析器支持XSD 1.1,就會明白斷言,在那裏你可以使用XPath表達你的規則。

在這種XSD文檔:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" 
    xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> 
    <xs:element name="FatherOfLocation" type="FatherOfLocation"/> 
    <xs:complexType name="FatherOfLocation"> 
     <xs:sequence> 
      <xs:element name="Location" maxOccurs="unbounded"> 
       <xs:complexType> 
        <xs:sequence> 
         <xs:element name ="aaaLocation" type="xs:string" minOccurs="0"/> 
        </xs:sequence> 
        <xs:attribute name="ref" type="xs:string" use="optional"/> 
        <xs:assert test="(@ref and not(aaaLocation)) or (not(@ref) and aaaLocation)"></xs:assert> 
       </xs:complexType> 
      </xs:element> 
     </xs:sequence> 
    </xs:complexType> 
</xs:schema> 

兩者ref屬性和aaaLocation元件是可選的,但assert聲明限制了(在complexType的上下文中使用XPath)的規則:

(@ref and not(aaaLocation)) or (not(@ref) and aaaLocation) 

所以這將驗證爲:

<Location ref="blah"/> 

<Location> <aaaLocation>...</aaaLocation> </Location> 

反而會驗證了

<Location ref="blah"> <aaaLocation>...</aaaLocation> </Location> 

<Location></Location> 
+0

謝謝。太棒了。但是JAXB支持這個版本嗎? – axelrod

+0

我不這麼認爲。這太近了。但是在JAXB中,您可以使用Java來處理這些規則。您可以選擇只在寫入時生成一種格式或其他格式,並且在讀取外部生成的XML時,可以使用Java檢查文件內容(具有屬性和元素的方法)並選擇要讀取的內容。 – helderdarocha