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());
    }
  }
  public boolean processStartElement(XdmNode node) {
    // Use a TreeWriter to make the matching node into a proper document
    TreeWriter treeWriter = new TreeWriter(runtime);
    treeWriter.startDocument(node.getBaseURI());
    treeWriter.addSubtree(node);
    treeWriter.endDocument();

    current.resetWriter();
    current.write(treeWriter.getResult());

    finest(step.getNode(), "Viewport copy matching node to " + current);

    sequencePosition++;
    runtime.getXProcData().setIterationPosition(sequencePosition);

    // Calculate all the variables
    inScopeOptions = parent.getInScopeOptions();
    for (Variable var : step.getVariables()) {
      RuntimeValue value = computeValue(var);

      if ("p3".equals(var.getName().getLocalName())) {
        System.err.println("DEBUG ME1: " + value.getString());
      }

      inScopeOptions.put(var.getName(), value);
    }

    try {
      for (XStep step : subpipeline) {
        step.reset();
        step.run();
      }
    } catch (SaxonApiException sae) {
      throw new XProcException(sae);
    }

    try {
      int count = 0;
      for (String port : inputs.keySet()) {
        if (port.startsWith("|")) {
          for (ReadablePipe reader : inputs.get(port)) {
            while (reader.moreDocuments()) {
              count++;

              if (count > 1) {
                XOutput output = getOutput(port.substring(1));
                if (!output.getSequence()) {
                  throw XProcException.dynamicError(7);
                }
              }

              XdmNode doc = reader.read();
              matcher.addSubtree(doc);
            }
            reader.resetReader();
          }
        }
      }
    } catch (SaxonApiException sae) {
      throw new XProcException(sae);
    }

    return false;
  }