All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.nc2.ft.point.writer.FeatureDatasetPointXML Maven / Gradle / Ivy

Go to download

The NetCDF-Java Library is a Java interface to NetCDF files, as well as to many other types of scientific data formats.

The newest version!
/*
 * Copyright (c) 1998 - 2014. University Corporation for Atmospheric Research/Unidata
 * Portions of this software were developed by the Unidata Program at the
 * University Corporation for Atmospheric Research.
 *
 * Access and use of this software shall impose the following obligations
 * and understandings on the user. The user is granted the right, without
 * any fee or cost, to use, copy, modify, alter, enhance and distribute
 * this software, and any derivative works thereof, and its supporting
 * documentation for any purpose whatsoever, provided that this entire
 * notice appears in all copies of the software, derivative works and
 * supporting documentation.  Further, UCAR requests that the user credit
 * UCAR/Unidata in any publications that result from the use of this
 * software or in any product that includes this software. The names UCAR
 * and/or Unidata, however, may not be used in any advertising or publicity
 * to endorse or promote any products or commercial entity unless specific
 * written permission is obtained from UCAR/Unidata. The user also
 * understands that UCAR/Unidata is not obligated to provide the user with
 * any support, consulting, training or assistance of any kind with regard
 * to the use, operation and performance of this software nor to provide
 * the user with any updates, revisions, new versions or "bug fixes."
 *
 * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package ucar.nc2.ft.point.writer;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import ucar.ma2.DataType;
import ucar.nc2.Attribute;
import ucar.nc2.Dimension;
import ucar.nc2.VariableSimpleIF;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants.FeatureType;
import ucar.nc2.ft.*;
import ucar.nc2.ncml.NcMLReader;
import ucar.nc2.ncml.NcMLWriter;
import ucar.nc2.time.CalendarDate;
import ucar.nc2.time.CalendarDateFormatter;
import ucar.nc2.time.CalendarDateRange;
import ucar.nc2.units.DateUnit;
import ucar.unidata.geoloc.LatLonPointImpl;
import ucar.unidata.geoloc.LatLonRect;
import ucar.unidata.geoloc.Station;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

/**
 * generate capabilities XML for a FeatureDatasetPoint / StationTimeSeriesFeatureCollection
 *
 * @author caron
 * @since Aug 19, 2009
 */
