(in-package :c2ffi) ;;;;;;;;; XML Tree Functions ;;;;;;;;;; (defun map-nodes-df (func root) "Depth-first traversal of ROOT." (funcall func root) (dolist (child (node-children root)) (map-nodes-df func child))) (defmacro do-nodes-df ((node-sym root &optional (result-form nil)) &body body) (once-only (root) `(block nil (map-nodes-df #'(lambda (,node-sym) ,@body) ,root) ,result-form))) (defun node-attribute (attr-name node &optional (test #'string=)) (second (find attr-name (node-attrs node) :key #'first :test test))) (defun find-in-tree (root element-type attr-val-lists &key (test #'string=) (all nil)) "Find a node in the tree with rood NODE whose name matches ELEMENT-TYPE and each attribute specified in ATTR-VAL-PAIRS matches. If ALL is true, then a list of all matching nodes are returned. Otherwise, the first match (in depth-first order) is returned." (let ((results nil)) (do-nodes-df (node root (nreverse results)) (when (and (funcall test (node-name node) element-type) (every #'(lambda (attr-val) (funcall test (second attr-val) (node-attribute (first attr-val) node test))) attr-val-lists)) (push node results) (unless all (return node))))))