private FSArray addTreebankNodeChildrenToIndexes(
      TreebankNode parent, JCas jCas, List<CoreLabel> tokenAnns, Tree tree) {
    Tree[] childTrees = tree.children();

    // collect all children (except leaves, which are just the words - POS tags are pre-terminals in
    // a Stanford tree)
    List<TreebankNode> childNodes = new ArrayList<TreebankNode>();
    for (Tree child : childTrees) {
      if (!child.isLeaf()) {

        // set node attributes and add children (mutual recursion)
        TreebankNode node = new TreebankNode(jCas);
        node.setParent(parent);
        this.addTreebankNodeToIndexes(node, jCas, child, tokenAnns);
        childNodes.add(node);
      }
    }

    // convert the child list into an FSArray
    FSArray childNodeArray = new FSArray(jCas, childNodes.size());
    for (int i = 0; i < childNodes.size(); ++i) {
      childNodeArray.set(i, childNodes.get(i));
    }
    return childNodeArray;
  }
  private void addTreebankNodeToIndexes(
      TreebankNode node, JCas jCas, Tree tree, List<CoreLabel> tokenAnns) {
    // figure out begin and end character offsets
    CoreMap label = (CoreMap) tree.label();
    CoreMap beginToken = tokenAnns.get(label.get(BeginIndexAnnotation.class));
    CoreMap endToken = tokenAnns.get(label.get(EndIndexAnnotation.class) - 1);
    int nodeBegin = beginToken.get(CharacterOffsetBeginAnnotation.class);
    int nodeEnd = endToken.get(CharacterOffsetEndAnnotation.class);

    // set span, node type, children (mutual recursion), and add it to the JCas
    node.setBegin(nodeBegin);
    node.setEnd(nodeEnd);
    node.setNodeType(tree.value());
    node.setChildren(this.addTreebankNodeChildrenToIndexes(node, jCas, tokenAnns, tree));
    node.setLeaf(node.getChildren().size() == 0);
    node.addToIndexes();
  }