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);
  }

}
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
Read a NcML variable element and nested elements when it creates a new Variable .