1
votes

I have to generate the following xml in my program using JAXB.

         <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
        <Employee empId="12345">
          <name>ABC</name>
          <address type="Residence">Bangalore</address>
         </Employee>

I have to generate the above xml using JAXB. I am having the Employee class as follows:

Employee Class

    package mypack;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement (name = "Employee")
    public class Employee {
            private String name;
        private String address;
        private int empId;
        private String addressType;

        @XmlAttribute
        public int getEmpId() {
            return empId;
        }
        public void setEmpId(int empId) {
            this.empId = empId;
        }

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

        public String getAddress() {
            return address;
        }
        public void setAddress(String address) {
            this.address = address;
        }

        public String getType() {
            return addressType;
        }
        public void setType(String addressType) {
            this.addressType = addressType;
        }   
    }

I am using JAXB to marshal the object.

Employee emp = new Employee();
            emp.setName("ABC");
            emp.setEmpId(12345);
                emp.setAddress("Bangalore");
                    emp.setType("Residence");
                    JAXBContext context = JAXBContext.newInstance(Employee.class);
            Marshaller marshaller = context.createMarshaller();
            marshaller.marshal(emp, System.out);

It does not generate the required xml. Rather it generates the xml as follows:

**Xml Being Generated**

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Employee empId="12345">
       <name>ABC</name>
       <address>Bangalore</address>
       <type>Residence</type>
    </Employee>

Actually I don't know how to annotate the type attribute so that I will generate the xml as <address type="Resident">Bangalore</address> Is my Employee class should be like as above? If yes, then how to annotate the type attribute so that it will come as an attribute in <address> tag.

Please help me out.

1
Have you thought about creating a schema and using XJC to create your java class? In your schema you could set up all the attributes and values to want. - John B
Schema will be useful if I am generating the java classes from xml. But my requirement is I have to generate the xml as specified from java objects. I mean to say java to xml, not the reverse. And I don't have to worry about xml because the xml is not required to have a schema with it in my case. Thanks - Surya
FYI, a schema can be used if you are going in either direction. Even if I don't need one, I find it helpful to use a schema to define the format of the XML and let XJC create the JaxB-appropriate Java class for me. I find this easier than writing the JaxB stuff myself. That's just me though. - John B
I agree. But I don't have any xsd file so that I can use that to generate the java classes. I have nothing actually. My requirement is to generate the xml file as per the format above. How can I proceed? Thanks again. - Surya
That's my point. Create an xsd file and let it create the Java classes rather that doing the work to create the classes yourself. You have a choice, you can either do the work to create the classes by hand or do the work to create the xsd and let XJC create the classes from the xsd. Personally, given a requirement to produce an xml file with a certain format, I would rather spend the effort creating the xsd. - John B

1 Answers

3
votes

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

You could use the MOXy's @XmlPath extension for this use case:

@XmlPath("address/@type")
public String getType() {
    return addressType;
}

Employee

package mypack;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement(name = "Employee")
public class Employee {

    private String name;
    private String address;
    private int empId;
    private String addressType;

    @XmlAttribute
    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @XmlPath("address/@type")
    public String getType() {
        return addressType;
    }

    public void setType(String addressType) {
        this.addressType = addressType;
    }
}

Demo

package mypack;

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Employee.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/mypack/input.xml");
        Employee employee = (Employee) unmarshaller.unmarshal(xml);

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

}

Input/Output

<?xml version="1.0" encoding="UTF-8"?>
<Employee empId="12345">
   <address type="Resident">Bangalore</address>
   <name>ABC</name>
</Employee>

For More Information


UPDATE

If you do not want to use any vendor specific extension then you could introduce a second class to represent the address information:

Address

package mypack;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;

public class Address {

    private String address;
    private String addressType;

    @XmlValue   
    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @XmlAttribute
    public String getType() {
        return addressType;
    }

    public void setType(String addressType) {
        this.addressType = addressType;
    }
}

Employee

package mypack;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Employee")
public class Employee {

    private String name;
    private Address address;
    private int empId;

    @XmlAttribute
    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}