You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

package nl.wldelft.timeseriesparsers;

package nl.wldelft.timeseriesparsers;
import nl.wldelft.util.TextUtils;
import nl.wldelft.util.TimeZoneUtils;
import nl.wldelft.util.io.XmlParser;
import nl.wldelft.util.timeseries.DefaultTimeSeriesHeader;
import nl.wldelft.util.timeseries.TimeSeriesContentHandler;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;
/**
 *
 *
 * @autor pelgrim
 * @author ekkelenk
 * Date: 8/9/13
 * Time: 9:35 AM
 * Import of content reviewer.
 */
public class AifsMLTimeSeriesParser implements XmlParser<TimeSeriesContentHandler> {
    private TimeSeriesContentHandler contentHandler = null;
    private XMLStreamReader reader = null;
    private DefaultTimeSeriesHeader header = null;
    //Use for all
    private String title = null;
    private String identifier = null;
    private String sequenceNumber = null;
    @Override
    public void parse(XMLStreamReader reader, String virtualFileName, TimeSeriesContentHandler contentHandler) throws Exception {
        this.reader = reader;
        this.contentHandler = contentHandler;
        header = new DefaultTimeSeriesHeader();
        reader.require(XMLStreamConstants.START_DOCUMENT, null, null);
        reader.nextTag();
        reader.require(XMLStreamConstants.START_ELEMENT, null, "product");
        reader.nextTag();
        //noinspection SpellCheckingInspection
        reader.require(XMLStreamConstants.START_ELEMENT, null, "amoc");
        reader.nextTag();
        reader.require(XMLStreamConstants.START_ELEMENT, null, "source");
        parseIdentifier();
        reader.require(XMLStreamConstants.START_ELEMENT, null, "warning");
        reader.nextTag();
        reader.require(XMLStreamConstants.START_ELEMENT, null, "warning-info");
        parseWarningInfo();
        parseAreas();
    }
    /**
     * filter the warning sequence and warning title text attributes from the text elements.
     * they will be used for all areas.
     *
     * @throws XMLStreamException
     */
    private void parseWarningInfo() throws XMLStreamException {
        do {
            if (!goTo("text")) {
                // no more text areas, return.
                return;
            }
            // we only need the sequence number and the title.
            if (this.sequenceNumber == null || this.title == null) {
                String type = reader.getAttributeValue(null, "type");
                if (TextUtils.equals("warning_sequence", type)) {
                    this.sequenceNumber = reader.getElementText();
                } else if (TextUtils.equals("warning_title_text", type)) {
                    this.title = reader.getElementText();
                }
            }
            if (this.sequenceNumber != null && this.title != null) {
                // we're finished with the text elements, skip to the areas
                goTo("area");
                return;
            }
        } while (reader.hasNext());
    }
    /**
     * Retrieve the identifier from the source element
     *
     * @throws javax.xml.stream.XMLStreamException;
     */
    private void parseIdentifier() throws XMLStreamException {
        goTo("identifier");
        if (TextUtils.equals(reader.getLocalName(), "identifier")) {
            this.identifier = reader.getElementText();
        }
        // only identifier inside the source tag. Jump to warning.
        goTo("warning");
    }
    /**
     * Retrieve the locationId from the forecast element(s) and call separate method to parse forecast data
     *
     * @throws javax.xml.stream.XMLStreamException;
     */
    private void parseAreas() throws XMLStreamException {
        do {
            if (!goTo("area")) {
                return;
            }
            String locationId = reader.getAttributeValue(null, "aac");
            parseForecastData(locationId);
        } while (reader.hasNext());
    }
    /**
     * helper class to store forecast data.
     */
    private static class ForecastData {
        private String parameter = null;
        private String value = null;
        private String unit = null;
        private String localTime = null;
        private String comment = null;
    }
    /**
     * Retrieve the variable, value, unit, time and comment from the forecast data element(s)
     * Retrieve comment text from forecast text element
     *
     * @throws javax.xml.stream.XMLStreamException;
     */
    private void parseForecastData(String locationId) throws XMLStreamException {
        // not every area has a forecast-period.
        if (!goTo("forecast-period")) {
            return;
        }
        // get the start-time-utc
        String externalForecastTime = reader.getAttributeValue(null, "start-time-utc");
        // the sequences are split over different elements. We have to merge them. We'll use a sequence map with String[].
        Map<String, ForecastData> forecastSequenceMap = new LinkedHashMap();
        do {
            if (!goTo("element")) break;
            String sequence = reader.getAttributeValue(null, "sequence");
            ForecastData forecastData = forecastSequenceMap.get(sequence);
            if (forecastData == null)  {
                forecastData = new ForecastData();
                forecastSequenceMap.put(sequence, forecastData);
            }
            String type = reader.getAttributeValue(null, "type");
            String units = reader.getAttributeValue(null, "units");
            // 0 = parameter, 1 = value   2 = unit  3 = local time   4 comment
            if (TextUtils.equals("prediction", type)) {
                // time-local will be set from the prediction element. See comment in [FEWS-11311]
                String timeLocal = reader.getAttributeValue(null, "time-local");
                String value = reader.getElementText();
                forecastData.parameter = "prediction";
                forecastData.localTime = timeLocal;
                forecastData.comment = value;
            } else if (TextUtils.equals("value", type)) {
                forecastData.value = reader.getElementText();
                forecastData.unit = units;
            }
        } while (reader.hasNext());
        //noinspection SpellCheckingInspection
        header.setForecastTime(TimeZoneUtils.GMT, "yyyy-MM-dd'T'HH:mm:ss'Z'", externalForecastTime);
        header.setLocationId(locationId);
        // The forecast sequence map contains a string array with the following elements:
        // 0 = parameter, 1 = value   2 = unit  3 = local time   4 comment
        for (ForecastData forecastData : forecastSequenceMap.values()) {
            contentHandler.setComment(identifier + " #" + sequenceNumber + ": " + title + '\n' + forecastData.comment);
            header.setParameterId(forecastData.parameter);
            contentHandler.setValue('.', forecastData.value);
            header.setUnit(forecastData.unit);
            long rawTimeZoneOffset = TimeZoneUtils.parseRawTimeZoneOffset(forecastData.localTime.substring(forecastData.localTime.length() - 6));
            contentHandler.setTime(TimeZoneUtils.getTimeZone(rawTimeZoneOffset), "yyyy-MM-dd'T'HH:mm:ss", forecastData.localTime.substring(0, forecastData.localTime.length() - 6));
            contentHandler.setTimeSeriesHeader(header);
            contentHandler.applyCurrentFields();
        }
    }
    /**
     * This method skips elements until a start element with the corresponding local name is found and returns true, if not returns false
     * Warning: if the element is not found the reader is skipped until the end of the document
     *
     * @param localName
     * @return boolean
     * @throws XMLStreamException
     */
    private boolean goTo(String localName) throws XMLStreamException {
        do {
            if (!reader.hasNext()) return false;
            reader.next();
        } while (!reader.isStartElement() || !TextUtils.equals(reader.getLocalName(), localName));
        return true;
    }
}

  • No labels