2.2.12.7 Mixed Content
Mixed content lets you embed child elements into the value of an element.
One example for the natural application of mixed content would be the
representation of text, where parts of a paragraph's text value might
have some specific property such as boldface or italic. These stretches
are best represented as children of the paragraph element.
Here is an example written in some simple markup similar to HTML:
<P>
<B>Mixed content</B> lets you embed <I>child elements</I>
into the value of an element.
</P>
To see how JAXB handles mixed content, we define a schema for our very simple
text markup language. We'll have chunks of text that may be used as an
entire paragraph as well as part of a paragraph, to be rendered in boldface,
in italics or underlined. The complex type ChunkType
has its
attribute mixed
set to true since we'll want to have plain
text as well, and an unbounded repetition of choices as child elements.
<xsd:complexType name="ChunkType" mixed="true">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="B" type="ChunkType"/>
<xsd:element name="I" type="ChunkType"/>
<xsd:element name="U" type="ChunkType"/>
</xsd:choice>
</xsd:complexType>
<xsd:complexType name="TextType">
<xsd:sequence>
<xsd:element name="P" type="ChunkType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
The generated Java code is somewhat opaque, as ChunkType
features just one method getContent
, apparently the Swiss
army knife for slicing a chunk of text. The generic list type now
happens to be java.lang.Serializable
, which is just another
way of saying "(almost) anything goes".
public class TextType {
protected List<ChunkType> p;
public List<ChunkType> getP() {
if (p == null) {
p = new ArrayList<ChunkType>();
}
return this.p;
}
}
public class ChunkType {
protected List<Serializable> content;
public List<Serializable> getContent() {
if (content == null) {
content = new ArrayList<Serializable>();
}
return this.content;
}
}
The documentation JAXB generates is kind enough to inform us that the
elements in the list returned by getContent
are either of
type String
or of type JAXBElement<ChunkType>
.
As we already know, this is the wrapper class JAXB uses whenever elements
have to be distinguished by their tags, and, indeed, we did use
ChunkType
with B
, I
and U
.
Having penetrated this slight obfuscation, we can now write code to
process a text as a list of paragraphs. The content list of a text
chunk yields plain and decorated chunks in any order.
private static void dumpChunk( ChunkType c ){
for( Serializable s: c.getContent() ){
if( s instanceof String ){
System.out.print( (String)s );
} else {
String tag = ((JAXBElement)s).getName().getLocalPart();
ChunkType chunk = (ChunkType)((JAXBElement)s).getValue();
System.out.print( "(" + tag + ":" );
dumpChunk( chunk );
System.out.print( ":" + tag + ")" );
}
}
}
//...(process a text)
TextType text = ...;
for( ChunkType c: text.getP() ){
dumpChunk( c );
}