cdm/src/main/java/ucar/nc2/ncml/NcmlConstructor.java
private Variable readVariable(NetcdfFile ncfile, Group g, Structure parentS, Element varElem) {
    String name = varElem.getAttributeValue("name");
    if (name == null) {
      errlog.format("NcML Variable name is required (%s)%n", varElem);
      return null;
    }

    String type = varElem.getAttributeValue("type");
    if (type == null) {
      errlog.format("NcML variable (%s) must have type attribute", name);
      return null;
    }
    DataType dtype = DataType.getType(type);

    String shape = varElem.getAttributeValue("shape");
    if (shape == null)
      shape = ""; // deprecated, prefer explicit ""

    Variable v;

    if (dtype == DataType.STRUCTURE) {
      Structure s = new Structure(ncfile, g, parentS, name);
      s.setDimensions(shape);
      v = s;
      // look for nested variables
      java.util.List<Element> varList = varElem.getChildren("variable", Catalog.ncmlNS);
      for (Element vElem : varList) {
        readVariable(ncfile, g, s, vElem);
      }

    } else if (dtype == DataType.SEQUENCE) {
        Sequence s = new Sequence(ncfile, g, parentS, name);
        v = s;
        // look for nested variables
        java.util.List<Element> varList = varElem.getChildren("variable", Catalog.ncmlNS);
        for (Element vElem : varList) {
          readVariable(ncfile, g, s, vElem);
        }

    } else {
      v = new Variable(ncfile, g, parentS, name, dtype, shape);

      // deal with values
      Element valueElem = varElem.getChild("values", Catalog.ncmlNS);
      if (valueElem != null)
        readValues(v, varElem, valueElem);
      // otherwise has fill values.
    }

    // look for attributes
    java.util.List<Element> attList = varElem.getChildren("attribute", Catalog.ncmlNS);
    for (Element attElem : attList)
      readAtt(v, attElem);

    if (parentS != null)
      parentS.addMemberVariable(v);
    else
      g.addVariable(v);    

    return v;
  }

  private void readValues(Variable v, Element varElem, Element valuesElem) {

    // check if values are specified by start / increment
    String startS = valuesElem.getAttributeValue("start");
    String incrS = valuesElem.getAttributeValue("increment");
    String nptsS = valuesElem.getAttributeValue("npts");
    int npts = (nptsS == null) ? (int) v.getSize() : Integer.parseInt(nptsS);

    // either start, increment are specified
    if ((startS != null) && (incrS != null)) {
      double start = Double.parseDouble(startS);
      double incr = Double.parseDouble(incrS);
      v.setValues(npts, start, incr);
      return;
    }

    // otherwise values are listed in text
    String values = varElem.getChildText("values", Catalog.ncmlNS);
    String sep = valuesElem.getAttributeValue("separator");
    if (sep == null) sep = " ";

    if (v.getDataType() == DataType.CHAR) {
      int nhave = values.length();
      int nwant = (int) v.getSize();
      char[] data = new char[nwant];
      int min = Math.min(nhave, nwant);
      for (int i = 0; i < min; i++) {
        data[i] = values.charAt(i);
      }
      Array dataArray = Array.factory(DataType.CHAR, v.getShape(), data);
      v.setCachedData(dataArray, true);

    } else {
      // or a list of values
      List<String> valList = new ArrayList<>();
      StringTokenizer tokn = new StringTokenizer(values, sep);
      while (tokn.hasMoreTokens())
        valList.add(tokn.nextToken());
      v.setValues(valList);
    }
  }

  private void readAtt(Object parent, Element attElem) {
    String name = attElem.getAttributeValue("name");
    if (name == null) {
      errlog.format("NcML Attribute name is required (%s)%n", attElem);
      return;
    }

    try {
      ucar.ma2.Array values = NcMLReader.readAttributeValues(attElem);
      Attribute att = new ucar.nc2.Attribute(name, values);
      if (parent instanceof Group)
        ((Group) parent).addAttribute(att);
      else if (parent instanceof Variable)
        ((Variable) parent).addAttribute(att);
    } catch (RuntimeException e) {
      errlog.format("NcML new Attribute Exception: %s att=%s in=%s%n", e.getMessage(), name, parent);
    }
  }

  /**
   * Read an NcML dimension element.
   *
   * @param g       put dimension into this group
   * @param dimElem ncml dimension element
   */
  private void readDim(Group g, Element dimElem) {
    String name = dimElem.getAttributeValue("name");
    if (name == null) {
      errlog.format("NcML Dimension name is required (%s)%n", dimElem);
      return;
    }

    String lengthS = dimElem.getAttributeValue("length");
    String isUnlimitedS = dimElem.getAttributeValue("isUnlimited");
    String isSharedS = dimElem.getAttributeValue("isShared");
    String isUnknownS = dimElem.getAttributeValue("isVariableLength");

    boolean isUnlimited = (isUnlimitedS != null) && isUnlimitedS.equalsIgnoreCase("true");
    boolean isUnknown = (isUnknownS != null) && isUnknownS.equalsIgnoreCase("true");
    boolean isShared = true;
    if ((isSharedS != null) && isSharedS.equalsIgnoreCase("false"))
      isShared = false;

    int len = Integer.parseInt(lengthS);
    if ((isUnknownS != null) && isUnknownS.equalsIgnoreCase("false"))
      len = Dimension.VLEN.getLength();

    Dimension dim = new Dimension(name, len, isShared, isUnlimited, isUnknown);

    if (debugConstruct) System.out.println(" add new dim = " + dim);
    g.addDimension(dim);
  }

}
private Variable readVariable(NetcdfFile ncfile, Group g, Structure parentS, Element varElem) {
    String name = varElem.getAttributeValue("name");
    if (name == null) {
      errlog.format("NcML Variable name is required (%s)%n", varElem);
      return null;
    }

    String type = varElem.getAttributeValue("type");
    if (type == null) {
      errlog.format("NcML variable (%s) must have type attribute", name);
      return null;
    }
    DataType dtype = DataType.getType(type);

    String shape = varElem.getAttributeValue("shape");
    if (shape == null)
      shape = ""; // deprecated, prefer explicit ""

    Variable v;

    if (dtype == DataType.STRUCTURE) {
      Structure s = new Structure(ncfile, g, parentS, name);
      s.setDimensions(shape);
      v = s;
      // look for nested variables
      java.util.List<Element> varList = varElem.getChildren("variable", Catalog.ncmlNS);
      for (Element vElem : varList) {
        readVariable(ncfile, g, s, vElem);
      }

    } else if (dtype == DataType.SEQUENCE) {
        Sequence s = new Sequence(ncfile, g, parentS, name);
        v = s;
        // look for nested variables
        java.util.List<Element> varList = varElem.getChildren("variable", Catalog.ncmlNS);
        for (Element vElem : varList) {
          readVariable(ncfile, g, s, vElem);
        }

    } else {
      v = new Variable(ncfile, g, parentS, name, dtype, shape);

      // deal with values
      Element valueElem = varElem.getChild("values", Catalog.ncmlNS);
      if (valueElem != null)
        readValues(v, varElem, valueElem);
      // otherwise has fill values.
    }

    // look for attributes
    java.util.List<Element> attList = varElem.getChildren("attribute", Catalog.ncmlNS);
    for (Element attElem : attList)
      readAtt(v, attElem);

    if (parentS != null)
      parentS.addMemberVariable(v);
    else
      g.addVariable(v);    

    return v;
  }

  private void readValues(Variable v, Element varElem, Element valuesElem) {

    // check if values are specified by start / increment
    String startS = valuesElem.getAttributeValue("start");
    String incrS = valuesElem.getAttributeValue("increment");
    String nptsS = valuesElem.getAttributeValue("npts");
    int npts = (nptsS == null) ? (int) v.getSize() : Integer.parseInt(nptsS);

    // either start, increment are specified
    if ((startS != null) && (incrS != null)) {
      double start = Double.parseDouble(startS);
      double incr = Double.parseDouble(incrS);
      v.setValues(npts, start, incr);
      return;
    }

    // otherwise values are listed in text
    String values = varElem.getChildText("values", Catalog.ncmlNS);
    String sep = valuesElem.getAttributeValue("separator");
    if (sep == null) sep = " ";

    if (v.getDataType() == DataType.CHAR) {
      int nhave = values.length();
      int nwant = (int) v.getSize();
      char[] data = new char[nwant];
      int min = Math.min(nhave, nwant);
      for (int i = 0; i < min; i++) {
        data[i] = values.charAt(i);
      }
      Array dataArray = Array.factory(DataType.CHAR, v.getShape(), data);
      v.setCachedData(dataArray, true);

    } else {
      // or a list of values
      List<String> valList = new ArrayList<>();
      StringTokenizer tokn = new StringTokenizer(values, sep);
      while (tokn.hasMoreTokens())
        valList.add(tokn.nextToken());
      v.setValues(valList);
    }
  }

  private void readAtt(Object parent, Element attElem) {
    String name = attElem.getAttributeValue("name");
    if (name == null) {
      errlog.format("NcML Attribute name is required (%s)%n", attElem);
      return;
    }

    try {
      ucar.ma2.Array values = NcMLReader.readAttributeValues(attElem);
      Attribute att = new ucar.nc2.Attribute(name, values);
      if (parent instanceof Group)
        ((Group) parent).addAttribute(att);
      else if (parent instanceof Variable)
        ((Variable) parent).addAttribute(att);
    } catch (RuntimeException e) {
      errlog.format("NcML new Attribute Exception: %s att=%s in=%s%n", e.getMessage(), name, parent);
    }
  }

  /**
   * Read an NcML dimension element.
   *
   * @param g       put dimension into this group
   * @param dimElem ncml dimension element
   */
  private void readDim(Group g, Element dimElem) {
    String name = dimElem.getAttributeValue("name");
    if (name == null) {
      errlog.format("NcML Dimension name is required (%s)%n", dimElem);
      return;
    }

    String lengthS = dimElem.getAttributeValue("length");
    String isUnlimitedS = dimElem.getAttributeValue("isUnlimited");
    String isSharedS = dimElem.getAttributeValue("isShared");
    String isUnknownS = dimElem.getAttributeValue("isVariableLength");

    boolean isUnlimited = (isUnlimitedS != null) && isUnlimitedS.equalsIgnoreCase("true");
    boolean isUnknown = (isUnknownS != null) && isUnknownS.equalsIgnoreCase("true");
    boolean isShared = true;
    if ((isSharedS != null) && isSharedS.equalsIgnoreCase("false"))
      isShared = false;

    int len = Integer.parseInt(lengthS);
    if ((isUnknownS != null) && isUnknownS.equalsIgnoreCase("false"))
      len = Dimension.VLEN.getLength();

    Dimension dim = new Dimension(name, len, isShared, isUnlimited, isUnknown);

    if (debugConstruct) System.out.println(" add new dim = " + dim);
    g.addDimension(dim);
  }

}
Read a NcML variable element, and nested elements, when it creates a new Variable.

@param ncfile      target dataset
@param g       parent Group
@param parentS parent Structure
@param varElem ncml variable element
@return return new Variable