Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
No Format
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.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();
        parseAreasparseWarningAreas();
    }
    /**
     * 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
                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 forecastarea element(s) and call separate method to parse forecast data
     *
     * @throws javax.xml.stream.XMLStreamException;
     */
    private void parseAreasparseWarningAreas() throws XMLStreamException {
        do// {
 parse alle areas binnen een warning element.
        do {
            if (!goTo("area","warning")) {
                // return;
            }alle area's have been processed or an end tag warning has been found.
            String locationId = reader.getAttributeValue(null, "aac") return;
            parseForecastData(locationId);
}
            String }locationId while= (reader.hasNext()getAttributeValue(null, "aac");
      }
    /**
  // an area *can helperhave classmore tothat storeone forecastfore-cast dataperiods.
     */
    private static class ForecastData {
 parseForecastData(locationId);
        }  private String parameter = null;
 while (reader.hasNext());
    }
    /**
     * helper privateclass Stringto valuestore =forecast null;data.
     */
    private Stringstatic unitclass =ForecastData null;{
        private String localTimeparameter = 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    if (!goTo("next forecast-period")) {,
        // but stop if return;
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 {
            if (!goTo("element")) break;
  // process all elements until we reach the end tag Stringforecast-period.
 sequence = reader.getAttributeValue(null, "sequence");
            ForecastData forecastData = forecastSequenceMap.get(sequence);if (!goTo("element", "forecast-period")) {
            if (forecastData == null)  {
   // break so we can write this forecast as a timeseries.
    forecastData = new ForecastData();
             break;
   forecastSequenceMap.put(sequence, forecastData);
            }
                String typesequence = reader.getAttributeValue(null, "typesequence");
            String units = reader.getAttributeValue(null, "units");
    if (sequence == null) {
         // 0 = parameter, 1 = value   2 = unit// we 3only =want localelements timewhere sequence have 4been commentfilled.
            if (TextUtils.equals("prediction", type)) {
     break;
           // time-local will be set from}
 the prediction element. See comment in [FEWS-11311]
                String timeLocalForecastData forecastData = readerforecastSequenceMap.getAttributeValue(null, "time-local"get(sequence);
                Stringif value(forecastData == reader.getElementText();
null) {
                    forecastData.parameter = "prediction" new ForecastData();
                forecastData.localTime = timeLocal;
    forecastSequenceMap.put(sequence, forecastData);
                }
  forecastData.comment = value;
            }String elsetype if= (TextUtilsreader.equalsgetAttributeValue("value"null, "type"));
 {
               String forecastData.valueunits = reader.getElementText(getAttributeValue(null, "units");
                forecastData.unit = units;
if (TextUtils.equals("prediction", type)) {
                  }
  // time-local will be set from }the whileprediction (reader.hasNext());element. See comment in [FEWS-11311]
        //noinspection SpellCheckingInspection
        header.setForecastTime(TimeZoneUtils.GMT   String timeLocal = reader.getAttributeValue(null, "yyyy-MM-dd'T'HH:mm:ss'Z'", externalForecastTime);
time-local");
                    String value = headerreader.setLocationIdgetElementText(locationId);
        // The forecast sequence map   contains a string array with theforecastData.parameter following elements:
 = "prediction";
       // 0 = parameter, 1 = value   2 = unit  3forecastData.localTime = local timetimeLocal;
   4 comment
        for (ForecastData forecastData : forecastSequenceMap.values()) {
   forecastData.comment = value;
       contentHandler.setComment(identifier + " #" + sequenceNumber + ": " +} titleelse + '\n' + forecastData.comment);
  if (TextUtils.equals("value", type)) {
          header.setParameterId(forecastData.parameter);
          forecastData.value = contentHandlerreader.setValue('.', forecastData.valuegetElementText();
                    header.setUnit(forecastData.unit) = units;
             long rawTimeZoneOffset = TimeZoneUtils.parseRawTimeZoneOffset(forecastData.localTime.substring(forecastData.localTime.length() - 6));
 }
            } while contentHandler(reader.setTime(TimeZoneUtils.getTimeZone(rawTimeZoneOffset), "yyyy-MM-dd'T'HH:mm:ss", forecastData.localTime.substring(0, forecastData.localTime.length() - 6));
hasNext());
            // All events have  contentHandler.setTimeSeriesHeader(header);
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  contentHandler.applyCurrentFields();false.
     * Otherwise returns }false
    }
 * Warning: if /**
the element is not found *and Thisthe methodend skipstag elementsis untilnot afound, startthe elementreader withis theskipped correspondinguntil localthe nameend isof found and returns true, if not returns falsethe document
     *
     * Warning: if the element 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.
     *
     * @param localName
     * @return boolean @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;
    }
}