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))))))