grib/src/main/java/ucar/nc2/grib/grib2/table/WmoCodeFlagTables.java
private void readGribCodes(Version version) throws IOException {
    String[] elems = version.getElemNames();
    if (elems == null) {
      throw new IllegalStateException("unknown version = " + version);
    }

    try (InputStream ios = WmoCodeFlagTables.class.getResourceAsStream(version.getResourceName())) {
      if (ios == null) {
        logger.error("cant open WmoCodeTable=" + version.getResourceName());
        throw new IOException("cant open WmoCodeTable=" + version.getResourceName());
      }

      org.jdom2.Document doc;
      try {
        SAXBuilder builder = new SAXBuilder();
        doc = builder.build(ios);
      } catch (JDOMException e) {
        throw new IOException(e.getMessage());
      }
      Element root = doc.getRootElement();

      Map<String, WmoTable> map = new HashMap<>();

      List<Element> featList = root.getChildren(elems[0]); // main element
      for (Element elem : featList) {
        String line = elem.getChildTextNormalize("No");
        String tableName = elem.getChildTextNormalize(elems[1]); // Title_en
        Element subtableElem = elem.getChild(elems[2]); // "SubTitle_en"

        TableType type;
        if (tableName.startsWith("Code table 4.1 ")) {
          type = TableType.cat;
        } else if (tableName.startsWith("Code table 4.2 ")) {
          type = TableType.param;
        } else if (tableName.startsWith("Flag")) {
          type = TableType.flag;
        } else if (tableName.startsWith("Code")) {
          type = TableType.code;
        } else {
          logger.warn("Unknown wmo table entry = '%s'", tableName);
          continue;
        }

        if (subtableElem != null) {
          tableName = subtableElem.getTextNormalize();
        }

        TableType finalType = type;
        WmoTable wmoTable = map.computeIfAbsent(tableName, name -> new WmoTable(name, finalType));

        String code = elem.getChildTextNormalize("CodeFlag");
        String value = elem.getChildTextNormalize("Value");    // Flag table only
        String meaning = elem.getChildTextNormalize(elems[3]); // MeaningParameterDescription_en

        Element unitElem = elem.getChild(elems[4]); // "UnitComments_en"
        String unit = (unitElem == null) ? null : unitElem.getTextNormalize();

        Element statusElem = elem.getChild("Status");
        String status = (statusElem == null) ? null : statusElem.getTextNormalize();

        wmoTable.addEntry(line, code, value, meaning, unit, status);
      }
      ios.close();

      this.wmoTables = map.values().stream().sorted().collect(ImmutableList.toImmutableList());
      ImmutableMap.Builder<String, WmoTable> builder = ImmutableMap.builder();
      map.values().forEach(t -> builder.put(t.getId(), t));
      this.wmoTableMap = builder.build();
    }
  }
private void readGribCodes(Version version) throws IOException {
    String[] elems = version.getElemNames();
    if (elems == null) {
      throw new IllegalStateException("unknown version = " + version);
    }

    try (InputStream ios = WmoCodeFlagTables.class.getResourceAsStream(version.getResourceName())) {
      if (ios == null) {
        logger.error("cant open WmoCodeTable=" + version.getResourceName());
        throw new IOException("cant open WmoCodeTable=" + version.getResourceName());
      }

      org.jdom2.Document doc;
      try {
        SAXBuilder builder = new SAXBuilder();
        doc = builder.build(ios);
      } catch (JDOMException e) {
        throw new IOException(e.getMessage());
      }
      Element root = doc.getRootElement();

      Map<String, WmoTable> map = new HashMap<>();

      List<Element> featList = root.getChildren(elems[0]); // main element
      for (Element elem : featList) {
        String line = elem.getChildTextNormalize("No");
        String tableName = elem.getChildTextNormalize(elems[1]); // Title_en
        Element subtableElem = elem.getChild(elems[2]); // "SubTitle_en"

        TableType type;
        if (tableName.startsWith("Code table 4.1 ")) {
          type = TableType.cat;
        } else if (tableName.startsWith("Code table 4.2 ")) {
          type = TableType.param;
        } else if (tableName.startsWith("Flag")) {
          type = TableType.flag;
        } else if (tableName.startsWith("Code")) {
          type = TableType.code;
        } else {
          logger.warn("Unknown wmo table entry = '%s'", tableName);
          continue;
        }

        if (subtableElem != null) {
          tableName = subtableElem.getTextNormalize();
        }

        TableType finalType = type;
        WmoTable wmoTable = map.computeIfAbsent(tableName, name -> new WmoTable(name, finalType));

        String code = elem.getChildTextNormalize("CodeFlag");
        String value = elem.getChildTextNormalize("Value");    // Flag table only
        String meaning = elem.getChildTextNormalize(elems[3]); // MeaningParameterDescription_en

        Element unitElem = elem.getChild(elems[4]); // "UnitComments_en"
        String unit = (unitElem == null) ? null : unitElem.getTextNormalize();

        Element statusElem = elem.getChild("Status");
        String status = (statusElem == null) ? null : statusElem.getTextNormalize();

        wmoTable.addEntry(line, code, value, meaning, unit, status);
      }
      ios.close();

      this.wmoTables = map.values().stream().sorted().collect(ImmutableList.toImmutableList());
      ImmutableMap.Builder<String, WmoTable> builder = ImmutableMap.builder();
      map.values().forEach(t -> builder.put(t.getId(), t));
      this.wmoTableMap = builder.build();
    }
  }
/*
Param Table:
<GRIB2_22_0_0_CodeFlag_exp_en>
<No>524</No>
<Title_en>Code table 4.2 - Parameter number by product discipline and parameter category</Title_en>
<SubTitle_en>Product discipline 0 - Meteorological products, parameter category 1: moisture</SubTitle_en>
<CodeFlag>101</CodeFlag>
<MeaningParameterDescription_en>Specific number concentration of snow</MeaningParameterDescription_en>
<UnitComments_en>kg-1</UnitComments_en>
<ElementDescription_en>Number of particles per unit mass of air</ElementDescription_en>
<Status>Operational</Status>
</GRIB2_22_0_0_CodeFlag_exp_en>

Code Table:
<GRIB2_22_0_0_CodeFlag_exp_en>
<No>2</No>
<Title_en>Code table 0.0 - Discipline of processed data in the GRIB message, number of GRIB Master table</Title_en>
<CodeFlag>1</CodeFlag>
<MeaningParameterDescription_en>Hydrological products</MeaningParameterDescription_en>
<Status>Operational</Status>
</GRIB2_22_0_0_CodeFlag_exp_en>

FlagTable:
<GRIB2_22_0_0_CodeFlag_exp_en>
<No>168</No>
<Title_en>Flag table 3.4 - Scanning mode</Title_en>
<CodeFlag>1</CodeFlag>
<Value>0</Value>
<MeaningParameterDescription_en>Points of first row or column scan in the +i (+x) direction</MeaningParameterDescription_en>
<Status>Operational</Status>
</GRIB2_22_0_0_CodeFlag_exp_en>
<GRIB2_22_0_0_CodeFlag_exp_en>
<No>169</No>
<Title_en>Flag table 3.4 - Scanning mode</Title_en>
<CodeFlag>1</CodeFlag>
<Value>1</Value>
<MeaningParameterDescription_en>Points of first row or column scan in the -i (-x) direction</MeaningParameterDescription_en>
<Status>Operational</Status>
</GRIB2_22_0_0_CodeFlag_exp_en>