public class FeatureDatasetPointXML {
  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FeatureDatasetPointXML.class);

  private FeatureDatasetPoint fdp;
  private String path;
  //private PointFeatureCollection pfc;
  //private NestedPointFeatureCollection pfc;

  public FeatureDatasetPointXML(FeatureDatasetPoint fdp, String path) {
    this.fdp = fdp;
    this.path = path;
  }

  public String getCapabilities() {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    return fmt.outputString(getCapabilitiesDocument());
  }

  public void getCapabilities(OutputStream os) throws IOException {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    fmt.output(getCapabilitiesDocument(), os);
  }

  /*
   * Write stationCollection XML document
   *
  public String writeStationCollectionXML(LatLonRect bb, String[] names) throws IOException {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    return fmt.outputString(makeStationCollectionDocument(bb, names));
  }

  public void writeStationCollectionXML(OutputStream os) throws IOException {
    XMLOutputter fmt = new XMLOutputter(Format.getPrettyFormat());
    fmt.output(makeStationCollectionDocument(), os);
  } */

  /**
   * Create an XML document for the stations in this dataset.
   *
   * @param bb    restrict stations to this bounding box, may be null
   * @param names restrict stations to these names, may be null
   * @return XML document for the stations
   * @throws IOException on read error
   */
  public Document makeStationCollectionDocument(LatLonRect bb, String[] names) throws IOException {

    List list = fdp.getPointFeatureCollectionList();
    FeatureCollection fc = list.get(0);

    if (!(fc instanceof StationTimeSeriesFeatureCollection)) {
      throw new UnsupportedOperationException(fc.getClass().getName() + " not a StationTimeSeriesFeatureCollection");
    }
    StationTimeSeriesFeatureCollection sobs = (StationTimeSeriesFeatureCollection) fc;

    Element rootElem = new Element("stationCollection");
    Document doc = new Document(rootElem);

    List stations;
    if (bb != null)
      stations = sobs.getStations(bb);
    else if (names != null)
      stations = sobs.getStations(Arrays.asList(names));
    else
      stations = sobs.getStations();

    for (Station s : stations) {
      Element sElem = new Element("station");
      sElem.setAttribute("name", s.getName());
      if (s.getWmoId() != null)
        sElem.setAttribute("wmo_id", s.getWmoId());
      if ((s.getDescription() != null) && (s.getDescription().length() > 0))
        sElem.addContent(new Element("description").addContent(s.getDescription()));

      sElem.addContent(new Element("longitude").addContent(Double.toString(s.getLongitude())));
      sElem.addContent(new Element("latitide").addContent(Double.toString(s.getLatitude())));
      if (!Double.isNaN(s.getAltitude()))
        sElem.addContent(new Element("altitude").addContent(Double.toString(s.getAltitude())));
      rootElem.addContent(sElem);
    }

    return doc;
  }

  /**
   * Create the capabilities XML document for this datasets
   *
   * @return capabilities XML document
   */
  public Document getCapabilitiesDocument() {
    Element rootElem = new Element("capabilities");
    Document doc = new Document(rootElem);
    if (null != path) {
      rootElem.setAttribute("location", path);
      Element elem = new Element("featureDataset");
      FeatureType ft = fdp.getFeatureType();
      elem.setAttribute("type", ft.toString().toLowerCase());
      String url = path.replace("dataset.xml", ft.toString().toLowerCase() + ".xml");
      elem.setAttribute("url", url);
      rootElem.addContent(elem);
    }

    //rootElem.addContent(new Element("TimeUnit").addContent(fdp.getTimeUnit()));
    //rootElem.addContent(new Element("AltitudeUnits").addContent(fdp.getAltUnits()));

    // data variables
    List vars = fdp.getDataVariables();
    Collections.sort(vars);
    for (VariableSimpleIF v : vars) {
      rootElem.addContent(writeVariable(v));
    }

    // add lat/lon bounding box
    try {
      fdp.calcBounds();
    } catch (IOException e) {
      //e.printStackTrace();
      log.warn("Unable to compute bounds for dataset " + fdp.getTitle(), e);
    }

    LatLonRect bb = fdp.getBoundingBox();
    if (bb != null)
      rootElem.addContent(writeBoundingBox(bb));

    // add date range
    CalendarDateRange dateRange = fdp.getCalendarDateRange();
    if (dateRange != null) {
      Element drElem = new Element("TimeSpan"); // from KML
      drElem.addContent(new Element("begin").addContent(dateRange.getStart().toString()));
      drElem.addContent(new Element("end").addContent(dateRange.getEnd().toString()));
      if (dateRange.getResolution() != null)
        drElem.addContent(new Element("resolution").addContent(dateRange.getResolution().toString()));

      rootElem.addContent(drElem);
    }

    // add accept list
    Element elem = new Element("AcceptList");
    //elem.addContent(new Element("accept").addContent("raw"));
    elem.addContent(new Element("accept").addContent("csv").setAttribute("displayName", "csv"));
    elem.addContent(new Element("accept").addContent("text/csv").setAttribute("displayName", "csv (file)"));
    elem.addContent(new Element("accept").addContent("xml").setAttribute("displayName", "xml"));
    elem.addContent(new Element("accept").addContent("text/xml").setAttribute("displayName", "xml (file)"));
    elem.addContent(new Element("accept").addContent("waterml2").setAttribute("displayName", "WaterML 2.0"));
    elem.addContent(new Element("accept").addContent("netcdf").setAttribute("displayName", "CF/NetCDF-3"));
    //elem.addContent(new Element("accept").addContent("ncstream"));
    rootElem.addContent(elem);

    return doc;
  }

  private Element writeBoundingBox(LatLonRect bb) {
    Element bbElem = new Element("LatLonBox"); // from KML
    bbElem.addContent(new Element("west").addContent(ucar.unidata.util.Format.dfrac(bb.getLonMin(), 6)));
    bbElem.addContent(new Element("east").addContent(ucar.unidata.util.Format.dfrac(bb.getLonMax(), 6)));
    bbElem.addContent(new Element("south").addContent(ucar.unidata.util.Format.dfrac(bb.getLatMin(), 6)));
    bbElem.addContent(new Element("north").addContent(ucar.unidata.util.Format.dfrac(bb.getLatMax(), 6)));
    return bbElem;
  }

  private Element writeVariable(VariableSimpleIF v) {
    Element varElem = new Element("variable");
    varElem.setAttribute("name", v.getShortName());

    ucar.ma2.DataType dt = v.getDataType();
    if (dt != null)
      varElem.setAttribute("type", dt.toString());

    // attributes
    for (Attribute att : v.getAttributes()) {
      varElem.addContent(NcMLWriter.writeAttribute(att, "attribute", null));
    }

    return varElem;
  }

  /////////////////////////////////////////////
  public static LatLonRect getSpatialExtent(Document doc) throws IOException {
    Element root = doc.getRootElement();
    Element latlonBox = root.getChild("LatLonBox");
    if (latlonBox == null) return null;

    String westS = latlonBox.getChildText("west");
    String eastS = latlonBox.getChildText("east");
    String northS = latlonBox.getChildText("north");
    String southS = latlonBox.getChildText("south");
    if ((westS == null) || (eastS == null) || (northS == null) || (southS == null)) return null;

    try {
      double west = Double.parseDouble(westS);
      double east = Double.parseDouble(eastS);
      double south = Double.parseDouble(southS);
      double north = Double.parseDouble(northS);
      return new LatLonRect(new LatLonPointImpl(south, east), new LatLonPointImpl(north, west));

    } catch (Exception e) {
      return null;
    }
  }

  public static CalendarDateRange getTimeSpan(Document doc) throws IOException {
    Element root = doc.getRootElement();
    Element timeSpan = root.getChild("TimeSpan");
    if (timeSpan == null) return null;

    String beginS = timeSpan.getChildText("begin");
    String endS = timeSpan.getChildText("end");
//    String resS = timeSpan.getChildText("resolution");
    if ((beginS == null) || (endS == null)) return null;

    try {
      CalendarDate start = CalendarDateFormatter.isoStringToCalendarDate(null, beginS);
      CalendarDate end = CalendarDateFormatter.isoStringToCalendarDate(null, endS);
      if ((start == null) || (end == null)) {
        return null;
      }

      CalendarDateRange dr = CalendarDateRange.of(start, end);

      // LOOK if (resS != null)
      //  dr.setResolution(new TimeDuration(resS));

      return dr;

    } catch (Exception e) {
      return null;
    }
  }

  public static DateUnit getTimeUnit(Document doc) throws IOException {
    Element root = doc.getRootElement();
    String timeUnitS = root.getChildText("TimeUnit");
    if (timeUnitS == null) return null;

    try {
      return new DateUnit(timeUnitS);
    } catch (Exception e) {
      log.error("Illegal date unit {}", timeUnitS);
      return null;
    }
  }

  public static String getAltUnits(Document doc) throws IOException {
    Element root = doc.getRootElement();
    return root.getChildText("AltitudeUnits");
  }

  public static List getDataVariables(Document doc) throws IOException {
    Element root = doc.getRootElement();

    List dataVars = new ArrayList<>();
    List varElems = root.getChildren("variable");
    for (Element varElem : varElems) {
      dataVars.add(new VariableSimple(varElem));
    }
    return dataVars;
  }

  private static class VariableSimple implements VariableSimpleIF {
    String name, desc, units;
    DataType dt;
    List atts;

    VariableSimple(Element velem) {
      name = velem.getAttributeValue("name");
      String type = velem.getAttributeValue("type");
      dt = DataType.getType(type);

      atts = new ArrayList<>();
      List attElems = velem.getChildren("attribute");
      for (Element attElem : attElems) {
        String attName = attElem.getAttributeValue("name");
        ucar.ma2.Array values = NcMLReader.readAttributeValues(attElem);
        atts.add(new Attribute(attName, values));
      }

      for (Attribute att : atts) {
        if (att.getShortName().equals(CDM.UNITS))
          units = att.getStringValue();
        if (att.getShortName().equals(CDM.LONG_NAME))
          desc = att.getStringValue();
        if ((desc == null) && att.getShortName().equals("description"))
          desc = att.getStringValue();
        if ((desc == null) && att.getShortName().equals("standard_name"))
          desc = att.getStringValue();
      }
    }

    @Override
    public String getName() {
      return name;
    }

    @Override
    public String getFullName() {
      return name;
    }

    @Override
    public String getShortName() {
      return name;
    }

    @Override
    public String getDescription() {
      return desc;
    }

    @Override
    public String getUnitsString() {
      return units;
    }

    @Override
    public int getRank() {
      return 0;
    }

    @Override
    public int[] getShape() {
      return new int[0];
    }

    @Override
    public List getDimensions() {
      return null;
    }

    @Override
    public DataType getDataType() {
      return dt;
    }

    @Override
    public List getAttributes() {
      return atts;
    }

    @Override
    public Attribute findAttributeIgnoreCase(String name) {
      for (Attribute att : atts) {
        if (att.getShortName().equalsIgnoreCase(name))
          return att;
      }
      return null;
    }

    @Override
    public int compareTo(VariableSimpleIF o) {
      return name.compareTo(o.getShortName()); // ??
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      VariableSimple that = (VariableSimple) o;
      return name.equals(that.name);
    }

    @Override
    public int hashCode() {
      return name.hashCode();
    }
  }

  public static void doOne(String location, String path, String result) throws IOException {
    FeatureDataset fd = FeatureDatasetFactoryManager.open(FeatureType.ANY_POINT, location, null, new Formatter(System.out));
    FeatureDatasetPointXML xml = new FeatureDatasetPointXML((FeatureDatasetPoint) fd, path);
    xml.getCapabilities(System.out);

    File f = new File(result);
    FileOutputStream fos = new FileOutputStream(f);
    xml.getCapabilities(fos);
    fos.close();
    System.out.printf("%s written%n", f.getPath());
  }

  // debug
  public static void main(String args[]) throws IOException {
    /* doOne( "Q:/cdmUnitTest/ft/station/Surface_METAR_20080205_0000.nc",
          "http://motherlode.ucar.edu:9080/thredds/cdmremote/idd/metar/gempak/collection",
          "C:/tmp/stationCapabilities.xml"
    ); */

    doOne("Q:/cdmUnitTest/ft/point/ship/nc/Surface_Buoy_20090920_0000.nc",
            "http://thredds.ucar.edu/thredds/cdmremote/idd/buoy/collection",
            "C:/tmp/pointCapabilities.xml"
    );


    /*
    File f = new File("C:/TEMP/stationCollection.xml");
    FileOutputStream fos = new FileOutputStream(f);
    xml.writeStationCollectionXML(fos);
    fos.close();
    System.out.println(" size xml=" + f.length());
    long s1 = f.length();

    f = new File("C:/TEMP/stationCollection.xml.gzip");
    fos = new FileOutputStream(f);
    GZIPOutputStream zout = new GZIPOutputStream(fos);
    xml.writeStationCollectionXML(zout);
    zout.close();
    double s2 = (double) f.length();
    System.out.printf(" size xml zipped=%d ratio=%f%n", f.length(), s1/s2);  */
  }

}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy