0

I would like to parse XML file to the object. I read some articles, tutorials and I thought that the best option in that case is JAXB.

XML example:

<response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XML-Schema-instance" version="1.2" xsi:noNamespaceSchemaLocation="http://aviationweather.gov/adds/schema/metar1_2.xsd">
<request_index>136291043</request_index>
<data_source name="metars"/>
<request type="retrieve"/>
<errors/>
<warnings/>
<time_taken_ms>5</time_taken_ms>
<data num_results="2">
<METAR>
<raw_text>
PHTO 071453Z AUTO 23005KT 10SM FEW060 19/17 A3004 RMK AO2 SLP171 T01940172 55001 TSNO
</raw_text>
<station_id>PHTO</station_id>
<observation_time>2017-07-07T14:53:00Z</observation_time>
<latitude>19.72</latitude>
<longitude>-155.05</longitude>
<temp_c>19.4</temp_c>
<dewpoint_c>17.2</dewpoint_c>
<wind_dir_degrees>230</wind_dir_degrees>
<wind_speed_kt>5</wind_speed_kt>
<visibility_statute_mi>10.0</visibility_statute_mi>
<altim_in_hg>30.041338</altim_in_hg>
<sea_level_pressure_mb>1017.1</sea_level_pressure_mb>
<quality_control_flags>
<auto>TRUE</auto>
<auto_station>TRUE</auto_station>
<lightning_sensor_off>TRUE</lightning_sensor_off>
</quality_control_flags>
<sky_condition sky_cover="FEW" cloud_base_ft_agl="6000"/>
<flight_category>VFR</flight_category>
<three_hr_pressure_tendency_mb>-0.1</three_hr_pressure_tendency_mb>
<metar_type>METAR</metar_type>
<elevation_m>12.0</elevation_m>
</METAR>
<METAR>...</METAR>
</data>
</response>

I created DTO classes:

1) Data class:

    @XmlRootElement(name = "data")
@XmlAccessorType(XmlAccessType.FIELD)
public class Data {

    public Data(){}

    public Data(int numResult, List<Metar> metars) {
        this.numResult = numResult;
        this.metars = metars;
    }

    public int getNumResult() {
        return numResult;
    }

    public void setNumResult(int numResult) {
        this.numResult = numResult;
    }

    public List<Metar> getMetars() {
        return metars;
    }

    public void setMetars(List<Metar> metars) {
        this.metars = metars;
    }

    @XmlAttribute(name="num_results")
    private int numResult;
    @XmlElement(name = "METAR")
    private List<Metar> metars ;
}
    }

2) Metar class:

    @Data
@Builder
@XmlRootElement(name ="METAR")
@XmlAccessorType(XmlAccessType.FIELD)
public class Metar {

    @Tolerate
    public Metar(){

    }

    @XmlElement(name = "raw_text")
    private String rawText;

    @XmlElement(name = "station_id")
    private String stationId;

    @XmlElement(name = "observation_time")
    private String observationTime;

    @XmlElement(name = "latitude")
    private float latitude;

    @XmlElement(name = "longitude")
    private float longitude;

    @XmlElement(name = "temp_c")
    private float tempC;    // in decimal Celcius degrees

    @XmlElement(name = "dewpoint_c")
    private float dewpointC;    // in decimal Celcius degrees

    @XmlElement(name = "wind_dir_degrees")
    private int windDirection;   // Degrees

    @XmlElement(name = "wind_speed_kt")
    private int windSpeed;   // Knots

    @XmlElement(name = "wind_gust_kt")
    private int windGusts;  // Knots

    @XmlElement(name = "visibility_statute_mi")
    private float visibility;   // StatuteMiles

    @XmlElement(name = "altim_in_hg")
    private float altimeter;    // inches of Hg

    @XmlElement(name = "sea_level_pressure_mb")
    private float seaLvlPressure;   // mb

    @XmlElement(name = "quality_control_flags")
    private String qualityControlFlags;

    @XmlElement(name = "wx_string")
    private String wxString;

And so on.. over 30 fields.

And The last one class with JAXB:

    String urlForMetar = StaticValues.MAIN_URL_ADDRESS_FOR_METAR;
    private StringBuilder xmlFile;

    @Override
    public String takeXmlFromApi() throws MalformedURLException, FileNotFoundException {
        String line = null;
        URL url = new URL(urlForMetar);
        HttpURLConnection connection = null;
        try {
            xmlFile = null;
            connection = (HttpURLConnection) url.openConnection();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            xmlFile = new StringBuilder();

            while ((line = bufferedReader.readLine()) != null) {
                xmlFile.append(line).append("\n");
            }

            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return xmlFile.toString();
    }

    @Override
    public void unmarshalFileFromXmlToObject(String xmlFile) throws Exception {


        JAXBContext jaxbContext = JAXBContext.newInstance(Data.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

        StringReader reader = new StringReader(xmlFile);
        Data metarData = (Data) unmarshaller.unmarshal(reader);

        System.out.println(metarData.getMetars().get(0).getStationId());
    }

But I have got that kind of errors:

Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"response"). Expected elements are <{}METAR>,<{}data> at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1131) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3132) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:852) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:214) at com.przemyslawostrouch.parsers.XmlParser.unmarshalFileFromXmlToObject(XmlParser.java:59) at com.przemyslawostrouch.main.WeatherAppApplication.main(WeatherAppApplication.java:24)

What is wrong? I read some articles about object factory class, should it be created? And second question quality control flags field have to be an Array instead of String ? I would like to add that I will not use this data for sure in the future.

<quality_control_flags>
<auto>TRUE</auto>
<auto_station>TRUE</auto_station>
<lightning_sensor_off>TRUE</lightning_sensor_off>
</quality_control_flags>
przemekost
  • 91
  • 2
  • 14
  • You need to add an default constructor (a constructor with no arguments) in the ResponseXml and Metar classes see https://stackoverflow.com/questions/4155361/what-jaxb-needs-a-public-no-arg-constructor-for – Chris Starling Jul 07 '17 at 16:08
  • 1
    Actually your xml have a defined schema in form of an xsd. `http://aviationweather.gov/adds/schema/metar1_2.xsd` So you can use this xsd to genarate the xml mapping classes. Jaxb have a command line tool which can do it. Here is a guide how to use it: https://www.thoughts-on-java.org/generate-your-jaxb-classes-in-second/ – Balázs Nemes Jul 07 '17 at 17:11
  • Also another way to generate class with perfect XML mapping in eclipse has been explained in this thread ->> https://stackoverflow.com/questions/6939299/how-can-i-get-the-eclipse-generatejaxb-classes-option-back – Acewin Jul 07 '17 at 17:20

0 Answers0