1

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.

Surya
  • 494
  • 3
  • 11
  • 23
  • 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 Oct 20 '11 at 12:41
  • 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 Oct 20 '11 at 12:45
  • 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 Oct 20 '11 at 13:44
  • 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 Oct 20 '11 at 16:59
  • 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 Oct 20 '11 at 17:11
  • You are absolutely right. Actually my approach was wrong. By the way, If you want someone to proceed with your way, what you would suggest? I understand xsd but I find it very cumbersome to write an xsd file on my own. Will you suggest any tool for that or some experience with xsd is enough? – Surya Oct 20 '11 at 18:19
  • You can use Eclipse to create a schema in a "visual" way so you don't have to know everything about schemas to write one that will work for you. Create a new schema and add types and elements. Use the Properties window to change various attributes. – John B Oct 20 '11 at 20:33
  • In my web application, I am receiving xml content (without xsd ) from some other services outside of my web app. My job is to retrieve the values from it using JAXB. Should I proceed with writing the xsd for the xml I am receiving and then using xjc tool to get jaxb specific classes and finally using the generated classes within my web application? Is my understanding correct? – Surya Oct 21 '11 at 03:49
  • That's how I would do it. Which is not saying that that is the "right" way necessarily. – John B Oct 21 '11 at 08:42

1 Answers1

3

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;
    }

}
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • I have to generate the xml from java using JAXB. Is not it possible to achieve the result using simple javax.xml.bind package? I mean without using any other library. – Surya Oct 20 '11 at 12:57
  • @Surya - Can you change your object model and introduce a second class to represent the address information? – bdoughan Oct 20 '11 at 13:05
  • Yes I can. But how should be my second class? If the attribute is on an complex type like above, then I can easily proceed with it. But the attribute that is giving me problem is type in
    tag which is a simple tag (without any nested tag within it). Could u please explain a more how to proceed?
    – Surya Oct 20 '11 at 17:03
  • @Surya - I have updated my answer with what the new model would look like. – bdoughan Oct 20 '11 at 17:11
  • It worked. Thanks a lot. The main tag I could not think of is @XmlValue in second model class. Anyhow, thanks for answering all my queries. I hope we can not produce the same xml without creating another model class for that. Am I right? – Surya Oct 20 '11 at 18:16
  • @Surya - Using the standard JAXB APIs you will need an `Address` class. If you use the `@XmlPath` extension from EclipseLink MOXy you do not need the `Address` class. – bdoughan Oct 20 '11 at 18:25
  • Ok. I will use EclipseLink MOXy whenever I get a chance. Thanks a lot again. – Surya Oct 20 '11 at 18:28