Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
No Format
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;
    private String externalForecastTime = 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.nextTagparseIdentifier();
        //noinspection SpellCheckingInspectionparseForecastTime();
        reader.require(XMLStreamConstants.START_ELEMENT, null, "amocwarning");
        reader.nextTag();
        reader.require(XMLStreamConstants.START_ELEMENT, null, "sourcewarning-info");
        parseIdentifierparseWarningInfo();
        reader.require(XMLStreamConstants.START_ELEMENT, null, "warning"parseWarningAreas();
    }
    reader.nextTag();/**
     * Retrieve  reader.require(XMLStreamConstants.START_ELEMENT, null, "warning-info");
  the identifier from the source element
      parseWarningInfo();*
     * @throws  parseWarningAreas()XMLStreamException;
    }
    */**
    private *void filterparseIdentifier() thethrows warningXMLStreamException sequence{
 and warning title text attributes from the text elements. goTo("identifier");
        if (TextUtils.equals(reader.getLocalName(), "identifier")) {
     *   they will be used forthis.identifier all= areasreader.getElementText();
     *
   }
  * @throws XMLStreamException}
     /**/
    private void parseWarningInfo() throws XMLStreamException { * Retrieve the identifier from the source element
     *
   do {
 * @throws XMLStreamException;
     */
    private ifvoid (!goTo("text","warning-info"))parseForecastTime() throws XMLStreamException {
        goTo("issue-time-utc");
        // no more text areas, return.if (TextUtils.equals(reader.getLocalName(), "issue-time-utc")) {
            this.externalForecastTime    return= reader.getElementText();
        }
    }
    goTo("warning");
    }

    //**
 we only need the sequence number* filter the warning sequence and thewarning title.
 text attributes from the text elements.
     * they if (this.sequenceNumber == null || this.title == null) {will be used for all areas.
     *
     * @throws XMLStreamException
     */
    Stringprivate typevoid = reader.getAttributeValue(null, "type");
parseWarningInfo() throws XMLStreamException {
        do {
            if (TextUtils.equals!goTo("warning_sequence", typetext","warning-info")) {
                // no more text this.sequenceNumber = reader.getElementText();
areas, return.
                return;
    } else if (TextUtils.equals("warning_title_text", type)) {      }
            // we only need the sequence number and this.title = reader.getElementText();the title.
            if (this.sequenceNumber == null }
    || this.title == null) {
        }
        String type   if (this.sequenceNumber != null && this.title != null) {= reader.getAttributeValue(null, "type");
                // we're finished with the text elements, skip to the areas
if (TextUtils.equals("warning_sequence", type)) {
                    this.sequenceNumber   return;= reader.getElementText();
            }
    } else   } whileif (readerTextUtils.hasNext(equals("warning_title_text", type)); {
      }
    /**
     * Retrieve the identifier from thethis.title source element
= reader.getElementText();
      *
       * @throws javax.xml.stream.XMLStreamException;  }
     */       }
    private  void parseIdentifier() throws XMLStreamException {
  if (this.sequenceNumber != null &&  goTo("identifier");
this.title != null) {
             if (TextUtils.equals(reader.getLocalName(), "identifier")) {
            this.identifier = reader.getElementText();
   // we're finished with the text elements, skip to the areas
             }
   return;
     // only identifier inside the source tag. Jump}
 to warning.
      } while goTo("warning"(reader.hasNext());
    }

    /**
     * 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. @throws 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")) {
        // but stop if not //found, getor thean start-time-utc
    end-tag area has been found.
        String externalForecastTime = reader.getAttributeValue(null, "start-time-utc");while (goTo("forecast-period","area")) {
            // 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'", this.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;
    }
}