When working with XML documents in Java, we often reach for DOM (Document Object Model), SAX (Simple API for XML), and the like. But when the document is complex, we can actually take a few lazy shortcuts. JAXB is my favorite lazy hack. When the file size is moderate (anything under 100 MB is a small file, heh), just throw the whole document into JAXB and then dig out the information you need from the JAXB objects. It’s a pretty nice approach.
But sometimes we run into weird formats.
For example, here is a snippet of XML:
<xxx>
here is <italic>a</italic> sample of <bold>XmlMixed</bold> type.
</xxx>So the corresponding XSD might look like this:
<complexType>
<complexContent>
<restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
<choice maxOccurs="unbounded" minOccurs="0">
<element ref="{http://xxx/schema}italic"/>
<element ref="{http://xxx/schema}bold"/>
</choice>
</restriction>
</complexContent>
</complexType>And compiling this XSD with xjc might produce code like the following:
@XmlElementRefs({
@XmlElementRef(name = "bold", namespace = "http://xxx/schema",
type = JAXBElement.class,
required = false),
@XmlElementRef(name = "italic", namespace = "http://xxx/schema",
type = JAXBElement.class,
required = false)
})
@XmlMixed
protected List<Object> content;Then, because of the requirements, we have to parse that here is <italic>a</italic> sample of <bold>XmlMixed</bold> type. text from above.
This time, even almighty Google doesn’t seem very helpful. Lots of people mention the mysterious creature called XmlMixed, but I couldn’t find anyone explaining in detail how to actually deal with it. Maybe everyone thinks it’s too simple to be worth mentioning—even the official docs don’t provide sample code... After some guessing (well, because I’m a noob), I finally figured it out. I’m writing it down here for my own future reference. If it helps others, that would be even better.
If anyone has more detailed information, thanks in advance for sharing.
Solution
Taking the earlier example, we end up with a List<Object> content. This content contains three kinds of data: 1) ordinary String, 2) a JAXBElement named bold, and 3) a JAXBElement named italic.
In terms of actual types, there are only two kinds of data: 1. String, 2. JAXBElement.
So we can solve it with a method like this:
public static String mixContentParse(List<Object> content){
String value = "";
for(Object cc: content){
if(cc.getClass().equals(JAXBElement.class)){
// italic or bold
value += ((JAXBElement)cc).getValue();
}else if(cc.getClass().equals(String.class)){
// general String type
value += ((String)cc);
}else {
System.out.println("There may sth wrong ?");
}
}
return value;
}This method retrieves all the text under the <xxx> tag and returns it as a String. After writing it, I realized it really is quite convenient. It’s just that without having studied this stuff, it feels like even the common-sense things slip by... embarrassing.
Just now my senior colleague critiqued my approach and gave me a more elegant version:
public static String mixContentParse(List<Object> content){
String value = "";
for(Object cc: content){
if(JAXBElement.class.isInstance(cc)){
// italic or bold
value += ((JAXBElement<?>)cc).getValue();
}else if(String.class.isInstance(cc)){
// general String type
value += (String)cc;
}else{
System.out.println("there may sth wrong?");
}
}
return value;
}
Comments · 7