JAXB - Ignore element - java

Is there any way to just ignore an element from Jaxb parsing?
I have a large XML file, and if I could ignore one of the large, complex elements, then it would probably parse a lot quicker.
It would be even better if it could not even validate the element contents at all and parse the rest of the document even if that element is not correct.
ex:this should only generate Foo.element1 and Foo.element2
<foo>
<element1>I want this</element1>
<element2>And this</element2>
<bar>
<a>ALL of bar should be ignored</a>
<b>this also should be ignored</b>
<c>
<x>a lot of C that take time to process</x>
</c>
<c>
<x>a lot of C that take time to process</x>
</c>
<c>
<x>a lot of C that take time to process</x>
</c>
<c>
<x>a lot of C that take time to process</x>
</c>
</bar>
</foo>

Assuming your JAXB model looks like this:
#XmlRootElement(name="foo")
public class Foo {
#XmlElement(name="element1")
String element1;
#XmlElement(name="element2")
String element2;
#XmlElement(name="bar")
Bar bar;
}
then simply removing the bar field from Foo will skip the <bar/> element in the input document.
Alternatively, annotated the field with #XmlTransient instead of #XmlElement, and it will also be skipped.

JAXB will ignore any unmapped properties.
Implementation wise (atleast in EcliseLink JAXB (MOXy), which I lead). When we are processing the contents via a SAX parser (i.e. the input was a SAXSource) then we swap out our ContentHandler that is responsible for building objects to one that does no processing for that section (org.eclipse.persistence.oxm.unmapped.UnmappedContentHandler). When a we are using processing the contents via a StAX parser we just advance to the next mapped event.
If you do have a property that corresponds to that node you can annotate it with #XmlTransient to make it an unmapped property.

All what you need it's mark field as #XmlTransient (#XmlTransient annotation which should hide fields that are not required). Example below
JavaEE:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "DeletedIds")
public class DeletedIds {
#XmlElement(name = "DeletedId")
private List<DeletedId> id;
#XmlTransient
#XmlElement(name = "success")
private String success;
//getters&setters
}
#XmlAccessorType(XmlAccessType.FIELD)
public class DeletedId {
private int id;
//getters&setters
}
Xml:
<DeletedIds>
<DeletedId>
<id>1</id>
</DeletedId>
<DeletedId>
<id>2</id>
</DeletedId>
</DeletedIds>

You have to use a SAX parser, and a document handler that effectively "skips" the node of non-interest. You can't get around reading the bytes, but at least you can get around having them waste extra resources.
If your code requires a DOM tree, then you basically use a SAX document handler that generates DOM nodes, but "skips" the nodes of non-interest. Definitely less convenient that using the supplied DOM tree generators, but a decent trade-off is you can't live with the extra memory overhead of the unwanted nodes but you need the DOM tree.

Related

Java spring. Annotations for tricky serialization to json and xml

