XSD格式<element> <complextype> vs <complextype> <element> </element> </complextype> </complextype> </element>

时间:2010-09-03 20:16:42

标签: xsd jaxb

此XSD部分来自:http://www.iana.org/assignments/xml-registry/schema/netconf.xsd

 <xs:complexType name="rpcType">
   <xs:sequence>
     <xs:element ref="rpcOperation"/>
   </xs:sequence>
   <xs:attribute name="message-id" type="messageIdType" use="required"/>
   <xs:anyAttribute processContents="lax"/>
 </xs:complexType>
 <xs:element name="rpc" type="rpcType"/>

是NETCONF中函数调用的核心,它是XML文档的节点。我很好奇为什么它不是这样的:

 <xs:element name="rpcType">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="rpcOperation"/>
    </xs:sequence>
    <xs:attribute name="message-id" type="messageIdType" use="required"/>
    <xs:anyAttribute processContents="lax"/>
  </xs:complexType>
 </xs:element>

理由是在#1中尝试编组bean时(在jaxb2中)我得到了异常:

[com.sun.istack.SAXException2: unable to marshal type "netconf.RpcType" as an element because it is missing an @XmlRootElement annotation]

我一遍又一遍地阅读this文章,并且真的无法掌握差异,为什么它会是#1 vs#2 ...

3 个答案:

答案 0 :(得分:12)

这不明显,我会给你的。它归结为类型与元素决策。

当你有类似

的东西时
<xs:element name="rpcType">
   <xs:complexType>

这实际上是一个“匿名类型”,并且是一种在元素rpcType内部以外的任何地方都不会出现的类型。由于这种确定性,XJC知道该类型将始终具有名称rpcType,因此为其生成@XmlRootElement注释,并使用rpcType名称。

另一方面,当你有

<xs:complexType name="rpcType">

然后,这定义了一个可重用的类型,可能由几个不同的元素引用。在您的模式中它只由一个元素引用的事实是无关紧要的。由于不确定性,XJC对冲其赌注并且不生成@XmlRootElement

JAXB Reference Implementation有一个名为"simple binding mode"的专有XJC标志,除其他外,它假定您编译的模式永远不会扩展或与另一个模式组合。这允许它做出某些假设,因此如果它看到一个complexType只被一个element使用,那么它通常会为它生成@XmlRootElement

现实比这更微妙和复杂,但在90%的情况下,这是一个充分的解释。

答案 1 :(得分:1)

相当棘手的问题。使用类型而不是元素设计模式有很多原因(这种方法被称为“百叶窗”方法而不是“萨拉米片”用于使用全局元素)。其中一个原因是类型可以是子类型,另一个原因是只有全局元素才可以是根元素。

有关架构方面的更多详细信息,请参阅this article

现在,尤其是JAXB问题。问题是您创建了一个与类型对应的类并尝试将其序列化。这意味着JAXB知道其内容模型,但不知道元素名称应该是什么。您需要将RpcType附加到元素(JAXBElement),例如:

marshaller.marshal(new ObjectFactory().createRpc(myRpcType));

ObjectFactory已放入JAXB为您创建的包中。

答案 2 :(得分:1)

命名类型的优点

使用全局/命名类型的模式的优点是可以创建扩展父类型的子/子类型。

<xs:complexType name="rpcType"> 
    <xs:sequence> 
        <xs:element ref="rpcOperation"/> 
    </xs:sequence> 
    <xs:attribute name="message-id" type="messageIdType" use="required"/> 
    <xs:anyAttribute processContents="lax"/> 
</xs:complexType> 
<xs:element name="rpc" type="rpcType"/> 

上面的片段将允许创建以下子类型:

<xs:complexType name="myRPCType"> 
    <xs:complexContent> 
        <xs:extension base="rpcType"> 
            <xs:sequence> 
                <xs:element name="childProperty" type="xs:string"/>
            </xs:sequence> 
        </xs:extension> 
    </xs:complexContent> 
</xs:complexType> 

对JAXB的影响

命名类型的另一个方面是它们可能被多个元素使用:

<xs:element name="FOO" type="rpcType"/>
<xs:element name="BAR" type="rpcType"/>

这意味着Java编译器的模式不能简单地选择一个可能的元素作为对应于“rpcType”的类的@XmlRootElement。