Search code examples
javaxmleclipsexml-parsingjavaparser

Read XML body element having multiple values based on different requests


I am parsing a XML request using Java. The XML structure is like this:

<?xml version="1.0" encoding="UTF-8"?>
<TestServices>
    <header>
        //Header Details
    </header>
    <body>
        <ele1>
            <ele2>
                <ele3>534159XXXXXX0176</ele3>  //Or ele_3, ele03, ele_03             
            </ele2>
        </ele1>
    </body>
</TestServices>

I have created classes for the same to read the Header and Body elements. Each node is a class and I am reading the ele3 value like this.

String ele3 = testServicesRequest.getBody().getEle1().getEle2().getEle3();

The element name for ele3 can be different based on different request. I have used Generate Java class from xsd feature in eclipse and it has generated classes like this.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "ele3"
})
public class ReqEle2 {
    @XmlElement(name = "ele3", required = true)
    protected String ele3;
    public String getEle3() {
        return ele3;
    }    
    public void setEle3(String value) {
        this.ele3 = value;
    }    
}

My requirement is simple. I just want to put multiple element names for single getEle3() method. eg. ele_3, ele03, ele_03 using less code changes. Or Please suggest me any other efficient way to do that.

For now I am trying to do this like this which I think is not good.

public class ReqEle3 {

    @XmlElement(name = "ele03", required = true)
    protected String ele3_1="";

    @XmlElement(name = "ele_3", required = true)
    protected String ele3_2="";

    @XmlElement(name = "ele3", required = true)
    protected String ele3_3="";

    @XmlElement(name = "ele3_old", required = true)
    protected String ele3_4="";

    public String getEle3() {
        if(ele3_1 != null && !ele3_1.isEmpty()){            
            return ele3_1;  
        }        
        else if(ele3_2 != null && !ele3_2.isEmpty()){           
            return ele3_2;  
        }
        else if(ele3_3 != null && !ele3_3.isEmpty()){           
            return ele3_3;  
        }
        else if(ele3_4 != null && !ele3_4.isEmpty()){           
            return ele3_4;  
        }
        return "";
    }    
}

Solution

  • You can write custom deserialiser for ele3 node. To be precise, custom deserialiser for ele2 node because this is the last constant node. Below example contains only required part to understand the solution:

    import org.w3c.dom.Element;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
    import javax.xml.bind.annotation.adapters.XmlAdapter;
    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    import java.io.StringReader;
    
    public class JaxbApp {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jaxbContext = JAXBContext.newInstance(ReqEle1.class);
            String xml0 = "<ele1><ele2><ele3>534159XXXXXX0176</ele3></ele2></ele1>";
            String xml1 = "<ele1><ele2><ele_3>534159XXXXXX0176</ele_3></ele2></ele1>";
            String xml2 = "<ele1><ele2><ele03>534159XXXXXX0176</ele03></ele2></ele1>";
    
            for (String xml : new String[]{xml0, xml1, xml2}) {
                StringReader reader = new StringReader(xml);
                Object unmarshal = jaxbContext.createUnmarshaller().unmarshal(reader);
                System.out.println(unmarshal);
            }
        }
    }
    
    @XmlRootElement(name = "ele1")
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {"ele2"})
    class ReqEle1 {
    
        @XmlJavaTypeAdapter(ReqEle2XmlAdapter.class)
        @XmlElement(name = "ele2", required = true)
        protected ReqEle2 ele2;
    
        // getters, setters
    }
    
    class ReqEle2XmlAdapter extends XmlAdapter<Object, ReqEle2> {
    
        @Override
        public ReqEle2 unmarshal(Object v) {
            Element element = (Element) v;
            ReqEle2 reqEle2 = new ReqEle2();
            reqEle2.setEle3(element.getFirstChild().getTextContent());
    
            return reqEle2;
        }
    
        @Override
        public Object marshal(ReqEle2 v) throws Exception {
            return null; // Implement if needed
        }
    }
    
    class ReqEle2 {
    
        protected String ele3;
    
        // getters, setters
    }
    

    Above code prints:

    ReqEle1{ele2=ReqEle2{ele3='534159XXXXXX0176'}}
    ReqEle1{ele2=ReqEle2{ele3='534159XXXXXX0176'}}
    ReqEle1{ele2=ReqEle2{ele3='534159XXXXXX0176'}}
    

    See also: