bla bla <...">

JAXB - Java / XMLValue and XMLElement conflict

I have the following html that I want to parse:

My input: <div> <span id="x1x1"> bla bla </span> </div> <span> <div> bla bla </div> </span> My output in java: jaxbContext = JAXBContext.newInstance(Div.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); jaxbUnmarshaller.unmarshal(file); System.out.println("id " + div1.getSpan().get(0).get(id) + "value " + div1.getSpan().get(0).get(id)) // should print: id = x1x1 value = bla bla 

I have the following class:

 public class Span List<Div> div; public List<Div> getDiv() { return div; } @XmlElement public void setDiv(List<Div> div) { for (int i = 0 ; i<div.size(); i++){ System.out.print("element")} this.div = div; } 

and

 public class Div List<Span> span = div1.get @XmlElement public void setSpan(List<Span> span) { for (int i = 0 ; i<span.size(); i++){ System.out.print("element")} this.span = span; } public List<Button> getSpan() { return span; } 

Now I also want the value span ("bla bla"). so I add to the Span class:

 String value; public String getValue() { return value; } @XmlValue public void setValue(String value) { this.value = value; } 

Bit this gives me the following error:

  If a class has '@XmlElement' property, it cannot have '@XmlValue' property. 

I am trying to use @XMLMixed, but to no avail. I would be happy, for example, with sample code. Thank.

+5
java jaxb
Mar 19 '13 at 9:01
source share
2 answers

UPDATE

Any element that can have both child notes that are text and elements has mixed content. In JAXB, this corresponds to the @XmlMixed annotation. @XmlMixed can be used independently by the collection property (see ORIGINAL RESPONSE) or in combination with @XmlAnyElement , @XmlElementRef or @XmlElementRefs . If the element can be anything that you would use @XmlAnyElement , if it is one known element, you would use @XmlElementRef and this is more than one known element that you use @XmlElementRefs .

Span

If both the text and the div are present in the same span, you can do the following by annotating the property with both @XmlElementRef and @XmlMixed . The element name specified in the @XmlElementRef annotation must match the direct root element specified for the target class.

 @XmlRootElement public class Span { List<Object> items = new ArrayList<Object>(); @XmlMixed @XmlElementRef(type=Div.class, name="div") public List<Object> getItems() { return items; } public void setItems(List<Object> mixed) { this.items = items; } } 

Div

The metadata for the div almost identical to the metadata specified for the Span .

 @XmlRootElement public class Div { List<Object> items = new ArrayList<Object>(); @XmlElementRef(name="span", type=Span.class) @XmlMixed public List<Object> getItems() { return items; } public void setItems(List<Object> items) { this.items = items; } } 

Demo

 public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Span.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); Span span = (Span) unmarshaller.unmarshal(new StringReader("<span>Text<div>Text2</div>Text3</span>")); System.out.println(span.getItems()); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(span, System.out); } } 

Exit

 [Text, forum15495156.Div@289f6ae, Text3] <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <span>Text<div>Text2</div>Text3</span> 



ORIGINAL RESPONSE

You can add the List<String> property annotated with @XmlMixed to the Span class:

Span

 import java.util.List; import javax.xml.bind.annotation.*; @XmlRootElement public class Span { List<Div> div; List<String> mixed; @XmlMixed public List<String> getMixed() { return mixed; } public void setMixed(List<String> mixed) { this.mixed = mixed; } public List<Div> getDiv() { return div; } @XmlElement public void setDiv(List<Div> div) { for (int i = 0; i < div.size(); i++) { System.out.print("element"); } this.div = div; } } 

Demo

 import java.io.StringReader; import javax.xml.bind.*; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Span.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); Span span1 = (Span) unmarshaller.unmarshal(new StringReader("<span>bla bla bla</span>")); System.out.println(span1.getMixed()); Span span2 = (Span) unmarshaller.unmarshal(new StringReader("<span><div/><div/></span>")); System.out.println(span2.getDiv()); } } 

Exit

 [bla bla bla] elementelement[forum15495156.Div@1f80ce47, forum15495156.Div@4166a779] 
+8
Mar 21 '13 at 14:58
source share
β€” -

Creating annotated JAXB classes from sample XML documents

Often the XML documents that need to be linked to the JAXB do not contain an XSD for the content, but there are some great tools to automate this if you have an XSD. This is the process that I use to quickly fill this gap and get a high-quality binding code. Hope this helps answer this question and gives a general solution for this type of problem.

High level process

This is the process I used to create the code for this random part of XML:

  • Get an example of good quality.
  • Create the XSD from the example using the Trang tool.
  • Create your binding code from XSD.

The whole process took me less than 5 minutes with preinstalled tools and gave high quality results. This is a very simple example, but the complexity of the XML example document can easily increase without increasing process time or reducing quality.

Creating a good quality example

A sample document is the most important part of this process. For more complex structures, you may need several documents to collect the necessary information, but we will stick to one document. We can make an example of the problem by wrapping the provided input in <div/> to create a file called example.xml :

 <div> <div> <span id="x1x1"> bla bla </span> </div> <span> <div> bla bla </div> </span> </div> 

This example shows that <div/> and <span/> can be nested and contain content.

NOTE. This HTML snippet is invalid because block-level elements cannot be nested inside inline elements. The β€œoff the shelf” circuit and the code generated from it are likely to choke on this input.

Create XSD from Example

This is a voodoo step in the process. Creating XSD manually will bring a lot of work and room for error. Without an automated process, you can also expose the complexity of the generator and the manual annotation code. Fortunately, there is a tool called Trang that will fill this gap.

