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

ucar.nc2.ncml.NcMLWriter 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 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.ncml;

import ucar.ma2.*;
import ucar.nc2.*;
import ucar.nc2.Attribute;
import ucar.nc2.util.URLnaming;
import ucar.nc2.dataset.*;

import thredds.catalog.XMLEntityResolver;
import org.jdom2.*;
import org.jdom2.output.XMLOutputter;
import org.jdom2.output.Format;
import ucar.nc2.util.xml.Parse;

import java.io.*;
import java.util.*;

/**
 * Helper class to write NcML.
 *
 * @author caron
 * @see ucar.nc2.NetcdfFile
 * @see http://www.unidata.ucar.edu/software/netcdf/ncml/
 */

public class NcMLWriter {
  protected static final Namespace ncNS = Namespace.getNamespace(XMLEntityResolver.NJ22_NAMESPACE);
  protected static final Namespace xsiNS = Namespace.getNamespace("xsi", XMLEntityResolver.W3C_XML_NAMESPACE);

  static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NcMLWriter.class);

  private NetcdfDataset ncd;
  private XMLOutputter fmt;
  private Variable aggCoord;

  /**
   * Write NcML from specified NetcdfFile to a String.
   *
   * @param ncfile      NcML for this NetcdfFile
   * @return the NcML in a String
   * @throws IOException on io error
   */
  public String writeXML(NetcdfFile ncfile) throws IOException {
    if (ncfile instanceof NetcdfDataset)
      ncd = (NetcdfDataset) ncfile;
    else
      ncd = new NetcdfDataset(ncfile, false);

    // Output the document, use standard formatter
    //fmt = new XMLOutputter("  ", true);
    //fmt.setLineSeparator("\n");
    fmt = new XMLOutputter(Format.getPrettyFormat());
    return fmt.outputString(makeDocument( null));
  }

  public String writeXML(Variable v) throws IOException {

    // Output the document, use standard formatter
    //fmt = new XMLOutputter("  ", true);
    //fmt.setLineSeparator("\n");
    fmt = new XMLOutputter(Format.getPrettyFormat());
    return fmt.outputString(makeDocument( null));
  }

  /**
   * Write a NetcdfFile as an XML document to the specified file.
   *
   * @param ncfile      NcML for this NetcdfFile
   * @param filenameOut write NcML to this location
   * @throws IOException on io error
   */
  public void writeXML(NetcdfFile ncfile, String filenameOut) throws IOException {
    OutputStream out = new BufferedOutputStream(new FileOutputStream(filenameOut, false));
    writeXML(ncfile, out, null);
    out.close();
  }

  /**
   * Write a NetcdfFile as an XML document to the specified stream.
   *
   * @param ncfile   NcML for this NetcdfFile
   * @param os       write to this OutputStream
   * @param location normally null, meaning use ncd.getLocation(); otherwise put this into the NcML location
   * @throws IOException on io error
   */
  public void writeXML(NetcdfFile ncfile, OutputStream os, String location) throws IOException {

    if (ncfile instanceof NetcdfDataset)
      ncd = (NetcdfDataset) ncfile;
    else
      ncd = new NetcdfDataset(ncfile, false);

    fmt = new XMLOutputter(Format.getPrettyFormat());
    fmt.output(makeDocument(location), os);
  }

  public void writeXMLexplicit(NetcdfFile ncfile, OutputStream os, String location) throws IOException {
    if (ncfile instanceof NetcdfDataset)
      ncd = (NetcdfDataset) ncfile;
    else
      ncd = new NetcdfDataset(ncfile, false);

    fmt = new XMLOutputter(Format.getPrettyFormat());
    Document doc = makeDocument(location);
    Element root = doc.getRootElement();
    root.addContent( new Element("explicit", ncNS));
    fmt.output(doc, os);
  }


  private Document makeDocument(String location) throws IOException {
    Element rootElem = new Element("netcdf", ncNS);
    Document doc = new Document(rootElem);

    // namespaces
    rootElem.addNamespaceDeclaration(ncNS);
    /* rootElem.addNamespaceDeclaration(xsiNS);

    if (ncfile instanceof NetcdfDataset)
      rootElem.setAttribute("schemaLocation",
        "http://www.ucar.edu/schemas/netcdf-2.2 http://www.unidata.ucar.edu/schemas/netcdfCS-2.2.xsd", xsiNS);
    else
      rootElem.setAttribute("schemaLocation",
        "http://www.ucar.edu/schemas/netcdf-2.2 http://www.unidata.ucar.edu/schemas/netcdf-2.2.xsd", xsiNS);
    */

    if (null == location)
      location = ncd.getLocation();

    if (null != location) {
      rootElem.setAttribute("location", URLnaming.canonicalizeWrite(location));
    }

    if (null != ncd.getId())
      rootElem.setAttribute("id", ncd.getId());

    if (null != ncd.getTitle())
      rootElem.setAttribute("title", ncd.getTitle());

    //if (ncd.getEnhanceMode() != NetcdfDataset.EnhanceMode.None)
    //  rootElem.setAttribute("enhance", ncd.getEnhanceMode().toString());

    Aggregation agg = ncd.getAggregation();
    if (agg != null) {
      String aggDimensionName = agg.getDimensionName();
      aggCoord = ncd.findVariable(aggDimensionName);
      //System.out.println("isMetadata="+aggCoord.isMetadata());
    }

    Group rootGroup = ncd.getRootGroup();

    /* if (ncd.getCoordSysWereAdded()) {
      String conv = ncd.findAttValueIgnoreCase(null, "Conventions", null);
      if (conv == null)
        rootGroup.addAttribute(new Attribute("Conventions", _Coordinate.Convention));
      else
        rootGroup.addAttribute(new Attribute("Conventions", conv + ", " + _Coordinate.Convention));
    } */

    writeGroup(rootElem, rootGroup);

    //if (agg != null) { LOOK ncml3
    //  rootElem.addContent(writeAggregation(agg));
    //}

    return doc;
  }

  /* private Element writeAggregation(AggregationIF agg) throws IOException {
    Element aggElem = new Element("aggregation", ncNS);
    Aggregation.Type type = agg.getType();
    aggElem.setAttribute("type", type.toString());

    String dimName = agg.getDimensionName();
    if (dimName != null)
      aggElem.setAttribute("dimName", dimName);

    List varList = agg.getVariables();
    for (String s : varList) {
      Element e = new Element("variableAgg", ncNS);
      e.setAttribute("name", s);
      aggElem.addContent(e);
    }

    List dsList = agg.getNestedDatasets();
    for (Aggregation.Dataset ds : dsList) {
      Element e = new Element("netcdf", ncNS);
      e.setAttribute("location", ds.getLocation());
      //if (type == Aggregation.Type.JOIN_EXISTING)
      e.setAttribute("ncoords", Integer.toString(ds.getNcoords(null)));
      if (null != ds.getCoordValueString())
        e.setAttribute("coordValue", ds.getCoordValueString());
      aggElem.addContent(e);
    }

    if (agg.getType() == Aggregation.Type.UNION) {
      List unionList = ((AggregationUnion) agg).getUnionDatasets();
      for (NetcdfDataset ds : unionList) {
        Element e = new Element("netcdf", ncNS);
        e.setAttribute("location", ds.getLocation());
        aggElem.addContent(e);
      }
    }

    return aggElem;
  } LOOK ncml3 */

  public static Element writeAttribute(ucar.nc2.Attribute att, String elementName, Namespace ns) {
    Element attElem = new Element(elementName, ns);
    attElem.setAttribute("name", att.getShortName());

    DataType dt = att.getDataType();
    if ((dt != null) && (dt != DataType.STRING))
      attElem.setAttribute("type", dt.toString());

    if (att.getLength() == 0) {
      if (att.isUnsigned())
        attElem.setAttribute("isUnsigned", "true");
      return attElem;
    }

    if (att.isString()) {
      StringBuilder buff = new StringBuilder();
      for (int i = 0; i < att.getLength(); i++) {
        String sval = att.getStringValue(i);
        if (i > 0) buff.append(",");
        buff.append(sval);
      }
      attElem.setAttribute("value", Parse.cleanCharacterData(buff.toString()));
      if (att.getLength() > 1)
        attElem.setAttribute("separator", ",");

    } else {
      StringBuilder buff = new StringBuilder();
      for (int i = 0; i < att.getLength(); i++) {
        Number val = att.getNumericValue(i);
        if (i > 0) buff.append(" ");
        buff.append(val.toString());
      }
      attElem.setAttribute("value", buff.toString());

      if (att.isUnsigned())
        attElem.setAttribute("isUnsigned", "true");
    }
    return attElem;
  }

  // shared dimensions
  public static Element writeDimension(Dimension dim, Namespace ns) {
    Element dimElem = new Element("dimension", ns);
    dimElem.setAttribute("name", dim.getShortName());
    if (dim.isVariableLength())
      dimElem.setAttribute("length", "*");
    else
      dimElem.setAttribute("length", Integer.toString(dim.getLength()));

    if (dim.isUnlimited())
      dimElem.setAttribute("isUnlimited", "true");
    if (dim.isVariableLength())
      dimElem.setAttribute("isVariableLength", "true");

    return dimElem;
  }

     // enum Typedef
  public static Element writeEnumTypedef(EnumTypedef etd, Namespace ns) {
    Element typeElem = new Element("enumTypedef", ns);
    typeElem.setAttribute("name", etd.getShortName());
    typeElem.setAttribute("type", etd.getBaseType().toString());
    Map map = etd.getMap();
    for (Map.Entry entry : map.entrySet()) {
      typeElem.addContent(new Element("enum", ns)
              .setAttribute("key", Integer.toString(entry.getKey()))
              .addContent(entry.getValue()));
    }

    return typeElem;
  }

  private Element writeGroup(Element elem, Group group) {

    // enumTypeDef
    for (EnumTypedef etd : group.getEnumTypedefs()) {
      elem.addContent(writeEnumTypedef(etd, ncNS));
    }

    // dimensions
    for (Dimension dim : group.getDimensions()) {
      elem.addContent(writeDimension(dim, ncNS));
    }

    // attributes
    for (Attribute att : group.getAttributes()) {
      elem.addContent(writeAttribute(att, "attribute", ncNS));
    }

    /* if (addCoords) {
         // coordinate axes
      Iterator vars = group.getVariables().iterator();
      while ( vars.hasNext()) {
        VariableEnhanced var = (VariableEnhanced) vars.next();
        if (var instanceof CoordinateAxis)
          elem.addContent( makeCoordinateAxis( (CoordinateAxis) var));
      }
    } */

    // regular variables
    for (Variable var : group.getVariables()) {
      try {
        elem.addContent(writeVariable((VariableEnhanced) var));
      } catch (ClassCastException e) {
        log.error("var not instanceof VariableEnhanced = " + var.getFullName(), e);
      }
    }

    // nested groups
    for (Group g : group.getGroups()) {
      Element groupElem = new Element("group", ncNS);
      groupElem.setAttribute("name", g.getShortName());
      elem.addContent(writeGroup(groupElem, g));
    }

    return elem;
  }

  /* private Element makeParameter( ucar.unidata.util.Parameter p, String elementName) {
    Element attElem = new Element(elementName, ncNS);
    attElem.setAttribute("name", p.getName());
    attElem.setAttribute("type", p.isString() ? "String" : "double");

    if (p.isString()) {
      String value = p.getStringValue();
      String err = org.jdom.Verifier.checkCharacterData(value);
      if (err != null) {
        value = "NcMLWriter invalid attribute value, err= "+err;
        System.out.println(value);
      }
      attElem.setAttribute("value", value);
    } else {

      StringBuilder buff = new StringBuilder();
      for (int i=0; i 0) buff.append( " ");
        buff.append( val);
      }
      attElem.setAttribute("value", buff.toString());
    }
    return attElem;
  } */

  /* private Element makeReferenceSys( ReferenceSystem referenceSystem) {
   Element elem = new Element("referenceCoordinateSystem", ncNS);
   elem.setAttribute("name", referenceSystem.getName());
   elem.setAttribute("authority", referenceSystem.getAuthority());
   if (referenceSystem.getReferenceType() != null)
     elem.setAttribute("type", referenceSystem.getReferenceType().toString());

   ArrayList params = referenceSystem.getParameters();
   for (int i=0; i 0) buff.append(" ");
      if (dim.isShared())
        buff.append(dim.getShortName());
      else if (dim.isVariableLength())
        buff.append("*");
      else
        buff.append(dim.getLength());
    }
    //if (buff.length() > 0)
    varElem.setAttribute("shape", buff.toString());

    DataType dt = var.getDataType();
    if (dt != null) {
      varElem.setAttribute("type", dt.toString());
      if (dt.isEnum())
        varElem.setAttribute("typedef", var.getEnumTypedef().getShortName());
    }


    // attributes
    for (Attribute att : var.getAttributes()) {
      varElem.addContent(writeAttribute(att, "attribute", ncNS));
    }

    if (var.isMetadata() || (var == aggCoord))
      varElem.addContent(writeValues(var, ncNS, true));

    if (isStructure) {
      Structure s = (Structure) var;
      for (Variable variable : s.getVariables()) {
        VariableEnhanced nestedV = (VariableEnhanced) variable;
        varElem.addContent(writeVariable(nestedV));
      }
    }

    return varElem;
  }

  /* private Element makeCoordinateAxis( CoordinateAxis var) {
   var.addAttribute( new Attribute(CDM.UNITS, var.getUnitsString()));
   if (var.getAxisType() != null)
     var.addAttribute( new Attribute(_Coordinate.AxisType", var.getAxisType().toString()));
   if (var.getPositive() != null)
     var.addAttribute( new Attribute(_Coordinate.ZisPositive", var.getPositive()));

   return makeVariable(var);
 } */

  public static Element writeValues(VariableEnhanced v, Namespace ns, boolean allowRegular) {
    Element elem = new Element("values", ns);

    StringBuilder buff = new StringBuilder();
    Array a;
    try {
      a = v.read();
    } catch (IOException ioe) {
      return elem;
    }

    if (v.getDataType() == DataType.CHAR) {
      char[] data = (char[]) a.getStorage();
      elem.setText(new String(data));

    } else if (v.getDataType() == DataType.STRING) { // use seperate elements??
      IndexIterator iter = a.getIndexIterator();
      int count = 0;
      while (iter.hasNext()) {
        String s = (String) iter.getObjectNext();
        if (count++ > 0) buff.append(" ");
        buff.append("\"").append(s).append("\"");
      }
      elem.setText(buff.toString());

    } else {
      //check to see if regular
      if (allowRegular && (a.getRank() == 1) && (a.getSize() > 2)) {
        Index ima = a.getIndex();
        double start = a.getDouble(ima.set(0));
        double incr = a.getDouble(ima.set(1)) - start;
        boolean isRegular = true;
        for (int i = 2; i < a.getSize(); i++) {
          double v1 = a.getDouble(ima.set(i));
          double v0 = a.getDouble(ima.set(i - 1));
          if (!ucar.nc2.util.Misc.closeEnough(v1 - v0, incr))
            isRegular = false;
        }

        if (isRegular) {
          elem.setAttribute("start", Double.toString(start));
          elem.setAttribute("increment", Double.toString(incr));
          elem.setAttribute("npts", Long.toString(v.getSize()));
          return elem;
        }
      }

      // not regular
      boolean isRealType = (v.getDataType() == DataType.DOUBLE) || (v.getDataType() == DataType.FLOAT);
      IndexIterator iter = a.getIndexIterator();
      buff.append(isRealType ? iter.getDoubleNext() : iter.getIntNext());
      while (iter.hasNext()) {
        buff.append(" ");
        buff.append(isRealType ? iter.getDoubleNext() : iter.getIntNext());
      }
      elem.setText(buff.toString());

    } // not string

    return elem;
  }

  public static void main(String arg[]) {
    //String urls = "C:/data/conventions/coards/cldc.mean.nc";
    String test = "http://testbedapps.sura.org/thredds/dodsC/shelf_hypoxia_scan/noaa/NGOM/GOMUD-2009.3.182.3D.nc";
    String urls = (arg.length == 0) ? test : arg[0];

    try {
      NetcdfDataset df = NetcdfDataset.openDataset(urls);
      NcMLWriter writer = new NcMLWriter();
      System.out.println("NetcdfDataset = " + urls + "\n" + df);
      System.out.println("-----------");
      writer.writeXML(df, System.out, null);
    } catch (Exception ioe) {
      System.out.println("error = " + urls);
      ioe.printStackTrace();
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy