private List<PsiElement> _process(final Matcher matcher, final boolean resolve) {
    final XmlTag root = matcher.getRoot();
    if (root == null || myHistory.contains(root)) {
      return Collections.emptyList();
    }
    myHistory.add(root);
    final List<PsiElement> found = new ArrayList<PsiElement>();

    try {
      if (matcher.isRecursive()) {
        root.accept(
            new XmlRecursiveElementVisitor() {
              @Override
              public void visitXmlTag(XmlTag tag) {
                final Matcher.Result match = matcher.match(tag);
                if (match != null) {
                  if (match.chain != null) {
                    found.addAll(_process(match.chain, resolve));
                  } else {
                    assert match.result != null;
                    found.add(match.result);
                    if (resolve) throw Stop.DONE;
                  }
                }
                super.visitXmlTag(tag);
              }
            });
      } else {
        root.acceptChildren(
            new XmlElementVisitor() {

              @Override
              public void visitXmlTag(XmlTag tag) {
                final Matcher.Result match = matcher.match(tag);
                if (match != null) {
                  if (match.chain != null) {
                    found.addAll(_process(match.chain, resolve));
                  } else {
                    assert match.result != null;
                    found.add(match.result);
                    if (resolve) throw Stop.DONE;
                  }
                }
              }
            });
      }
    } catch (Stop e) {
      /* processing stopped */
    }
    return found;
  }