Nihvel Nihvel - 2 months ago 11
Java Question

Java loop inside Unmarshal object

At this link: JAXB Unmarshalling XML string - Looping through all tags
it was proposed a good solution.
I'm trying to benefit from it but I am not able to have it working in my case.

Consider a XML like this:

<campaign value="field1">
<name value="firstName"/>
<type value="type"/>
<record>
<firstTime value="13"/>
<secondTime value="14"/>
</record>
</campaign>


And consider all the classes for Unmarshalling, created and working.
campaign class, containing name, value, record[] etc.

JAXBContext c = JAXBContext.newInstance(Campaign.class);
Unmarshaller u = c.createUnmarshaller();
Campaign campaign = (Campaign) u.unmarshal(file);


I can extract the value of "name" and "type" but, because of the List<>, I am not able to go beyond this.

private String Name = null;
[...]
Name = campaign.getName().getValue();
System.out.println(Name);


How would you loop into
<record>
, and get all the values for firstTime and secondTime, knowing that there could be more
<record>
in other XML file?

EDIT:
Campaign Class

@XmlRootElement(name = "Campaign")
@XmlType(name = "Campaign", propOrder = {
"Name",
"Type",
"Record" })
public class Campaign {
@XmlElement(required = true)
protected Name Name;

@XmlElement(required = true)
protected Type Type;

@XmlElement(required = true)
protected List<Record> Record= new ArrayList<Record>();


public Name getName () {return Name;}
public void setName (Name value) {this.Name= value;}

public Type getType () {return Type;}
public void setType (Type value) {this.Type = value;}

public void setRecord(Recordvalue) {this.Record.add(value);}
}


Record Class

@XmlRootElement(name = "Record")
@XmlType(name = "Record", propOrder = {
"firstTime",
"secondTime" })
public class Record{
@XmlElement(required = true)
protected firstTime firstTime;

@XmlElement(required = true)
protected secondTime secondTime;


public Name getFirstTime () {return firstTime;}
public void setFirstTime (firstTime value) {this.firstTime= value;}

public Name getSecondTime () {return secondTime;}
public void setSecondTime (secondTime value) {this.secondTime= value;}
}


The program is much more big, but it just keeps repeating.. I need to extract everything in order to upload to a DB later.
But now, I only need to print them on screen and knowing that I have all the values I'd need.

Yes I had a look at that link too, I don't know why I just can't concentrate on how to continue, seems that the worst part was easier for me!

Thanks

EDIT 3:
I forgot to paste the methods for set and get.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Type")
public class Type {

@XmlAttribute
protected String value;

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


It is the same for all, I simply pasted Type here.

Answer

I'm still unsure about what your problem is. Tell me if my answer is not what you're looking for.

You have a few changes to make :

@XmlRootElement(name = "campaign")
@XmlType(name = "campaign", propOrder = {
    "name",
    "type",
    "record" })
public class Campaign {
    @XmlElement(required = true)
    protected Name name;

    @XmlElement(required = true)
    protected Type type;

    @XmlElement(required = true)
    protected List<Record> record;


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

    public Type getType () {return type;}
    public void setType (Type value) {this.type = value;}

    //Initialise your record list inside the getter instead of in member declaration
    public List<Record> getRecord() {
        if(this.record == null) record = new ArrayList<>();
        return this.record;
    }

    //Do not use a setter as an add method for the list
    public void setRecord(List<Record> value) {this.record = value;}

    //If you need to add record inside your list, do not use a setter, define an add method or access the list with the getter.
    public void addRecord(Record value) {this.record.add(value);}
}

I'll go under the assumption that you have defined proper toString() method for all of the classes used in the Campaign.

For exemple, the Record class string may go like :

@Override
public String toString(){
    return " First value : + "this.firstTime.getValue() + " Second value : " +this.secondTime.getValue();
}

Now to display everything :

List<File> files = new ArrayList<>();

//Add all XML Files containing a campaign root element into the files list
JAXBContext c = JAXBContext.newInstance(Campaign.class);
Unmarshaller u = c.createUnmarshaller();

//Declare list to store all of your camapaign object
List<Campaign> campaigns = new ArrayList<>();

for(File f : files)
{
    campaigns.add(u.unmarshall(f));
}

//display all campaigns
for(Campaign camp : campaigns){
    System.out.println(camp.getName());
    System.out.println(camp.getType());

    //Display all records
    for(Record rec : camp.getRecord()){
        System.out.println(rec);
    }
}

You can of course change the System.out.println() lines to whatever code you want.

Comments