unmarshal parse marshal jaxbunmarshaller jaxbcontext golang example bean xml jaxb unmarshalling

xml - parse - unmarshal golang



JAXB: ¿Cómo puedo eliminar XML sin espacio de nombres? (3)

Tengo un archivo XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <object> <str>the type</str> <bool type="boolean">true</bool> </object>

Y quiero desempaquetarlo para un objeto de la clase a continuación

@XmlRootElement(name="object") public class Spec { public String str; public Object bool; }

¿Cómo puedo hacer esto? A menos que especifique espacios de nombres (ver a continuación), no funciona.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <object> <str>the type</str> <bool xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:boolean">true</bool> </object>


Basado en los comentarios de Blaise (¡gracias, Blaise!) Y en mi investigación. Aquí está la solución a mi problema. ¿Estás de acuerdo con eso Blaise, o tienes una mejor manera?

package forum7184526; import java.io.FileInputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.util.StreamReaderDelegate; import org.eclipse.persistence.oxm.XMLConstants; public class Demo { public static void main(String[] args) throws Exception { XMLInputFactory xif = XMLInputFactory.newFactory(); XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("input.xml")); xsr = new XsiTypeReader(xsr); JAXBContext jc = JAXBContext.newInstance(Spec.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); Spec spec = (Spec) unmarshaller.unmarshal(xsr); } private static class XsiTypeReader extends StreamReaderDelegate { public XsiTypeReader(XMLStreamReader reader) { super(reader); } @Override public String getAttributeNamespace(int arg0) { if("type".equals(getAttributeLocalName(arg0))) { return "http://www.w3.org/2001/XMLSchema-instance"; } return super.getAttributeNamespace(arg0); } @Override public String getAttributeValue(int arg0) { String n = getAttributeLocalName(arg0); if("type".equals(n)) { String v = super.getAttributeValue(arg0); return "xs:"+ v; } return super.getAttributeValue(arg0); } @Override public NamespaceContext getNamespaceContext() { return new MyNamespaceContext(super.getNamespaceContext()); } } private static class MyNamespaceContext implements NamespaceContext { public NamespaceContext _context; public MyNamespaceContext(NamespaceContext c){ _context = c; } @Override public Iterator<?> getPrefixes(String namespaceURI) { return _context.getPrefixes(namespaceURI); } @Override public String getPrefix(String namespaceURI) { return _context.getPrefix(namespaceURI); } @Override public String getNamespaceURI(String prefix) { if("xs".equals(prefix)) { return "http://www.w3.org/2001/XMLSchema"; } return _context.getNamespaceURI(prefix); } } }


Una forma más fácil podría ser usar unmarshalByDeclaredType , ya que ya conoce el tipo que desea desasignar.

Mediante el uso

Unmarshaller.unmarshal(rootNode, MyType.class);

no necesita tener una declaración de espacio de nombre en el XML, ya que transfiere el JAXBElement que tiene el espacio de nombres ya configurado.

Esto también es perfectamente legal, ya que no es necesario que haga referencia a un espacio de nombres en una instancia XML, consulte http://www.w3.org/TR/xmlschema-0/#PO , y muchos clientes producen XML de esa manera.

Finalmente lo tengo a trabajar. Tenga en cuenta que debe eliminar cualquier espacio de nombre personalizado en el esquema; aquí está el código de muestra de trabajo:

El esquema:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="customer"> <xsd:complexType> <xsd:sequence minOccurs="1" maxOccurs="1"> <xsd:element name="name" type="xsd:string" minOccurs="1" maxOccurs="1" /> <xsd:element name="phone" type="xsd:string" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element>

XML:

<?xml version="1.0" encoding="UTF-8"?> <customer> <name>Jane Doe</name> <phone>08154712</phone> </customer>

Código JAXB:

JAXBContext jc = JAXBContext.newInstance(Customer.class); Unmarshaller u = jc.createUnmarshaller(); u.setSchema(schemaInputStream); // load your schema from File or any streamsource Customer = u.unmarshal(new StreamSource(inputStream), clazz); // pass in your XML as inputStream


ACTUALIZAR

Puede hacer que esto funcione al introducir una capa intermedia para traducir entre type y xsi:type . A continuación se muestra un ejemplo del uso de StAX StreamReaderDelegate para hacer esto para la operación unmarshal de JAXB:

package forum7184526; import java.io.FileInputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.util.StreamReaderDelegate; import org.eclipse.persistence.oxm.XMLConstants; public class Demo { public static void main(String[] args) throws Exception { XMLInputFactory xif = XMLInputFactory.newFactory(); XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("input.xml")); xsr = new XsiTypeReader(xsr); JAXBContext jc = JAXBContext.newInstance(Spec.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); Spec spec = (Spec) unmarshaller.unmarshal(xsr); } private static class XsiTypeReader extends StreamReaderDelegate { public XsiTypeReader(XMLStreamReader reader) { super(reader); } @Override public String getAttributeNamespace(int arg0) { if("type".equals(getAttributeLocalName(arg0))) { return XMLConstants.SCHEMA_INSTANCE_URL; } return super.getAttributeNamespace(arg0); } } }

xsi:type es un mecanismo de esquema para especificar el tipo real de un elemento (similar a un molde en Java). Si elimina el espacio de nombres, está cambiando la semántica del documento.

En EclipseLink JAXB (MOXy) le permitimos especificar su propio indicador de herencia para objetos de dominio usando @XmlDescriminatorNode y @XmlDescrimatorValue . Actualmente no ofrecemos este tipo de personalización para las propiedades del tipo de datos: