Форматирование XSD <element><complexType> против - PullRequest
6 голосов
/ 04 сентября 2010

Эта часть 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]

Я читал эту статью снова и снова, и действительно не могу понять разницу, и почему это будет # 1 против # 2 ...

Ответы [ 3 ]

12 голосов
/ 04 сентября 2010

Это не очевидно, я дам вам. Это сводится к решению типа против элемента.

Когда у вас есть что-то вроде

<xs:element name="rpcType">
   <xs:complexType>

По сути, это «анонимный тип», и это тип, который никогда не может встречаться нигде, кроме как внутри элемента rpcType. Из-за этой уверенности XJC знает, что этот тип всегда будет иметь имя rpcType, и поэтому генерирует для него аннотацию @XmlRootElement с именем rpcType.

С другой стороны, когда у вас есть

<xs:complexType name="rpcType">

тогда это определяет тип многоразового использования, на который потенциально могут ссылаться несколько различных элементов. Тот факт, что в вашей схеме на него ссылается только один элемент, не имеет значения. Из-за этой неопределенности XJC хеджирует свои ставки и не генерирует @XmlRootElement.

Эталонная реализация JAXB имеет собственный флаг XJC, называемый «режим простого связывания» , который, среди прочего, предполагает, что компилируемая схема никогда не будет расширена или объединена с другой. Это позволяет ему делать определенные предположения, поэтому, если он видит, что именованное complexType используется только одним element, то он часто генерирует @XmlRootElement для него.

Реальность более тонкая и сложная, чем это, но в 90% случаев это достаточное объяснение.

1 голос
/ 07 сентября 2010

Преимущества именованных типов

Преимущество схемы, использующей глобальные / именованные типы, заключается в том, что можно создавать дочерние / подтипы, расширяющие родительский тип.

<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 не может просто выбрать один из возможных элементов в качестве @XmlRootElement для класса, соответствующего «rpcType».

1 голос
/ 04 сентября 2010

Довольно сложный вопрос.Существует много причин для разработки схем с использованием типов, а не элементов (этот подход называется подходом «жалюзи» вместо «кусочка салями» для использования глобальных элементов).Одна из причин заключается в том, что типы могут быть подтипированы, а другая заключается в том, что полезно иметь только глобальные элементы, которые могут быть корневыми элементами.

См. в этой статье для получения дополнительной информации о стороне схемы.

Теперь, что касается вопроса JAXB в частности.Проблема в том, что вы создали класс, соответствующий типу, и попытались его сериализовать.Это означает, что JAXB знает свою модель содержимого, но не знает, каким должно быть имя элемента.Вам необходимо прикрепить свой RpcType к элементу (JAXBElement), например:

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

ObjectFactory был помещен в пакет, созданный JAXB для вас.

...