/** Allocate a Comparator to perform the comparisons described by this sort key component */
  public Comparator makeComparator(XPathContext context) throws XPathException {

    String orderX = order.evaluateAsString(context);

    final Configuration config = context.getConfiguration();
    final TypeHierarchy th = config.getTypeHierarchy();

    Comparator comp;
    if (collation != null) {
      comp = collation;
    } else if (collationName != null) {
      String cname = collationName.evaluateAsString(context);
      URI collationURI;
      try {
        collationURI = new URI(cname);
        if (!collationURI.isAbsolute()) {
          if (baseURI == null) {
            throw new DynamicError("Collation URI is relative, and base URI is unknown");
          } else {
            URI base = new URI(baseURI);
            collationURI = base.resolve(collationURI);
          }
        }
      } catch (URISyntaxException err) {
        throw new DynamicError("Collation name " + cname + " is not a valid URI: " + err);
      }
      try {
        comp = context.getCollation(collationURI.toString());
      } catch (XPathException e) {
        if ("FOCH0002".equals(e.getErrorCodeLocalPart())) {
          e.setErrorCode("XTDE1035");
        }
        throw e;
      }
    } else {
      String caseOrderX = caseOrder.evaluateAsString(context);
      String languageX = language.evaluateAsString(context);
      Properties props = new Properties();
      if (!languageX.equals("")) {
        props.setProperty("lang", languageX);
      }
      if (!caseOrderX.equals("#default")) {
        props.setProperty("case-order", caseOrderX);
      }
      comp = config.getPlatform().makeCollation(config, props);
    }

    if (dataTypeExpression == null) {
      int type = sortKey.getItemType(th).getAtomizedItemType().getPrimitiveType();
      comp = AtomicSortComparer.makeSortComparer(comp, type, context);
      if (!emptyLeast) {
        comp = new EmptyGreatestComparer((AtomicComparer) comp);
      }
    } else {
      String dataType = dataTypeExpression.evaluateAsString(context);
      if (dataType.equals("text")) {
        comp = new TextComparer(comp);
      } else if (dataType.equals("number")) {
        comp = NumericComparer.getInstance();
      } else {
        DynamicError err = new DynamicError("data-type on xsl:sort must be 'text' or 'number'");
        err.setErrorCode("XTDE0030");
        throw err;
      }
    }

    if (stable != null) {
      StringValue stableVal = (StringValue) stable.evaluateItem(context);
      String s = stableVal.getStringValue().trim();
      if (s.equals("yes") || s.equals("no")) {
        // no action
      } else {
        DynamicError err = new DynamicError("Value of 'stable' on xsl:sort must be 'yes' or 'no'");
        err.setErrorCode("XTDE0030");
        throw err;
      }
    }

    if (orderX.equals("ascending")) {
      return comp;
    } else if (orderX.equals("descending")) {
      return new DescendingComparer(comp);
    } else {
      DynamicError err1 = new DynamicError("order must be 'ascending' or 'descending'");
      err1.setErrorCode("XTDE0030");
      throw err1;
    }
  }