private void runSimple() throws SaxonApiException {
    TreeWriter treeWriter = new TreeWriter(runtime);
    treeWriter.startDocument(step.getNode().getBaseURI());
    treeWriter.addStartElement(wrapper);
    treeWriter.startContent();

    while (source.moreDocuments()) {
      XdmNode node = source.read();
      treeWriter.addSubtree(node);
    }

    treeWriter.addEndElement();
    treeWriter.endDocument();

    XdmNode doc = treeWriter.getResult();
    result.write(doc);
  }
  private void runAdjacent() throws SaxonApiException {
    TreeWriter treeWriter = null;
    String last = null;
    boolean open = false;

    int count = 0;
    while (source.moreDocuments()) {
      count++;
      source.read();
    }
    source.resetReader();

    DocumentSequenceIterator xsi = new DocumentSequenceIterator(); // See below
    xsi.setLast(count);

    int pos = 0;
    while (source.moreDocuments()) {
      XdmNode node = source.read();
      pos++;

      Item item = null;

      try {
        XPathCompiler xcomp = runtime.getProcessor().newXPathCompiler();
        xcomp.setBaseURI(step.getNode().getBaseURI());

        for (String prefix : groupAdjacent.getNamespaceBindings().keySet()) {
          xcomp.declareNamespace(prefix, groupAdjacent.getNamespaceBindings().get(prefix));
        }

        XPathExecutable xexec = xcomp.compile(groupAdjacent.getString());

        // From Michael Kay: http://markmail.org/message/vkb2vaq2miylgndu
        //
        // Underneath the s9api XPathExecutable is a net.sf.saxon.sxpath.XPathExpression.

        XPathExpression xexpr = xexec.getUnderlyingExpression();

        // Call createDynamicContext() on this to get an XPathDynamicContext object;

        XPathDynamicContext xdc = xexpr.createDynamicContext(node.getUnderlyingNode());

        // call getXPathContextObject() on that to get the underlying XPathContext.

        XPathContext xc = xdc.getXPathContextObject();

        // Then call XPathContext.setCurrentIterator()
        // to supply a SequenceIterator whose current() and position() methods return
        // the context item and position respectively. If there's any risk that the
        // expression will call the last() method, then it's simplest to make your
        // iterator's getProperties() return LAST_POSITION_FINDER, and implement the
        // LastPositionFinder interface, in which case last() will be implemented by
        // calling the iterator's getLastPosition() method. (Otherwise last() is
        // implemented by calling getAnother() to clone the iterator and calling next()
        // on the clone until the end of the sequence is reached).

        xsi.setPosition(pos);
        xsi.setItem(node.getUnderlyingNode());
        xc.setCurrentIterator(xsi);

        // Then evaluate the expression by calling iterate() on the
        // net.sf.saxon.sxpath.XPathExpression object.

        SequenceIterator results = xexpr.iterate(xdc);
        item = results.next();

        if (item == null) {
          throw new XProcException(
              step.getNode(), "The group-adjacent expression returned nothing.");
        }

        if (results.next() != null) {
          throw new XProcException(
              step.getNode(), "Didn't expect group-adjacent to return a sequence!");
        }
      } catch (XPathException xe) {
        throw new XProcException(xe);
      }

      //
      //  Good luck!
      //

      // FIXME: Compute effective boolean value in a more robust way
      String cur = item.getStringValue();

      if (last != null) {
        if (last.equals(cur)) {
          treeWriter.addSubtree(node);
        } else {
          if (open) {
            open = false;
            treeWriter.addEndElement();
            treeWriter.endDocument();
            result.write(treeWriter.getResult());
          }
        }
      }

      if (last == null || !last.equals(cur)) {
        last = cur;
        open = true;
        treeWriter = new TreeWriter(runtime);
        treeWriter.startDocument(step.getNode().getBaseURI());
        treeWriter.addStartElement(wrapper);
        treeWriter.startContent();
        treeWriter.addSubtree(node);
      }
    }

    if (open) {
      open = false;
      treeWriter.addEndElement();
      treeWriter.endDocument();
      result.write(treeWriter.getResult());
    }
  }