public static void trimBranch(Branch branch) {
    // This does not normalize whitespace!
    // The document tree is modified in place, but no nodes are removed.
    if (trimmed.get(branch) != null) return;
    trimmed.put(branch, branch);
    List content = branch.content();
    // trim leading whitespace
    // NB: dom4j can have multiple consecutive Text nodes
    boolean first = true;
    for (int i = 0, n = content.size(); i < n; i++) {
      Object obj = content.get(i);
      if (obj instanceof Text) {
        Text text = (Text) obj;
        if (first) {
          String s = trimLeading(text.getText());
          text.setText(s);
          if (s.length() > 0)
            first = false;
        }
      } else {
        first = false;
        if (obj instanceof Branch)
          trimBranch((Branch) obj);
      }
    }
    // trim trailing whitespace
    for (int i = content.size()-1; i >= 0; i--) {
      Object obj = content.get(i);
      if (obj instanceof Text) {
        Text text = (Text) obj;
        String s = trimTrailing(text.getText());
        text.setText(s);
        if (s.length() > 0)
          break;
      } else
        break;
    }
  }