LISP Xpath按顺序获取多个节点

时间:2014-03-22 01:37:43

标签: xpath lisp common-lisp

首先,我对LISP真的很陌生,我试图感受这种语言。

让我们使用以下代码(我使用closure-html和cxml-stop):

(defparameter *document*
   (cxml:parse "<test a='1' b='2' xmlns:foo='http://foo'>
                      <child>hello world</child>
                      <mommy>hello</mommy>
                      <father>world</father>
                      <child>hello world2</child>
                      <mommy>hello2</mommy>
                      <father>world2</father>
                      <child>hello world3</child>
                      <mommy>hello3</mommy>
                      <father>world3</father>
                      <foo:child>bar</foo:child>
                    </test>"
           (stp:make-builder)))

如何获取followind输出:

 Child: hello world
 Mommy: hello
 Father: world
 Child: hello world2
 Mommy: hello2
 Father: world2
 Child: hello world3
 Mommy: hello3
 Father: world3

我已经能够按顺序凝胶所有的Childs,然后按顺序凝胶所有的Mommys,然后是所有的父亲。

但是我现在无法按照它们出现的顺序获取节点。

任何想法?

提前致谢:)

2 个答案:

答案 0 :(得分:0)

我不知道LISP,但是如果你正在寻找XPath表达式来获取test元素中的所有child,mommy和father元素,你可以使用它:

/test/*[name()='child' or name()='father' or name()='mommy']

上面的表达式意味着选择元素名称等于'child'或'father'或'mommy'的<test>的所有子元素。这将返回所有匹配的元素,以便它们以XML格式显示。假设您知道如何在LISP中调用XPath表达式,那么上面的XPath应该会让您知道如何实现该要求。

答案 1 :(得分:0)

首先,我不太了解XML部分,而且我不熟悉cxml的API。

据我了解,问题是将stp:of-name包装成允许按多个名称搜索的东西。

一种解决方案是实现函数of-names

(defun of-names (&rest names)
  #'(lambda (ch)
      (some #'(lambda (n)
                (funcall (stp:of-name n) ch)) names)))

另一个解决方案是实现更高阶or&#39;,i。即编写or的包装器,它将接受一个参数的多个函数并返回or个值的函数:

(defun f-or (&rest funs)
  #'(lambda (x)
      (dolist (f funs)
        (let ((y (funcall f x)))
          (when y
            (return y))))))

现在两种形式

(let ((name-text (mapcar #'(lambda (e)
                             (list (stp:local-name e)
                                   (stp:data (first (stp:list-children e)))))
                         (stp:filter-children (f-or (stp:of-name "child") 
                                                    (stp:of-name "mommy")
                                                    (stp:of-name "father"))
                                              (first (stp:list-children *document*))))))

  (format nil "~{~{~@(~A~): ~A~}~^~%~}" name-text))

(let ((name-text (mapcar #'(lambda (e)
                             (list (stp:local-name e)
                                   (stp:data (first (stp:list-children e)))))
                         (stp:filter-children (of-names "child" "mommy" "father")
                                              (first (stp:list-children *document*))))))
  (format nil "~{~{~@(~A~): ~A~}~^~%~}" name-text))

产生字符串

"Child: hello world
Mommy: hello
Father: world
Child: hello world2
Mommy: hello2
Father: world2
Child: hello world3
Mommy: hello3
Father: world3"