Trang can do a lot, but one task he succeeds in is creating XSD from XML documents. For simple structures, he can completely cope with this step. For more complex input, it can get most of the way.

Trang is available from Maven Central in this vector:

 <dependency> <groupId>com.thaiopensource</groupId> <artifactId>trang</artifactId> <version>20091111</version> </dependency> 

You can download and convert the example.xml document with the following commands:

 wget http://repo1.maven.org/maven2/com/thaiopensource/trang/20091111/trang-20091111.jar java -jar trang-20091111.jar example.xml example.xsd 

The result is example.xsd :

 <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="div"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element ref="div"/> <xs:element ref="span"/> </xs:choice> </xs:complexType> </xs:element> <xs:element name="span"> <xs:complexType mixed="true"> <xs:sequence> <xs:element minOccurs="0" maxOccurs="unbounded" ref="div"/> </xs:sequence> <xs:attribute name="id" type="xs:NCName"/> </xs:complexType> </xs:element> </xs:schema> 

For simple documents, this is usually all that is required. You may need to edit this file a bit, but at least you have a working XSD as a starting point.

Generate your bind code with XSD

Now that we have the XSD, we can use the XJC tool and create the binding code we are looking for. To start XJC, pass it the XSD, the package you want to create, and the src directory. These two commands will generate code for example.xsd in a package named example :

 mkdir src xjc -d src -p example example.xsd 

You will now have the following files in the src directory:

 src/example/Div.java src/example/ObjectFactory.java src/example/Span.java 

I included the contents of the files at the end of this article, but here is the part that interests us from Span.java :

 @XmlElementRefs({ @XmlElementRef(name = "div", type = Div.class), @XmlElementRef(name = "span", type = Span.class) }) @XmlMixed protected List<Object> content; 

While manually coding annotations can work, automating the creation of these files can save time and improve quality. It also gives you access to all the plugins available for the XJC tool.




Filled Files Created by XJC

Example / Div.java:

 // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2013.03.22 at 01:15:22 PM MST // package example; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementRefs; import javax.xml.bind.annotation.XmlMixed; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; /** * <p>Java class for anonymous complex type. * * <p>The following schema fragment specifies the expected content contained within this class. * * <pre> * &lt;complexType> * &lt;complexContent> * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * &lt;choice maxOccurs="unbounded" minOccurs="0"> * &lt;element ref="{}div"/> * &lt;element ref="{}span"/> * &lt;/choice> * &lt;/restriction> * &lt;/complexContent> * &lt;/complexType> * </pre> * * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "content" }) @XmlRootElement(name = "div") public class Div { @XmlElementRefs({ @XmlElementRef(name = "div", type = Div.class), @XmlElementRef(name = "span", type = Span.class) }) @XmlMixed protected List<Object> content; /** * Gets the value of the content property. * * <p> * This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a <CODE>set</CODE> method for the content property. * * <p> * For example, to add a new item, do as follows: * <pre> * getContent().add(newItem); * </pre> * * * <p> * Objects of the following type(s) are allowed in the list * {@link Div } * {@link String } * {@link Span } * * */ public List<Object> getContent() { if (content == null) { content = new ArrayList<Object>(); } return this.content; } } 

Example / Span.java

 // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2013.03.22 at 01:15:22 PM MST // package example; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlMixed; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSchemaType; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** * <p>Java class for anonymous complex type. * * <p>The following schema fragment specifies the expected content contained within this class. * * <pre> * &lt;complexType> * &lt;complexContent> * &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * &lt;sequence> * &lt;element ref="{}div" maxOccurs="unbounded" minOccurs="0"/> * &lt;/sequence> * &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}NCName" /> * &lt;/restriction> * &lt;/complexContent> * &lt;/complexType> * </pre> * * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "content" }) @XmlRootElement(name = "span") public class Span { @XmlElementRef(name = "div", type = Div.class) @XmlMixed protected List<Object> content; @XmlAttribute @XmlJavaTypeAdapter(CollapsedStringAdapter.class) @XmlSchemaType(name = "NCName") protected String id; /** * Gets the value of the content property. * * <p> * This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a <CODE>set</CODE> method for the content property. * * <p> * For example, to add a new item, do as follows: * <pre> * getContent().add(newItem); * </pre> * * * <p> * Objects of the following type(s) are allowed in the list * {@link Div } * {@link String } * * */ public List<Object> getContent() { if (content == null) { content = new ArrayList<Object>(); } return this.content; } /** * Gets the value of the id property. * * @return * possible object is * {@link String } * */ public String getId() { return id; } /** * Sets the value of the id property. * * @param value * allowed object is * {@link String } * */ public void setId(String value) { this.id = value; } } 

Example / ObjectFactory.java

 // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2013.03.22 at 01:15:22 PM MST // package example; import javax.xml.bind.annotation.XmlRegistry; /** * This object contains factory methods for each * Java content interface and Java element interface * generated in the example package. * <p>An ObjectFactory allows you to programatically * construct new instances of the Java representation * for XML content. The Java representation of XML * content can consist of schema derived interfaces * and classes representing the binding of schema * type definitions, element declarations and model * groups. Factory methods for each of these are * provided in this class. * */ @XmlRegistry public class ObjectFactory { /** * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: example * */ public ObjectFactory() { } /** * Create an instance of {@link Div } * */ public Div createDiv() { return new Div(); } /** * Create an instance of {@link Span } * */ public Span createSpan() { return new Span(); } } 
+3
Mar 21 '13 at 16:22
source share



All Articles