In JAXB or Xstream is it possible to Filter out certain Child Elements on Type/value during unmarshall

StackOverflow https://stackoverflow.com/questions/21161881

  •  28-09-2022
  •  | 
  •  

Domanda

Hope everyone is well, quick question to see if anyone has any feedback.

I was experimenting with both JaxB and Xstream over last two days. I was basically using the XML libraries to marshal and unmarshal XML to / from Java objects. Now this was a very simple task which I got working very quickly. However, the XML I want to unmarshal into a list of Java objects is very long and contains many child elements that could be ignored and not put into the list of java objects. For example the xml would look similar to:

<?xml version="1.0" encoding="UTF-8"?>
<Tables>
    <Table1>
        <TYPE>Test1</TYPE>
        <DATE>2014-01-16</DATE>
        <FLAG>True</FLAG>
    </Table1>
    <Table1>
        <TYPE>Test2</TYPE>
        <DATE>2014-01-15</DATE>
        <FLAG>False</FLAG>
    </Table1>
    <Table1>
        <TYPE>Test1</TYPE>
        <DATE>2014-01-14</DATE>
        <FLAG>True</FLAG>
    </Table1>
</Tables>

So I would like the library to iterate through all the xml elements and unmarshal into a list of java objects which so far works, however as it iterates I would like to add additional functionality to check the Type and Flag element values, if TYPE value equals Test2 and or if Flag value equals False to ignore this child element all together and not include it in the finished list of Java objects. Does anyone know if this is possible with either JaxB or Xstream? Alternatively, can anyone suggest maybe a better approach to accomplish this which requires minimum code and manual parsing.

I have been looking at ValidationEventHandler and XmlAdapter in JaxB but I do not think these will allow me do what I want. I got close with the Xmldapter however the unmarshal has to return either null or an object for each xml child element it processes, it also changed the xml syntax to attribute form i.e TYPE = "Test1" etc which I did not see any way of altering.

Xstream allows you to implement a Converter which has a canConvert method, however this only works on Class type, and not child element type which I weant to check for each child element. Had a look at MapperWrapper wrapMapper method which can be overloaded in Xstream, but it only shows element attribute name, i.e FLAG and does not show value, also if it did show value I do not see anyway of telling the function to ignore child root element and all attributes for said child.

Anyway, that's my two cent. Any advice?

È stato utile?

Soluzione

If you choose EclipseLink MOXy as your JAXB implementation (rather than the default implementation), you can use annotations on your Java classes for unmarshalling that employ XPath expressions. This could be used to filter out certain input. Here is the link: http://www.eclipse.org/eclipselink/moxy.php

Alternatively, and probably more simple, would be to use the XML transformation API with a stylesheet that has templates which filter out the unwanted content. Please check class javax.xml.bind.util.JAXBResult, which allows you to transform from one source (for example an InputStream or InputReader) directly to Java objects. Think of it as unmarshalling with a transformer in between.

EDIT: I'll give you a hand with a basic XSLT and some code. Here's the stylesheet that would do what you describe:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Table1[TYPE = 'Test1' or FLAG = 'True']">
        <!-- Don't do anything, since we want to filter these Table1 elements out -->
    </xsl:template>

</xsl:stylesheet>

And a code excerpt that can serve as a basis:

//Obtain a TransformerFactory
//Obtain a Source for your stylesheet, like a StreamSource
Transformer transformer = transformerFactory.newTransformer(source);

//Next, create an Unmarshaller from a JAXBContext
Unmarshaller unmarshaller = context.createUnmarshaller();

//Create a JAXBResult with the Unmarshaller
JAXBResult result = new JAXBResult(unmarshaller);

//Obtain a Source for your input XML, and transform
transformer.transform(inputSource, result);

//Get the JAXBElement from the result
final JAXBElement<?> jaxbEl = (JAXBElement<?>)result.getResult();

//And now your unmarshalled Java bean from the JAXBElement
Object bean = jaxbEl.getValue();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top