JoeWill
JoeWill

Reputation: 11

With JAXB, howTo create a class object to map element, attribute OR only value?

I need a class object "Cell" that could be used to create the following tags :

<cell display="orange"><text>Performances</text></cell>

but also :

<cell>SomethingWritten</cell>

To my understanding, I need to create a class with Xmlattribute (display), Xmlelement (text) but also Xmlvalue. So something looking like this :

public class Cell {

private String text;

@XmlAttribute
private String display;

@XmlValue
private String value;
}

How is it possible since the use of element and value is (seems to be) forbidden ? To be noticed, the Cell tags is always used as a list of object in the parent tag. So I always have something like :

<Page>
   <cell display="a"><text>thisIsText1</text></cell>
   <cell display="b"><text>thisIsText2</text></cell>
   <cell display="c"><text>thisIsText3</text></cell>
   <cell>value1</cell>
   <cell>value2</cell>
   <cell>value3</cell>
<Page/>

I tried using XmlMixed but never succeed. Thanks in advance.

Upvotes: 1

Views: 785

Answers (1)

Sam
Sam

Reputation: 680

The code below is bad design and may not work well going in the XML to Java direction, but it does resolve the central issue which is that an XML element cannot have both a value and a child element.

I'm sure there's a good reason XML is written this way, so the structure of the document being created here possibly breaks a few of their design principles, here is how to do it:

@XmlRootElement(name="page")
@XmlAccessorType(XmlAccessType.NONE)
public class Page {
    @XmlElements ( value = {
            @XmlElement(name = "cell", type = Cell.class),
            @XmlElement(name = "cell", type = CellValue.class)
        }
    )
    public List getValues()
    {
        List values = new ArrayList();
        values.addAll(cells);
        values.addAll(cellValues);
        return values;
    }

    private List<Cell> cells;
    private List<CellValue> cellValues;

    public Page(){
        cells= new ArrayList<>();
        cellValues = new ArrayList<>();
    }

    public List<Cell> getCells() {
        return cells;
    }

    public void setCells(List<Cell> cells) {
        this.cells = cells;
    }

    public List<CellValue> getCellValues() {
        return cellValues;
    }

    public void setCellValues(List<CellValue> cellValues) {
        this.cellValues = cellValues;
    }
}

@XmlRootElement(name = "cell")
@XmlAccessorType(XmlAccessType.NONE)
public class Cell {

    @XmlElement
    private Text text;
    @XmlAttribute
    private String display;

    public Cell() {
    }

    public Text getText() {
        return text;
    }

    public void setText(Text text) {
        this.text = text;
    }

    public String getDisplay() {
        return display;
    }

    public void setDisplay(String display) {
        this.display = display;
    }
}

@XmlRootElement(name = "text")
@XmlAccessorType(XmlAccessType.NONE)
public class Text {

    @XmlValue
    private String text;

    public Text(){}

    public Text(String text){
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

@XmlRootElement(name = "cell")
@XmlAccessorType(XmlAccessType.NONE)
public class CellValue {

    @XmlValue
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

With example usage:

    Cell c1 = new Cell();
    c1.setDisplay("123");
    c1.setText(new Text("abc"));

    Cell c2 = new Cell();
    c2.setDisplay("456");
    c2.setText(new Text("def"));

    Page page = new Page();
    page.getCells().add(c1);
    page.getCells().add(c2);

    CellValue cv1 = new CellValue();
    cv1.setValue("value1");

    CellValue cv2 = new CellValue();
    cv2.setValue("value2");

    page.getCellValues().add(cv1);
    page.getCellValues().add(cv2);

    JAXBContext jc = JAXBContext.newInstance(Page.class);

    Marshaller marshaller = jc.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(page, System.out);

And output:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<page>
    <cell display="123">
        <text>abc</text>
    </cell>
    <cell display="456">
        <text>def</text>
    </cell>
    <cell>value1</cell>
    <cell>value2</cell>
</page>

Upvotes: 1

Related Questions