Search code examples
javajaxbxml-binding

jaxb: bind attribute to element


How can I realize this XML with JAXB? Currently the expires attribute in the grantA,C,B elements is not bounded - but it should. I don't know how to associate an element with an attribute. Do I have to create classes for every grantA,C,B?
XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <customers>
        <customer>
            <name>C1</name>
            <grantA expires="">false</grantA>
            <grantB expires="">true</grantB>
            <grantC expires="">true</grantC>
        </customer>
        <customer>
            <name>C2</name>
            <grantA expires="">false</grantA>
            <grantB expires="">true</grantB>
            <grantC expires="">true</grantC>
        </customer>
        <customer>
            <name>C3</name>
            <grantA expires="">false</grantA>
            <grantB expires="">true</grantB>
            <grantC expires="">false</grantC>
        </customer>
    </customers>

XSD:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="name" type="xs:string" />

    <xs:element name="grantA" type="xs:boolean" />
    <xs:element name="grantB" type="xs:boolean" />
    <xs:element name="grantC" type="xs:boolean" />

    <xs:element name="customers" type="customers" />
    <xs:element name="customer">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="name" />
                <xs:element name="grantA">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:string">
                                <xs:attribute name="expires" type="xs:string" />
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
                <xs:element name="grantB">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:string">
                                <xs:attribute name="expires" type="xs:string" />
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
                <xs:element name="grantC">
                    <xs:complexType>
                        <xs:simpleContent>
                            <xs:extension base="xs:string">
                                <xs:attribute name="expires" type="xs:string" />
                            </xs:extension>
                        </xs:simpleContent>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="customers">
        <xs:sequence>
            <xs:element ref="customer" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:schema>

My current state is:

Customers.java:

@XmlRootElement(name = "customers")
public class Customers
{
    private List<Customer>  customerList;

    @XmlElement(name = "customer")
    public List<Customer> getCustomerList()
    {
        if (null == customerList)
        {
            customerList = new ArrayList<Customer>();
        }
        return customerList;
    }

    public void setCustomerList(List<Customer> customers)
    {
        this.customerList = customers;
    }

}

Customer.java

@XmlRootElement(name = "customer")
@XmlType(propOrder = { "name", "grantA", "grantB", "grantC" })
public class Customer
{
    private String  name = "";
    private boolean grantA;
    private boolean grantB;
    private boolean grantC;

    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)   
    @XmlElement(name = "name", required=true)
    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    @XmlElement(name = "grantA", required=true)
    public boolean isGrantA()
    {
        return grantA;
    }

    public void setGrantA(boolean grantA)
    {
        this.grantA = grantA;
    }



    @XmlElement(name = "grantB", required=true)
    public boolean isGrantB()
    {
        return grantB;
    }

    public void setGrantB(boolean grantB)
    {
        this.grantB = grantB;
    }

    @XmlElement(name = "grantC", required=true)
    public boolean isGrantC()
    {
        return grantC;
    }

    public void setGrantC(boolean grantC)
    {
        this.grantC = grantC;
    }


    @Override
    public String toString()
    {
        return "" + name + "[ " + grantA + ", " + grantB + " " + grantC + " ]";
    }

}

Solution

  • You could create a single class, Grant, like this:

    @XmlType
    public class Grant {
        @XmlAttribute
        private String expires;
    
        @XmlValue
        private boolean value;
    
        //getters and setters
    }
    

    and in the Customer class map it with different names, like this:

    public class Customer
    {
        private String  name = "";
        @XmlElement(name="grantA");
        private Grant grantA;
    
        @XmlElement(name="grantB");
        private Grant grantB;
    
        @XmlElement(name="grantC");
        private Grant grantC;
    
        //rest of the code
    }