我找不到示例,也找不到这些函数的文档:
find-recursively
find-recursively-if
假设我想在堆栈溢出的首页找到第一个<div class="summary">我可以这样得到HTML树:

(defun get-page (url)
  "Get STP(DOM alternative) representation of page"
  (chtml:parse
   (drakma:http-request url)
   (cxml-stp:make-builder)))

(get-page "http://stackoverflow.com")

不过,从这里开始,我不知道真正的参数应该是什么样的find-recursivelyfind-recursively-if
编辑:使用<div class="summary">在SO首页找到第一个find-recursively-if的解决方案:
(cxml-stp:find-recursively-if
 (lambda (node)
   (and (typep node 'cxml-stp:element)
    (equal (stp:local-name node) "div")
    (equal (stp:attribute-value node "class") "summary")))
 (get-page "http://stackoverflow.com"))

最佳答案

这些函数遍历节点树,并在找到所需节点(在find-recursively的情况下)或满足谓词的节点(在find-recursively-if的情况下)时返回谓词可能应该对节点执行某些操作,但可以是任意的例如,这里有一种返回第10个节点的方法(通过使用在第10次调用时返回true的谓词):

;; return the 10th node
(let ((x 0))
  (cxml-stp:find-recursively-if
   (lambda (node)
     (= (incf x) 10))
   (get-page "http://stackoverflow.com")))

作为一个更实际的例子,下面是如何检索本地名为"title"的元素(请注意,您只能在local-name上使用elements,而不能在任意node上使用,因此:key函数有点尴尬):
CL-USER> (cxml-stp:find-recursively
          "title"
          (get-page "http://stackoverflow.com")
          :key (lambda (node)
                 (if (typep node 'cxml-stp:element)
                     (cxml-stp:local-name node)
                     ""))
          :test 'string-equal)
;=>
;#.(CXML-STP:ELEMENT
;   #| :PARENT of type ELEMENT |#
;   :CHILDREN '(#.(CXML-STP:TEXT
;                  #| :PARENT of type ELEMENT |#
;                  :DATA "Stack Overflow"))
;   :LOCAL-NAME "title"
;   :NAMESPACE-URI "http://www.w3.org/1999/xhtml")

10-06 13:27