aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorLars Magne Ingebrigtsen2014-11-26 19:39:49 +0100
committerLars Magne Ingebrigtsen2014-11-26 19:42:29 +0100
commit115178cd46b10383a12bd865739d0d55eea20251 (patch)
tree378d42edbcee5494d69ed1ab7a72c7e486b65153 /lisp
parent549a1bae4a54c56c4c8d212f1441ac44aac89a4b (diff)
downloademacs-115178cd46b10383a12bd865739d0d55eea20251.tar.gz
emacs-115178cd46b10383a12bd865739d0d55eea20251.zip
* dom.el: New file.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog4
-rw-r--r--lisp/dom.el176
2 files changed, 180 insertions, 0 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index ee473902376..794f5f84b2f 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -8,6 +8,10 @@
8 Remove spurious reference to symbol category_properties. 8 Remove spurious reference to symbol category_properties.
9 * progmodes/cc-engine.el (c-state-pp-to-literal): Fix here. 9 * progmodes/cc-engine.el (c-state-pp-to-literal): Fix here.
10 10
112014-11-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
12
13 * dom.el: New file.
14
112014-11-26 Glenn Morris <rgm@gnu.org> 152014-11-26 Glenn Morris <rgm@gnu.org>
12 16
13 * arc-mode.el (archive-visit-single-files): Add :version. 17 * arc-mode.el (archive-visit-single-files): Add :version.
diff --git a/lisp/dom.el b/lisp/dom.el
new file mode 100644
index 00000000000..3157e0b2f2a
--- /dev/null
+++ b/lisp/dom.el
@@ -0,0 +1,176 @@
1;;; dom.el --- XML/HTML (etc.) DOM manipulation and searching functions
2
3;; Copyright (C) 2014 Free Software Foundation, Inc.
4
5;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6;; Keywords: xml, html
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23;;; Commentary:
24
25;;; Code:
26
27(require 'cl-lib)
28
29(defsubst dom-tag (node)
30 "Return the NODE tag."
31 ;; Called on a list of nodes. Use the first.
32 (if (consp (car node))
33 (caar node)
34 (car node)))
35
36(defsubst dom-attributes (node)
37 "Return the NODE attributes."
38 ;; Called on a list of nodes. Use the first.
39 (if (consp (car node))
40 (cadr (car node))
41 (cadr node)))
42
43(defsubst dom-children (node)
44 "Return the NODE children."
45 ;; Called on a list of nodes. Use the first.
46 (if (consp (car node))
47 (cddr (car node))
48 (cddr node)))
49
50(defun dom-set-attributes (node attributes)
51 "Set the attributes of NODE to ATTRIBUTES."
52 (setq node (dom-ensure-node node))
53 (setcar (cdr node) attributes))
54
55(defun dom-set-attribute (node attribute value)
56 "Set ATTRIBUTE in NODE to VALUE."
57 (setq node (dom-ensure-node node))
58 (let ((old (assoc attribute (cadr node))))
59 (if old
60 (setcdr old value)
61 (setcar (cdr node) (nconc (cadr node) (list (cons attribute value)))))))
62
63(defmacro dom-attr (node attr)
64 "Return the attribute ATTR from NODE.
65A typical attribute is `href'."
66 `(cdr (assq ,attr (dom-attributes ,node))))
67
68(defun dom-text (node)
69 "Return all the text bits in the current node concatenated."
70 (mapconcat 'identity (cl-remove-if-not 'stringp (dom-children node)) " "))
71
72(defun dom-texts (node &optional separator)
73 "Return all textual data under NODE concatenated with SEPARATOR in-between."
74 (mapconcat
75 'identity
76 (mapcar
77 (lambda (elem)
78 (if (stringp elem)
79 elem
80 (dom-texts elem separator)))
81 (dom-children node))
82 (or separator " ")))
83
84(defun dom-child-by-tag (dom tag)
85 "Return the first child of DOM that is of type TAG."
86 (assoc tag (dom-children dom)))
87
88(defun dom-by-tag (dom tag)
89 "Return elements in DOM that is of type TAG.
90A name is a symbol like `td'."
91 (let ((matches (cl-loop for child in (dom-children dom)
92 for matches = (and (not (stringp child))
93 (dom-by-tag child tag))
94 when matches
95 append matches)))
96 (if (eq (dom-tag dom) tag)
97 (cons dom matches)
98 matches)))
99
100(defun dom-by-class (dom match)
101 "Return elements in DOM that have a class name that matches regexp MATCH."
102 (dom-elements dom 'class match))
103
104(defun dom-by-style (dom match)
105 "Return elements in DOM that have a style that matches regexp MATCH."
106 (dom-elements dom 'style match))
107
108(defun dom-by-id (dom match)
109 "Return elements in DOM that have an ID that matches regexp MATCH."
110 (dom-elements dom 'id match))
111
112(defun dom-elements (dom attribute match)
113 "Find elements matching MATCH (a regexp) in ATTRIBUTE.
114ATTRIBUTE would typically be `class', `id' or the like."
115 (let ((matches (cl-loop for child in (dom-children dom)
116 for matches = (dom-elements child attribute match)
117 when matches
118 append matches))
119 (attr (dom-attr dom attribute)))
120 (if (and attr
121 (string-match match attr))
122 (cons dom matches)
123 matches)))
124
125(defun dom-parent (dom node)
126 "Return the parent of NODE in DOM."
127 (if (memq node (dom-children dom))
128 dom
129 (let ((result nil))
130 (dolist (elem (dom-children dom))
131 (when (and (not result)
132 (not (stringp elem)))
133 (setq result (dom-parent elem node))))
134 result)))
135
136(defun dom-node (tag &optional attributes &rest children)
137 "Return a DOM node with TAG and ATTRIBUTES."
138 (if children
139 `(,tag ,attributes ,@children)
140 (list tag attributes)))
141
142(defun dom-append-child (node child)
143 "Append CHILD to the end of NODE's children."
144 (setq node (dom-ensure-node node))
145 (nconc node (list child)))
146
147(defun dom-add-child-before (node child &optional before)
148 "Add CHILD to NODE's children before child BEFORE.
149If BEFORE is nil, make CHILD NODE's first child."
150 (setq node (dom-ensure-node node))
151 (let ((children (dom-children node)))
152 (when (and before
153 (not (memq before children)))
154 (error "%s does not exist as a child" before))
155 (let ((pos (if before
156 (cl-position before children)
157 0)))
158 (if (zerop pos)
159 ;; First child.
160 (setcdr (cdr node) (cons child (cddr node)))
161 (setcdr (nthcdr (1- pos) children)
162 (cons child (nthcdr pos children))))))
163 node)
164
165(defun dom-ensure-node (node)
166 "Ensure that NODE is a proper DOM node."
167 ;; Add empty attributes, if none.
168 (when (consp (car node))
169 (setq node (car node)))
170 (when (= (length node) 1)
171 (setcdr node (list nil)))
172 node)
173
174(provide 'dom)
175
176;;; dom.el ends here