public ExtendCoverageExpr(Node node, XmlQuery xq) throws WCPSException {

    log.trace(node.getNodeName());

    Node child;
    String nodeName;

    axisList = new ArrayList<DimensionIntervalElement>();

    child = node.getFirstChild();
    while (child != null) {
      nodeName = child.getNodeName();

      if (nodeName.equals("#" + WCPSConstants.MSG_TEXT)) {
        child = child.getNextSibling();
        continue;
      }

      try {
        coverageExprType = new CoverageExpr(child, xq);
        coverageInfo = coverageExprType.getCoverageInfo();
        super.children.add(coverageExprType);
        child = child.getNextSibling();
        continue;
      } catch (WCPSException e) {
      }

      try {
        // Start a new axis and save it
        elem = new DimensionIntervalElement(child, xq, coverageInfo);
        log.trace("  " + WCPSConstants.MSG_ADD_NEW_AXIS + ": " + elem.getAxisName());
        axisList.add(elem);
        super.children.add(elem);
        child = elem.getNextNode();
        continue;
      } catch (WCPSException e) {
        log.error(WCPSConstants.ERRTXT_THIS_WAS_NO_DIM + ": " + child.getNodeName());
      }

      // else unknown element
      throw new WCPSException(
          WCPSConstants.ERRTXT_UNKNOWN_NODE_EXTENDCOVERAGE + child.getNodeName());
    }

    dims = coverageInfo.getNumDimensions();
    log.trace("  " + WCPSConstants.MSG_NUMBER_OF_DIMENSIONS + ": " + dims);
    dim = new String[dims];

    for (int j = 0; j < dims; ++j) {
      dim[j] = "*:*";
    }

    Iterator<DimensionIntervalElement> i = axisList.iterator();
    DimensionIntervalElement axis;
    int axisId;
    int axisLo, axisHi;
    int order = 0;

    while (i.hasNext()) {
      axis = i.next();
      axisId = coverageInfo.getDomainIndexByName(axis.getAxisName());
      log.trace("  " + WCPSConstants.MSG_AXIS + " " + WCPSConstants.MSG_ID + ": " + axisId);
      log.trace(
          "  " + WCPSConstants.MSG_AXIS + " " + WCPSConstants.MSG_NAME + ": " + axis.getAxisName());
      log.trace("  " + WCPSConstants.MSG_AXIS + " " + WCPSConstants.MSG_COORDS + ": ");

      axisLo = Integer.parseInt(axis.getLowCoord());
      axisHi = Integer.parseInt(axis.getHighCoord());
      dim[axisId] = axisLo + ":" + axisHi;
      coverageInfo.setCellDimension(
          axisId,
          new CellDomainElement(
              BigInteger.valueOf(axisLo), BigInteger.valueOf(axisHi), axis.getAxisName(), order));
      order += 1;
    }
  }
  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);
  }