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.io.IOException;
import java.util.CollectionArrayList;
import java.util.LinkedHashMapCollection;
import java.util.MapList;

/**
 *
 * @autor pelgrim
 * @author ekkelenk
 * Date: 8/9/13
 * Time: 9:35 AM
 * Import of content reviewer.the warnings from the AifsML format
 */
public class AifsMLTimeSeriesParser implements XmlParser<TimeSeriesContentHandler> {

    public static final String HYFS_MARKER = "[HYFS]";
    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 sequenceNumberexternalForecastTime = null;


    private@Override
 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");
        parseIdentifier();

        parseForecastTime();
        reader.require(XMLStreamConstants.START_ELEMENT, null, if (!XmlStreamReaderUtils.goTo(reader, "warning")); {
        reader.nextTag();
    // There has to  reader.require(XMLStreamConstants.START_ELEMENT, null, "warning-info");be a warning element.
        parseWarningInfo();
    throw new IOException("Input  parseWarningAreas();
    }
    /**file doesn't contain a warning element: " + virtualFileName);
     * Retrieve the identifier}
 from the source element
     *reader.require(XMLStreamConstants.START_ELEMENT, null, "warning");
     *  @throws XMLStreamExceptionreader.nextTag();
     */
    private void parseIdentifier() throws XMLStreamException {reader.require(XMLStreamConstants.START_ELEMENT, null, "warning-info");

        goToparseWarningInfo("identifier");
        if (TextUtils.equals(reader.getLocalName(), "identifier")) {
            this.identifier = reader.getElementText()parseWarningAreas();
        }
    }
    /**
     * Retrieve the identifier from the source element
     *
     * @throws XMLStreamException;
     */
    private void parseForecastTimeparseIdentifier() throws XMLStreamException {
        XmlStreamReaderUtils.goTo("issue-time-utcreader, "identifier");
        if (TextUtils.equals(reader.getLocalName(), "issue-time-utcidentifier")) {
            this.externalForecastTimeidentifier = reader.getElementText();
        }
        goTo("warning");
    }

    /**
     * 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 (!XmlStreamReaderUtils.goTo(reader, "text", "warning-info")) {
                // no more text areas, return.
                return;
            }
            // we only need the sequencethe number andwarning the title.
            if (this.sequenceNumber == null || this.title == null) {
                String type = reader.getAttributeValue(null, "type");
                if (TextUtils.equals("warning_sequencetitle", type)) {
                    this.sequenceNumbertitle = reader.getElementText();
                }
       else if (TextUtils.equals("warning_title_text", type)) {    }
                    if (this.title != reader.getElementText();null) {
                }
            }
// we're finished with the text elements, skip to the areas
              if (this.sequenceNumber != null && this.title != null) {
 return;
            }
        }  // we're finished with the text elements, skip to the areaswhile (reader.hasNext());
    }


    /**
     * Retrieve the locationId from the area element(s) and call separate return;
method to parse forecast data
        }*
     *   } while (reader.hasNext())@throws XMLStreamException;
    }

    /** */
    private *void RetrieveparseWarningAreas() thethrows locationIdXMLStreamException from{
 the area element(s) and call separate method to// parse forecastalle data
areas binnen een warning  *element.
     *   @throwsdo XMLStreamException;{
     */
      private void parseWarningAreas() throws XMLStreamExceptionif (!XmlStreamReaderUtils.goTo(reader, "area", "warning")) {
        // parse alle areas binnen een warning element.
 // alle area's have been processed or doan {
end tag warning has been found.
       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;
  // an area can have      }
            String locationId = reader.getAttributeValue(null, "aac");
            // an area can have more 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 unitlocalTime = null;
        private String localTimecomment = 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 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.
        List<ForecastData> forecastDataList = new ArrayList<>();
        while (XmlStreamReaderUtils.goTo(reader, "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();this.externalForecastTime = reader.getAttributeValue(null, "start-time-utc");
            // inside the forecast-period we need to  process the text elements first.
            do {
                // process all elements until we reach the end tag forecast-period.
                if (!XmlStreamReaderUtils.goTo(reader, "elementtext", "forecast-period")) {
                    // break so we can write this forecast as a timeseries.
                    break;
                }
                String sequence = reader.getAttributeValue(null, "sequencetype");
                if (sequence == null!TextUtils.equals("river_level_prediction", sequence)) {
                    // we only want elementsthe whereriver sequence have been filledlevel prediction.
                    breakcontinue;
                }
                // ForecastDatawe forecastDatafound = forecastSequenceMap.get(sequence);a river_level_prediction.

                ifString (forecastDatavalue == null) {;
                String   comment forecastData = new ForecastData()null;
                String time =  forecastSequenceMap.put(sequence, forecastData);
null;
                String  }riverLevelPredictionText = reader.getElementText();
                Stringint typeindex = readerriverLevelPredictionText.getAttributeValue(null, "type"indexOf(HYFS_MARKER);
                Stringif units(index != reader.getAttributeValue(null, "units");-1) {
                if (TextUtils.equals("prediction", type)) {
 String valueComment = riverLevelPredictionText.substring(index + HYFS_MARKER.length());
               // time-local will be set fromint thesplit prediction= element. See comment in [FEWS-11311]valueComment.indexOf(",");
                    Stringif timeLocal(split != reader.getAttributeValue(null, "time-local");-1) {
                    String    value = readervalueComment.getElementTextsubstring(0, split);
                    forecastData.parameter = "prediction";
  comment = valueComment.substring(split + 1);
              forecastData.localTime = timeLocal;
        time = parseTime();
          forecastData.comment = value;
        }
        } else if (TextUtils.equals("value", type)) {
   }
                if forecastData.value(time != reader.getElementText();
null) {
                    ForecastData forecastData.unit = unitsnew ForecastData();
                }    forecastData.comment = comment;
            } while (reader.hasNext());
      forecastData.localTime = time;
    // All events have been collected
            writeTimeSerie(locationId, forecastSequenceMap.values())forecastData.value = value;
        }
    }
    /**
    forecastData.parameter * Write a time serie header and it's events based on the forecastData.
= "prediction";
                * @param locationId location of the timeserie forecastDataList.add(forecastData);
     * @param externalForecastTime forecast time.
     * @param forecastCollection}
 collection of forecast events.
     */
   } private void writeTimeSerie(String locationId, Collection<ForecastData> forecastCollection) {
while (reader.hasNext());
            //noinspection SpellCheckingInspection
 All events have been collected
            header.setForecastTime(TimeZoneUtils.GMT, "yyyy-MM-dd'T'HH:mm:ss'Z'", this.externalForecastTimewriteTimeSerie(locationId, forecastDataList);
        header.setLocationId(locationId);
}
    }

    private forString parseTime(ForecastData) forecastDatathrows :XMLStreamException forecastCollection) {
        // if we  contentHandler.setComment(identifier + " #" + sequenceNumber + ": " + title + '\n' + forecastData.comment);
   get here, a river_level_prediction was found. No we need to parse all elements until we find the end of the forecast period
         header.setParameterId(forecastData.parameter);do {
            contentHandler.setValue('.', forecastData.value);
            header.setUnit(forecastData.unit);// process all elements until we reach the end tag forecast-period.
            if (!XmlStreamReaderUtils.goTo(reader, "element", "forecast-period")) {
            long   rawTimeZoneOffset = TimeZoneUtils.parseRawTimeZoneOffset(forecastData.localTime.substring(forecastData.localTime.length() - 6));// no element found
            contentHandler.setTime(TimeZoneUtils.getTimeZone(rawTimeZoneOffset), "yyyy-MM-dd'T'HH:mm:ss", forecastData.localTime.substring(0, forecastData.localTime.length() - 6)) return null;
            contentHandler.setTimeSeriesHeader(header);}
            contentHandler.applyCurrentFields();
    String typeAttribute = reader.getAttributeValue(null, "type");
       }
    }
 if (TextUtils.equals("time",  /**typeAttribute)) {
     * This method skips elements until a start element with the correspondingString localtimeString name is found and returns true, if not returns false
= reader.getElementText();
              * Warning: ifint theindex element is not found the reader is skipped until the end of the document
= timeString.indexOf(HYFS_MARKER);
                if *
(index != -1) {
  * @param localName local element name
     * @return boolean return true if the localname wasreturn foundtimeString.
substring(index + HYFS_MARKER.length());
   * @throws XMLStreamException
     */
    private boolean goTo(String localName) throws XMLStreamException {
}
            do {}
        } while   if (!reader.hasNext()) return false;
            reader.next()return null;
    }

    }/**
 while (!reader.isStartElement() || !TextUtils.equals(reader.getLocalName(), localName));
        return true;
    }
 * Write a time serie header and it's events based on the forecastData.
     /**
 @param locationId location of *the Thistimeserie
 method skips elements until a* start@param elementexternalForecastTime with the corresponding local name is found and returns true,forecast time.
     * If@param anforecastCollection endcollection tagof with name endName is found, return falseforecast events.
     */
 Otherwise returns false
 private void writeTimeSerie(String locationId, *Collection<ForecastData> Warning: if the element is not found and the end tag is not found, the reader is skipped until the end of the document
     *
forecastCollection) {
        //noinspection SpellCheckingInspection
        header.setForecastTime(TimeZoneUtils.GMT, "yyyy-MM-dd'T'HH:mm:ss'Z'", this.externalForecastTime);
        header.setLocationId(locationId);
      * @param localNamefor local(ForecastData nameforecastData to: lookforecastCollection) 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.contentHandler.setComment(identifier + ": " + title + '\n' + forecastData.comment);
            header.setParameterId(forecastData.parameter);
     * @throws XMLStreamException
     */
contentHandler.setValue('.', forecastData.value);
     private boolean goTo(String localName, String endName) throws XMLStreamException {// header.setUnit(forecastData.unit);
        do {
   long rawTimeZoneOffset        if (!reader.hasNext()) return false= TimeZoneUtils.parseRawTimeZoneOffset(forecastData.localTime.substring(forecastData.localTime.length() - 6));
            if (reader.isEndElement() && TextUtils.equals(reader.getLocalName(), endName)) return falsecontentHandler.setTime(TimeZoneUtils.getTimeZone(rawTimeZoneOffset), "yyyy-MM-dd'T'HH:mm:ss", forecastData.localTime.substring(0, forecastData.localTime.length() - 6));
            readercontentHandler.nextsetTimeSeriesHeader(header);
        } while (!reader.isStartElement() || !TextUtils.equals(reader.getLocalName(), localName)contentHandler.applyCurrentFields();
        return true;}
    }
}