/ traversal /
/traversal/interface.lisp
 1 ;;;; type-defines-accessors
 2 ;;;; Under this implementation strategy, elements would need only implement
 3 ;;;; accessors for traversing the node graph.
 4 (in-package #:oh-ducks.traversal)
 5 
 6 ;;; general accessors
 7 
 8 (defgeneric element-children (element)
 9   (:documentation "Returns a sequence of element's child tags."))
10 (defgeneric element-parent (element)
11   (:documentation "Returns element's parent element."))
12 (defgeneric element-attribute (attribute element)
13   (:documentation "Returns the value of the attribute of element, or nil if no such attribute exists."))
14 (defgeneric element-type (element)
15   (:documentation "Returns the tag name (type) of element."))
16 (defgeneric element-content (element)
17   (:documentation "Returns a string containing the contents of the element, if it contains only textual nodes, or a sequence containing all of the element's child nodes (textual nodes as strings, tag nodes as whatever they'd be under #'element-children).")
18   (:method :around ((element t))
19     (let ((val (call-next-method)))
20       (if (every #'stringp val)
21           (reduce (curry #'concatenate 'string) val)
22           val))))
23 
24 ;;; special accessors in case something special needs to happen
25 
26 (defgeneric element-id (element)
27   (:documentation "Equivalent in spirit to (element-attribute :id element).")
28   (:method (element) (element-attribute :id element)))
29 
30 (defgeneric element-classes (element)
31   (:documentation "Equivalent in spirit to (element-attribute :class element), except it returns a sequence of individual classes.")
32   (:method (element)
33     (split-sequence:split-sequence #\Space (element-attribute :class element) :remove-empty-subseqs t)))
34 
35 (defgeneric element-type-equal (element type)
36   (:documentation "Equivalent in spirit to (string-equal (element-type element) type), but not obligated to work under the assumption of string-designators.")
37   (:method (element type) (string-equal type (element-type element))))
38 
39 (defgeneric element-ancestors (element)
40   (:documentation "The result of calling element-parent repeatedly up the document tree.")
41   (:method (element)
42     (let ((parent (element-parent element)))
43       (when parent
44         (cons parent (element-ancestors parent))))))