I\'ve been playing around with natural language parse trees and manipulating them in various ways. I\'ve been using Stanford\'s Tregex and Tsurgeon tools but the code is a mess
This is a typical case of using Lisp. You would need a function that maps another function over the tree.
Here is a procedural matching example using Common Lisp. There are matchers in Lisp that work over list structures, which could be used instead. Using a list matcher would simplify the example (see my other answer for an example using a pattern matcher).
The code:
(defun node-children (node)
(rest node))
(defun node-name (node)
(second node))
(defun node-type (node)
(first node))
(defun treemap (tree matcher transformer)
(cond ((null tree) nil)
((consp tree)
(if (funcall matcher tree)
(funcall transformer tree)
(cons (node-type tree)
(mapcar (lambda (child)
(treemap child matcher transformer))
(node-children tree)))))
(t tree))))
The example:
(defvar *tree*
'(ROOT
(S
(NP
(NP (NNP Bank))
(PP (IN of)
(NP (NNP America))))
(VP (VBD used)
(S
(VP (TO to)
(VP (VB be)
(VP (VBN called)
(NP
(NP (NNP Bank))
(PP (IN of)
(NP (NNP Italy))))))))))))
(defun example ()
(pprint
(treemap *tree*
(lambda (node)
(and (= (length (node-children node)) 2)
(eq (node-type (first (node-children node))) 'np)
(some (lambda (node)
(eq (node-name node) 'bank))
(children (first (node-children node))))
(eq (first (second (node-children node))) 'pp)))
(lambda (node)
(list (node-type node)
(append (first (node-children node))
(node-children (second (node-children node)))))))))
Running the example:
CL-USER 75 > (example)
(ROOT
(S
(NP
(NP (NNP BANK) (IN OF) (NP (NNP AMERICA))))
(VP
(VBD USED)
(S
(VP
(TO TO)
(VP
(VB BE)
(VP
(VBN CALLED)
(NP
(NP
(NNP BANK)
(IN OF)
(NP (NNP ITALY)))))))))))