XML streaming through conversion to Unmarshaller JAXB with declared class type for root element

There are many examples of streaming XML through XSLT and then JAXB to Java objects. Often they look like this:

Transformer responseTransformer = TransformerFactory.newInstance().newTransformer(new StreamSource(getClass().getResourceAsStream("ResponseTransformation.xsl"))); Unmarshaller jaxbUnmarshaller = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName()).createUnmarshaller(); JAXBResult jaxbResult = new JAXBResult(jaxbUnmarshaller); responseTransformer.transform(new StreamSource(new StringReader(responseXml)), jaxbResult); res = jaxbResult.getResult(); 

There are also examples of Unmarshal JAXB from a declared type like this (from Unmarshaller javadoc):

 JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" ); Unmarshaller u = jc.createUnmarshaller(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new File( "nosferatu.xml")); Element fooSubtree = ...; // traverse DOM till reach xml element foo, constrained by a // local element declaration in schema. // FooType is the JAXB mapping of the type of local element declaration foo. JAXBElement<FooType> foo = u.unmarshal(fooSubtree, FooType.class); 

Notice how we define FooType.class for the root element in the u.unmarshal(fooSubtree, FooType.class) call u.unmarshal(fooSubtree, FooType.class) . Nice.

Question: Is there a way to combine a streaming processing method, as in the above example, with an indication of the type of declaration, as in the example below?

I like the way to achieve it, but it requires access to the JAXB implementation classes. Of course, this can be done through the open JAXB interface, right?

Thanks!

+4
source share
1 answer

You can access the unmarshaller.unmarshal (source, type) methods by creating an XMLFilter. This code will allow you to perform the conversion and not marshal into an object that is not associated with the root element in the XSD:

 import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLFilter; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.Unmarshaller; import javax.xml.bind.util.JAXBResult; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamSource; import static org.apache.commons.io.IOUtils.closeQuietly; ... InputStream transformIn = null; InputStream sourceIn = null; try { // get the transform and source streams. transformIn = ...; sourceIn = ...; // create the filtered source SAXTransformerFactory factory = (SAXTransformerFactory)TransformerFactory.newInstance(); XMLFilter filter = factory.newXMLFilter(new StreamSource(transformIn)); Source source = new SAXSource(filter, new InputSource(new InputStreamReader(sourceIn, "UTF-8"))); // unmarshal the object. Unmarshaller jaxbUnmarshaller = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName()).createUnmarshaller(); JAXBElement<FooType> foo = jaxbUnmarshaller.unmarshal(source, FooType.class); } finally { closeQuietly(transformIn); closeQuietly(sourceIn); } 

WARNING Just because you use the streaming API does not mean that the implementation is streaming. Most XSLT processors will create a DOM style representation for input before converting the document. If you are trying to avoid creating a document before canceling it, this code may not do this. See this answer for more information on processors.

+1
source

Source: https://habr.com/ru/post/1391352/


All Articles