@Override
 public String resolve(String fieldName, int[] arrayPos)
     throws FieldDoesNotHaveDimensionException, FieldIndexOutOfBoundsException,
         InvalidElementException, IOException {
   String result = null;
   try {
     result = wrapped.resolve(fieldName, arrayPos);
   } catch (FieldIndexOutOfBoundsException ex) {
     if (ex.getDimension() > dimension) {
       fieldResolvedUsingFullArrayPos = true;
     }
     throw ex;
   }
   fieldResolvedUsingFullArrayPos = true;
   return result;
 }
  @Override
  public void resolve(
      DefaultParser parser,
      String parametersString,
      Reader oin,
      Writer out,
      DataFieldResolver dataFieldResolver,
      int[] arrayPositioner)
      throws IOException {

    if (out != null) {
      out.flush();
    }

    String[] endMarkers = {"/loop"};

    if (!(oin instanceof MultiMarkLineNumberReader)) {
      throw new RuntimeException("MultiMarkLineNumberReader required");
    }
    MultiMarkLineNumberReader in = (MultiMarkLineNumberReader) oin;
    in.mark(64000); // this is the maximum codelength in a loop

    int[] newArrayPositioner = new int[arrayPositioner.length + 1]; // add a loop recursion
    for (int i = 0; i < arrayPositioner.length; i++) {
      newArrayPositioner[i] = arrayPositioner[i]; // copy existing values
    }
    newArrayPositioner[newArrayPositioner.length - 1] = 0;

    String[] parameters = parametersString.trim().split(" ");
    boolean sortValues;
    SortedMap<Object, String> sortedMap = null;
    boolean invertSortOrder = false;
    String sortKeyField = null;
    if (parameters[0].equals("sort")) {
      sortValues = true;
      if (parameters[1].equals("desc")) {
        invertSortOrder = true;
      } else {
        if (!parameters[1].equals("asc")) {
          throw new RuntimeException("the keyword sort must be followed by either asc or desc");
        }
      }
      sortedMap = new TreeMap<Object, String>();
      sortKeyField = parameters[2];
    } else {
      sortValues = false;
    }

    while (true) {
      final WrappedDataFieldResolver wrappedDataFieldResolver =
          new WrappedDataFieldResolver(dataFieldResolver, arrayPositioner.length);
      final StringWriter outBuffer = new StringWriter();
      if (out != null) { // parse loop content
        parser.perform(outBuffer, endMarkers, newArrayPositioner, wrappedDataFieldResolver);
      } else { // skip to the end tag
        parser.perform(null, endMarkers, newArrayPositioner, wrappedDataFieldResolver);
      }
      if (out == null) {
        break;
      }
      if (!wrappedDataFieldResolver.isFieldResolvedUsingFullArrayPos()) {
        // none of the fields evaluating to a value used the full length
        // of the array positioner (so incrementing the loop variable
        // wouldn't yield to a different result)
        break;
      } else {
        if (out != null) {
          if (sortValues) {
            Object value = null;
            try {
              value = dataFieldResolver.resolveAsObject(sortKeyField, newArrayPositioner);

            } catch (FieldDoesNotHaveDimensionException ex) {
              log.warn(
                  "the sort-key"
                      + sortKeyField
                      + "doesn't have as many dimensions as loops are nested");
            } catch (FieldIndexOutOfBoundsException ex) {
              log.debug("the sort-key" + sortKeyField + "end before an other field in the loop");
            } catch (InvalidElementException ex) {
              log.warn("the sort-key" + sortKeyField + "is an invalid elemend");
            }
            SortKeyValue sortKeyValue =
                new SortKeyValue(
                    newArrayPositioner[newArrayPositioner.length - 1], value, invertSortOrder);
            sortedMap.put(sortKeyValue, outBuffer.toString());
          } else {
            out.write(outBuffer.toString());
          }
        }
        in.reset(); // reset back to the beginning of the loop
      }
      newArrayPositioner[newArrayPositioner.length - 1]++; // increment loop variable
    }
    in.removeMark(); // recursion ended, remove corresponding mark
    if (sortValues) {
      for (String string : sortedMap.values()) {
        out.write(string);
      }
    }
    return;
  }