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

Compare with Current View Page History

« Previous Version 4 Next »

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.Collection;
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();
        parseWarningAreas();
    }
    /**
     * 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","warning-info")) {
                // 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
                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 area element(s) and call separate method to parse forecast data
     *
     * @throws javax.xml.stream.XMLStreamException;
     */
    private void parseWarningAreas() throws XMLStreamException {
        // parse alle areas binnen een warning element.
        do {
            if (!goTo("area","warning")) {
                // alle area's have been processed or an end tag warning has been found.
                return;
            }
            String locationId = reader.getAttributeValue(null, "aac");
            // an area can have more that one fore-cast periods.
            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
     * return true if more forecast periods are available
     *
     * @throws javax.xml.stream.XMLStreamException;
     */
    private void parseForecastData(String locationId) throws XMLStreamException {
        // not every area has a forecast-period. Try to find the next forecast-period,
        // but stop if not found, or an end-tag area has been found.
        while (goTo("forecast-period","area")) {
            // 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 {
                // process all elements until we reach the end tag forecast-period.
                if (!goTo("element", "forecast-period")) {
                    // break so we can write this forecast as a timeseries.
                    break;
                }
                String sequence = reader.getAttributeValue(null, "sequence");
                if (sequence == null) {
                    // we only want elements where sequence have been filled.
                    break;
                }
                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");
                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());
            // All events have been collected
            writeTimeSerie(locationId, externalForecastTime, forecastSequenceMap.values());
        }
    }
    /**
     * Write a time serie header and it's events based on the forecastData.
     * @param locationId location of the timeserie
     * @param externalForecastTime forecast time.
     * @param forecastCollection collection of forecast events.
     */
    private void writeTimeSerie(String locationId, String externalForecastTime, Collection<ForecastData> forecastCollection) {
        //noinspection SpellCheckingInspection
        header.setForecastTime(TimeZoneUtils.GMT, "yyyy-MM-dd'T'HH:mm:ss'Z'", externalForecastTime);
        header.setLocationId(locationId);
        for (ForecastData forecastData : forecastCollection) {
            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 local element name
     * @return boolean return true if the localname was found.
     * @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;
    }
    /**
     * This method skips elements until a start element with the corresponding local name is found and returns true,
     * If an end tag with name endName is found, return false.
     * Otherwise returns false
     * Warning: if the element is not found and the end tag is not found, the reader is skipped until the end of the document
     *
     * @param localName local name to look for
     * @param endName local name of end tag to find.
     * @return boolean return true if localName cannot be found or the endName end tag has been found.
     * @throws XMLStreamException
     */
    private boolean goTo(String localName, String endName) throws XMLStreamException {
        do {
            if (!reader.hasNext()) return false;
            if (reader.isEndElement() && TextUtils.equals(reader.getLocalName(), endName)) return false;
            reader.next();
        } while (!reader.isStartElement() || !TextUtils.equals(reader.getLocalName(), localName));
        return true;
    }
}
 
  • No labels