public FieldName(Node node, XmlQuery xq, CoverageInfo covInfo) throws WCPSException {
    while ((node != null) && node.getNodeName().equals("#" + WcpsConstants.MSG_TEXT)) {
      node = node.getNextSibling();
    }

    if (node == null) {
      throw new WCPSException("FieldNameType parsing error.");
    }

    String nodeName = node.getNodeName();
    log.trace(nodeName);

    if (nodeName.equals(WcpsConstants.MSG_NAME)) {
      this.name = node.getTextContent();
      log.trace("Found field name: " + name);
      String coverageName = covInfo.getCoverageName();
      try {
        covMeta = xq.getMetadataSource().read(coverageName);
      } catch (Exception ex) {
        log.error(ex.getMessage());
        throw new WCPSException(ex.getMessage(), ex);
      }
      try {
        nameIndex = covMeta.getRangeIndexByName(name).toString();
      } catch (PetascopeException ex1) {
        boolean wrongFieldSubset = true;
        log.debug("Range field subset " + name + " does not seem by-label: trying by-index.");

        if (MiscUtil.isInteger(name)) {
          try {
            // range subsetting might have been done via range field /index/ (instead of label):
            // check this is a valid index
            nameIndex = name;
            name = covMeta.getRangeNameByIndex(Integer.parseInt(name));
            wrongFieldSubset = false; // indeed subset was by-index
          } catch (PetascopeException ex2) {
            log.debug("Range field subset " + nameIndex + " is neither a valid index.");
          }
        }
        if (wrongFieldSubset) {
          log.error("Illegal range field selection: " + name);
          throw new WCPSException(ex1.getExceptionCode(), ex1.getExceptionText());
        }
      }
    }
  }
  public CoverageExpr(Node node, XmlQuery xq) throws WCPSException, SecoreException {
    while ((node != null) && node.getNodeName().equals("#" + WcpsConstants.MSG_TEXT)) {
      node = node.getNextSibling();
    }

    if (node == null) {
      throw new WCPSException("CoverageExprType parsing error.");
    }

    String nodeName = node.getNodeName();
    log.trace(nodeName);

    simpleCoverage = false;

    if (nodeName.equals(WcpsConstants.MSG_COVERAGE)) {
      simpleCoverage = true;
      childInfo = node.getFirstChild().getNodeValue();

      if (!xq.isIteratorDefined(childInfo)) {
        throw new WCPSException(WcpsConstants.MSG_ITERATOR + " " + childInfo + " not defined");
      }

      Iterator<String> coverages = xq.getCoverages(childInfo);

      try {
        info = new CoverageInfo(xq.getMetadataSource().read(coverages.next()));

        while (coverages.hasNext()) { // Check if all the coverages are compatible
          CoverageInfo tmp = new CoverageInfo(xq.getMetadataSource().read(coverages.next()));

          if (!tmp.isCompatible(info)) {
            throw new WCPSException("Incompatible coverages within the same iterator.");
          }
        }
      } catch (Exception ex) {
        throw new WCPSException(ex.getMessage(), ex);
      }

      log.trace("Found simple coverage definition: " + childInfo + ", " + info.toString());
    } else if (nodeName.equals(WcpsConstants.MSG_CRS_TRANSFORM)) {
      // TODO: implement CrsTransform class
      child = new CrsTransformCoverageExpr(node, xq);
    } else if (nodeName.equals(WcpsConstants.MSG_SCALE)) {
      child = new ScaleCoverageExpr(node, xq);
    } else if (nodeName.equals(WcpsConstants.MSG_CONSTRUCT)) {
      child = new ConstructCoverageExpr(node.getFirstChild(), xq);
    } else if (nodeName.equals(WcpsConstants.MSG_CONST)) {
      child = new ConstantCoverageExpr(node.getFirstChild(), xq);
    } else if (nodeName.equals(WcpsConstants.MSG_SWITCH)) {
      child = new SwitchExpr(node, xq);
    }
    //        else if (nodeName.equals("variableRef"))
    //        {
    //            child = new VariableReference(node, xq);
    //        }
    else { // Try one of the groups
      child = null;
      String firstMessage = "";

      Node childNode = node;
      while ((childNode != null) && childNode.getNodeName().equals("#" + WcpsConstants.MSG_TEXT)) {
        childNode = childNode.getNextSibling();
      }
      String n = childNode.getNodeName();

      // TODO: not implemented
      //            if (child == null) {
      //                try {
      //                    child = new SetMetadataCoverageExpr(node, xq);
      //                    log.trace("  " + WcpsConstants.MSG_MATCHED_SET_METADATA);
      //                } catch (WCPSException e) {
      //                    child = null;
      //                    exMessage = e.getMessage();
      //                    firstMessage = exMessage;
      //                }
      //            }

      if (child == null) {
        if (n.equals(WcpsConstants.MSG_RANGE_CONSTRUCTOR)
            || UnaryOperationCoverageExpr.NODE_NAMES.contains(n)
            || BinaryOperationCoverageExpr.NODE_NAMES.contains(nodeName)) {
          try {
            child = new InducedOperationCoverageExpr(node, xq);
            log.trace("Matched induced coverage expression operation.");
          } catch (WCPSException e) {
            child = null;
            if (e.getMessage().equals("Method not implemented")) {
              throw e;
            }
          }
        }
      }

      if (child == null) {
        if (SubsetOperationCoverageExpr.NODE_NAMES.contains(n)) {
          try {
            child = new SubsetOperationCoverageExpr(node, xq);
            log.trace("Matched subset operation.");
          } catch (WCPSException e) {
            if (e.getExceptionCode().equals(ExceptionCode.MissingCRS)
                || e.getExceptionCode().equals(ExceptionCode.InvalidSubsetting)) {
              throw (e);
            }
            child = null;
            exMessage = exMessage.equals(firstMessage) ? e.getMessage() : exMessage;
          }
        }
      }

      if (child == null) {
        try {
          child = new ScalarExpr(node, xq);
          this.scalarExpr = true;
          log.trace("Matched scalar expression.");
        } catch (WCPSException e) {
          child = null;
          exMessage = exMessage.equals(firstMessage) ? e.getMessage() : exMessage;
        }
      }
    }

    if (!simpleCoverage && (child == null)) {
      throw new WCPSException(
          "Invalid coverage Expression, next node: " + node.getNodeName() + " - " + exMessage);
    }

    if (info == null) {
      info = new CoverageInfo(((ICoverageInfo) child).getCoverageInfo());
    }

    if (!(child == null)) {
      // Keep child for XML tree crawling
      super.children.add(child);
    }

    // Fetch slices, so that we know which axes should be discarded from the computation
    slices = MiscUtil.childrenOfType(this, SliceCoverageExpr.class);
  }