I'm trying to rewrite some API serialization from custom mappers to annotation-based style and faced with one hard mapping (which was earlier custom-serialized to json and xml separately) that I can not "translate" to. (Serialization is made with Jackson.)
In the POJO we have a collection, e.g.
class Data {
Set<Integer> tags;
}
which should be serialized in xml like:
<tags>
<tag id="1"/>
<tag id="2"/>
</tags>
and in json like:
{
"tags":[1,2]
}
Strait method with
#XmlElementWrapper(name="tags")
#XmlElement(name="tag")
gives good json, but incorrect xml like
<root>
<tags>
<tag>1<tag/>
<tag>2<tag/>
</tags>
</root>
cause there is no attribute specification.
I tried to wrap a bit with:
class Data{
#XmlElementWrapper(name="tags")
#XmlElement(name="tag")
Set<Tag> tags;
}
class Tag{
#XmlAttribute(name="id")
Integer id;
}
But this produces unwanted key in json format, like:
"tags":[
{"tag":{"id":1}},
{"tag":{"id":2}}
]
Ok, then. I tried to specify custom json serializer(implementing JsonSerializer and injecting with #JsonSerialize(using = ...) ), but seems it also affects xml "render".
Is it possible to do the trick with annotations only? Or mb is it possible somehow use default json serialization and custom xml serializtaion for some class? .e.g.
use custom xml serialization only for Reasons class in such way
class Data {
#XmlElement("tags")
Reasons tags;
}
but let all surrounding data be "render" with general strategy.
Simply create a getter annotated with #JsonValue will tell Jackson to produce a single value, without any field name.
This mapping:
#XmlRootElement
public class Data{
public Set<Tag> tags;
}
public class Tag{
#XmlAttribute
public Integer id;
#JsonValue
public Integer getId() {
return id;
}
}
Will then produce:
{"tags":[2,1]}
And:
<data><tags id="2"/><tags id="1"/></data>
PS: You're using JAXB annotations, i don't think Jackson will honor them.
To get the XML result above, you need to use JAXB:
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(Data.class, Tag.class);
Marshaller m = context.createMarshaller();
m.marshal(value, writer);
System.out.println(writer.getBuffer().toString());
As a final note, i'm not super fan of using a single mapping for multiple representations. It's probably good for simple stuff, but if your code grows more complex than this, i strongly suggest you create two sets of classes (one for XML mapping and one for JSON), maybe with a common interface.

How to create multiple xml request by only changing one field?

I need help to find the approach of how to create xml multiple times while I will be changing only two fields everytime and rest of the fields would be same as now. Please tell me the way to do it in java?
This is the sample xml below:
I would be changing the value of <Id> and <Originator>
<TransactionBlk>
<Id>NIK</Id>
<CorrelationId />
<Originator>NIK</Originator>
<Service>GetIns</Service>
<VersionNbr>1</VersionNbr>
<VersionNbrMin>0</VersionNbrMin>
<MsgNm>Req</MsgNm>
<MsgFormatCd>XML</MsgFormatCd>
</TransactionBlk>
You can crate one class contain all this parameter as class variable, create getter and setter method. Create object of class set value by using setter method.
You can use JAXB API's class to convert your java object into XML format.
The JAXBContext class provides the client's entry point to the JAXB API.
It provides an abstraction for managing the XML/Java binding information
necessary to implement the JAXB binding framework operations: unmarshal,
marshal and validate.
Here is Doc reference for convert your Java object into XML.
Here are tutorial for same Tutorial Link
Sample Code :
#XmlRootElement(name="TransactionBlk_REQ",namespace="http://TransactionBlk.com")
#XmlAccessorType(XmlAccessType.FIELD)
public class TransactionBlk
{
#XmlElement(name = "Id")
private String id;
#XmlElement(name = "Originator")
private String Originator;
//Your getter and setter method.
}
TransactionBlk bean = new TransactionBlk();
//Set your parameter value here
StringWriter responseWriter = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(TransactionBlk.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(bean, responseWriter);
String xmlStr = responseWriter!=null?responseWriter.toString():null;
You can use XSLT to transform XML.
If all you're doing is printing a "boilerplate" document with changes in those two values, a, you could use the DPH (Desperate Perl Hacker) approach: simply assemble it as text, pausing to print the values at the appropriate places. To be safe, you should pre-scan the values to make sure they don't contain the <, >, or & characters and escape those if you find them.
For something more complex, or if you want to start learning how to do it "properly", look at the standard XML APIs for Java: DOM (the Document Object Model, an in-memory tree model of a document), SAX (an event-stream view of a document), and JAXP (tools to take an XML document and parse it into DOM or SAX so you can read it, and to take DOM or SAX and write those out as XML syntax). JAXP also provides standard APIs for invoking XPath to search a document and XSLT to apply a stylesheet to a document, so taken together these cover a huge percentage of the basic operations on XML.
You might want to look at some tutorials on using Java to manipulate XML. I'm certainly biased, not least because they published one of my articles, but in my experience IBM's DeveloperWorks website (https://www.ibm.com/developerworks/xml/) has had better-than-average material for learning about XML and other standards.

Using a JAXB XmlAdapter to adapt an entire list without a wrapper element

I'm trying to use an XmlAdapter to unmarshal XML into a custom collection type (that intentionally does not implement the Collection interface due to a conflicting restriction imposed by another use of the class, which unfortunately fails if the class contains any collections). The difficulty is that the XML nodes that will be placed into the collection are not wrapped in a wrapper element.
Here's what my XML essentially looks like:
<xml>
<foo></foo>
<bar>1</bar>
<bar>2</bar>
</xml>
I can make JAXB unmarshall this to the following POJO:
class Naive {
Foo foo;
List<Bar> bar;
}
However, what I want to do is the following:
class Bars {
// There will be a fixed number of these, known in advance
Bar bar1;
Bar bar2;
}
class BarsAdapter extends XmlAdapter<ArrayList<Bar>, Bars> {
...
}
class Custom {
Foo foo;
#XmlJavaTypeAdapter(BarsAdapter.class) // won't work
Bars bar;
}
As you can see, I wrote an XmlAdapter that wants to adapt the entire list, not the individual elements, but it never gets invoked for unmarshalling. (It does get invoked for marshalling.)
If my XML contained a wrapper around the <bar> elements, then I know how to solve this:
<xml>
<foo></foo>
<wrapper>
<bar>1</bar>
<bar>2</bar>
</wrapper>
</xml>
because then I could annotate the bars field with #XmlElement(id="wrapper") and the adapter would get correctly called. However, the XML schema comes from an RFC and is entirely unchangeable, so I am stuck as to how to proceed. Any ideas appreciated!

Handling different object types contained within the same set of elements

I have an XML document that looks something like the following:
Note that I cannot change the schema because it is part of a standard XML Schema (Library of Congress METS).
<amdSec ID="AMDSEC001">
<digiprovMD ID="DMD001">
<mdWrap MDTYPE="OBJECT">
<xmlData>
<object xsi:type="file">
.....
</object>
</xmlData>
</mdWrap>
</digiprovMD>
<digiprovMD ID="DMD001_EVENT">
<mdWrap MDTYPE="EVENT">
<xmlData>
<event xsi:type="event">
.....
</event>
</xmlData>
</mdWrap>
</digiprovMD>
</amdSec>
As you can see, the inner element <mdWrap> can contain elements of different types; in this case they're <event> and <object>, but it isn't constrained to just those two types. Creating two classes (like below), marshals okay, but this doesn't work for unmarshalling.
class ObjectMDWrap {
#XmlElementWrapper(name = "xmlData")
#XmlElement(name = "object")
List<MyObject> object; //Wrapped in list to use #XmlElementWrapper
}
class EventMDWrap {
#XmlElementWrapper(name = "xmlData")
#XmlElement(name = "event")
List<MyEvent> event; //Wrapped in list to use #XmlElementWrapper
}
What can I do so that JAXB unmarshals the correct "type" of MDWrap?
I think, the best solution in this case is a generating POJO classes using XJC tool.
Download XSD file which describe XML file.
Using XJC tool convert XSD file into POJO classes. If XSD is not correct - fix it.
Make some changes if you need in generated classes.
Use this classes in marshalling / unmarshalling process.
I was able to figure out the solution, and it's much simpler than I initially thought (which speaks to my relative inexperience with XML and JAXB). By creating my MDWrap class in the following way
class MDWrap {
#XmlAnyElement(lax = true)
#XmlElementWrapper(name = "xmlData")
Object wrappedMD;
}
Then MDWrap can contain an object of any type, and will unmarshal properly, as long as the class of which wrappedMD is an instance of is annotated with #XmlRootElement. The trick is to annotate wrappedMD as XmlAnyElement.

What is the Jaxb equivalent of a Text node value?

I am looking to convert a class that looks like this ...
public class Amenity {
public String id;
public String value;
}
into the following XML using JaxB annotations:
<amenity id="id-string-here">value-string-here</amenity>
Does anyone know what annotation to use on the value member variable to accomplish this? The closest I've gotten so far is:
#XmlRootElement
public class Amenity {
#XmlAttribute
public String id;
#XmlElement
public String value;
}
Unfortunately this approach doesn't allow me to specify that the value member variable should not be rendered as its own tag <value></value>.
I'm not 100% sure about this, but try to use an #XmlValue annotation instead of #XmlElement.
It looks like the question was referring to text nodes not CDATA nodes, but here is a link on how EclipseLink JAXB (MOXy) handles CDATA:
http://bdoughan.blogspot.com/2010/07/cdata-cdata-run-run-data-run.html
This documentation writes:
Q. How can I cause the Marshaller to generate CDATA blocks?
A. This functionality is not available from JAXB directly, but you can configure an Apache Xerces-J XMLSerializer to produce CDATA blocks. Please review the JaxbCDATASample.java sample app for more detail.
(btw, this does not answer your particular question, but since the question title is misleading, and this is the first google result for jaxb CDATA, I'm answering a bit different question)
JAXB does not support marshaling/marshaling to/from CDATA xml types.

Categories