首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从Common (闭包XML )中的节点中提取XML数据

从Common (闭包XML )中的节点中提取XML数据
EN

Code Review用户
提问于 2018-06-02 23:43:09
回答 1查看 152关注 0票数 2

这是一个函数,用于获取XML元素(以闭包XML格式表示)和名称,并在该XML元素中(在标记或属性中)查找该名称中的简单数据。它很管用,但我对LISP还不熟悉--它能写得更优雅些吗?

代码语言:javascript
复制
(defun find-data-inside-xml (element name)
  ;; Maybe there's an attribute?
  (if (dom:has-attribute element name) (dom:get-attribute element name)
  ;; There isn't, we have to do it the ugly way. Find suitable subnodes.
    (let ((candidate-values (loop for node across (dom:child-nodes element) 
                           when (string= (dom:node-name node) name) collect node)))
     ;; Check there was only one of them.
     (cond
        ((> (length candidate-values) 1) (error "XML element has multiple ~S elements." name))
        ((= (length candidate-values) 0) (error "XML element missing ~S element." name))
        (t (let ((cand-children (dom:child-nodes (car candidate-values))))
            ;; Check the one there was, has only one child node.
            (cond
             ((> (length cand-children) 1) (error "XML ~S element has complex content." name))
             ((= (length cand-children) 0) (error "~S element has no content." name))
             (t (let ((content-node (elt cand-children 0)))
                 ;; If that child node is text, that's our value. Otherwise, error.
                 (if (eq (dom:node-type content-node) :text)
                     (dom:node-value content-node)
                     (error "~S element value is not text." name)))))))))))
EN

回答 1

Code Review用户

回答已采纳

发布于 2018-06-04 08:17:58

  • 您可以使用REMOVE代替循环。
  • 您可以用断言替换CONDs和IFs以及错误。
  • 先换车

具体的函数使代码的意图更加清晰。

未经测试:

代码语言:javascript
复制
(defun find-data-inside-xml (element name)
  (if (dom:has-attribute element name)
      (dom:get-attribute element name)
    (let* ((candidates (remove name (dom:child-nodes element)
                               :key #'dom:node-name
                               :test-not #'string=))
           (n-candidates (length candidates)))
      (assert (not (> n-candidates 1)) ()
              "XML element has multiple ~S elements." name)
      (assert (not (= n-candidates 0)) ()
              "XML element missing ~S element."       name)
      (let* ((candidate-children (dom:child-nodes (first candidate-values)))
             (n-candidate-children (length candidate-children)))
        (assert (not (> n-candidate-children 1)) ()
                "XML ~S element has complex content." name)
        (assert (not (= n-candidate-children 0)) ()
                "~S element has no content."          name)
        (let ((content-node (elt candidate-children 0)))
          (assert (eq (dom:node-type content-node) :text) ()
                   "~S element value is not text." name)
          (dom:node-value content-node))))))

有时,人们也会看到一些宏观的东西,以使代码级别的意图更加清晰。但这还有其他代价:

代码语言:javascript
复制
(defmacro with-length-checked ((varn var &rest exprs) &body body)
  (let ((asserts (loop for (test test-a msg . args) in exprs
                       collect `(assert (not (,test ,var ,test-a)) ,msg ,@args))))
    `(let ((,var (length ,varn)))
       ,@asserts
       ,@body)))

(defun find-data-inside-xml (element name)
  (if (dom:has-attribute element name)
      (dom:get-attribute element name)
    (let ((candidates (remove name (dom:child-nodes element)
                              :key #'dom:node-name
                              :test-not #'string=)))
      (with-length-checked (candidates n-candidates
                            (> 1 "XML element has multiple ~S elements." name)
                            (= 0 "XML element missing ~S element."       name))
        (let ((candidate-children   (dom:child-nodes (first candidate-values))))
          (with-length-checked (candidate-children n-candidate-children
                                (> 1 "XML ~S element has complex content." name)
                                (= 0  "~S element has no content."         name))
             (let ((content-node (elt candidate-children 0)))
               (assert (eq (dom:node-type content-node) :text) ()
                 "~S element value is not text." name)
               (dom:node-value content-node))))))))
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/195724

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档