the type<...">

JAXB: how can I untie XML without namespaces?

I have an XML file:

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

And I want to cancel it for the class object below

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

How can i do this? If I do not specify a namespace (see below), this will not work.

 <?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> 
+9
xml jaxb unmarshalling
source share
4 answers

A simpler way might be to use unmarshalByDeclaredType , since you already know the type you want to decouple.

Using

 Unmarshaller.unmarshal(rootNode, MyType.class); 

you do not need to have a namespace declaration in XML, as you are passing a JAXBElement that already has a namespace installed.

This is also completely legal, since you do not need to refer to the namespace in the XML instance, see http://www.w3.org/TR/xmlschema-0/#PO - and many clients produce XML this way.

Finally he earned. Note that you need to remove any user namespace in the schema; here's a working code example:

Scheme:

 <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> 

JAXB Code:

 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 
+8
source share

UPDATE

You can get this to work by introducing an intermediate layer to translate between type and xsi:type . The following is an example of using StAX StreamReaderDelegate for this for a Unmarshal JAXB operation:

 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 is a schema mechanism for indicating the actual type of an element (similar to updating in Java). If you remove the namespace, you change the semantics of the document.

In EclipseLink JAXB (MOXy), we allow you to specify your own inheritance indicator for domain objects using @XmlDescriminatorNode and @XmlDescrimatorValue . We do not currently offer this type of customization for data type properties:

+6
source share

Based on Blaze's comments (thanks to Blaze!) And my research. Here is the solution to my problem. Do you agree with this Blaze, or do you have a better way?

 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); } } } 
+3
source share

Thanks to everyone here shared my solution that works for my code

I try to make it universal, each namespace contains a ":" I write code, if any tag has a ":" it will be deleted from XML.

This is used to skip namespace during unmarshalling using jaxb.

 public class NamespaceFilter { private NamespaceFilter() { } private static final String COLON = ":"; public static XMLReader nameSpaceFilter() throws SAXException { XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) { private boolean skipNamespace; @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { if (qName.indexOf(COLON) > -1) { skipNamespace = true; } else { skipNamespace = false; super.startElement("", localName, qName, atts); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.indexOf(COLON) > -1) { skipNamespace = true; } else { skipNamespace = false; super.endElement("", localName, qName); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (!skipNamespace) { super.characters(ch, start, length); } } }; return xr; } } 

to expose

 XMLReader xr = NamespaceFilter.nameSpaceFilter(); Source src = new SAXSource(xr, new InputSource("filePath")); StringWriter sw = new StringWriter(); Result res = new StreamResult(sw); TransformerFactory.newInstance().newTransformer().transform(src, res); JAXBContext jc = JAXBContext.newInstance(Tab.class); Unmarshaller u = jc.createUnmarshaller(); String done = sw.getBuffer().toString(); StringReader reader = new StringReader(done); Tab tab = (Tab) u.unmarshal(reader); System.out.println(tab); 
0
source share

All Articles