2010-04-26 13 views
9

Estoy usando xjc para generar clases Java a partir del esquema XML y el siguiente es un extracto del XSD.Esquema XML a clases Java con XJC

<xs:element name="NameInfo"> 
    <xs:complexType> 
    <xs:sequence> 
     <xs:choice> 
     <xs:element ref="UnstructuredName"/> <!-- This line --> 
     <xs:sequence> 
      <xs:element ref="StructuredName"/> 
      <xs:element ref="UnstructuredName" minOccurs="0"/> <!-- and this line! --> 
     </xs:sequence> 
     </xs:choice> 
     <xs:element ref="SomethingElse" minOccurs="0"/> 
    </xs:sequence> 
    </xs:complexType> 
</xs:element> 

En su mayor parte las clases generadas están bien, pero para el bloque anterior me gustaría tener algo como:

public List<Object> getContent() { 
    if (content == null) { 
    content = new ArrayList<Object>(); 
    } 
    return this.content; 
} 

con el siguiente comentario sobre ella:

* You are getting this "catch-all" property because of the following reason: 
* The field name "UnstructuredName" is used by two different parts of a schema. See: 
* line XXXX of file:FILE.xsd 
* line XXXX of file:FILE.xsd 
* To get rid of this property, apply a property customization to one 
* of both of the following declarations to change their names: 
* Gets the value of the content property. 

tengo colocó un comentario al final de las dos líneas en cuestión.

Por el momento, no creo que sea fácil cambiar el esquema, ya que esto se decidió entre proveedores y no me gustaría ir por esta ruta (si es posible) ya que ralentizará bastante el progreso.

He buscado y he encontrado this page, ¿la personalización externa es lo que quiero hacer? He estado trabajando principalmente con las clases generadas, por lo que no estoy completamente familiarizado con el proceso que genera estas clases. ¡Un ejemplo simple de la "personalización de propiedades" sería genial! El método alternativo para generar las clases de Java estaría bien, siempre y cuando el esquema aún se pueda usar.

EDITAR: Debo aclarar que los dos UnstructuredName son de hecho el mismo elemento.

Respuesta

1

El problema esencial aquí es que tiene un <xs:sequence> que consiste en un <xs:choice>, que se traduce en Java como "un List de cosas". La estructura de tipos de Java no es lo suficientemente flexible como para representar esto mejor.

Una personalización vinculante podría ayudarle, pero en este caso, sospecho que no, ya que no puedo ver una mejor manera de representar esta información.

Una técnica alternativa que he utilizado en el pasado es pasar primero el esquema a través de una simple transformación XSLT, reorganizando los componentes en algo más compatible con JAXB, permitiendo las mismas estructuras que los documentos tendrán en realidad . De esta manera, puede "cambiar" el esquema sin cambiar el original.

+0

No estoy muy seguro de cómo re-organización de los elementos puede ayudar en este caso. Si puedo la "secuencia" interna en otro elemento, ¿se resolvería este problema? ¿Es eso factible con la transformación? Si realizo alguna transformación, ¿necesitaría una para transformarme en una estructura que me gusta y luego realizar otra transformación de regreso a su estructura original? – nevets1219

2

He tenido el mismo problema. Cambié a xmlbeans y eje. XMLBeans puede compilar su esquema sin problemas y sin dolor de cabeza. JaxB no puede manejar esto. Para hacer que JaxB maneje esto, puedes cambiar tu esquema un poco.

<xs:sequence> 
      <xs:choice> 
    <!-- changed the following line --> 
      <xs:element name="UnstructuredTop" type="UnstructuredName"/> 
    <!-- end of change --> 
      <xs:sequence> 
       <xs:element ref="StructuredName"/> 
       <xs:element ref="UnstructuredName" minOccurs="0"/> 
      </xs:sequence> 
      </xs:choice> 
      <xs:element ref="SomethingElse" minOccurs="0"/> 
    </xs:sequence> 

Entonces JaxB distinguirá los dos y no se apagará.

Sin embargo, su situación es como mi situación. Cambiar el esquema estaba fuera de discusión. Así que fui con xmlBeans y axis (que sux).

5

también puede utilizar una personalización vinculante llama <xjc:simple />:

<?xml version="1.0" encoding="UTF-8"?> 
<jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" 
       xmlns:xs="http://www.w3.org/2001/XMLSchema" 
       xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
       jxb:version="2.0"> 
     <jxb:globalBindings> 
      <xjc:simple /> 
     </jxb:globalBindings> 
</jxb:bindings> 

favor, sin embargo, se aconseje que esto es específico del proveedor (que usa algo más que XJC aunque;))

Más información here

0

Creé una clase contenedora para resolver el problema:

List<JAXBElement<?>> contentList = address.getContent(); 
if (contentList != null && contentList.size() > 0) { 
    Address4JaxbMula address4JaxbMula = new Address4JaxbMula(contentList); 

... }

...

public static class Address4JaxbMula { 
    public CountryCodeType countryCode; 
    public AddressFixType addressFix; 
    public String addressFree; 

    public Address4JaxbMula(List<JAXBElement<?>> contentList) { 
     if (contentList != null && contentList.size() > 0) { 
      for (JAXBElement<?> content : contentList) { 
       Object value = content.getValue(); 
       if (value.getClass().isAssignableFrom(CountryCodeType.class)) { 
        countryCode = (CountryCodeType) content.getValue(); 
       } else if (value.getClass().isAssignableFrom(AddressFixType.class)) { 
        addressFix = (AddressFixType) content.getValue(); 
       } else { 
        addressFree = (String) value; 
       } 
      } 
     } 
    } 

} 
Cuestiones relacionadas