1 /*
2  * Copyright (C) 2018-2021 Alexander Borisov
3  *
4  * Author: Alexander Borisov <borisov@lexbor.com>
5  */
6 
7 #ifndef LEXBOR_DOM_ELEMENT_H
8 #define LEXBOR_DOM_ELEMENT_H
9 
10 #ifdef __cplusplus
11 extern "C" {
12 #endif
13 
14 #include "lexbor/core/str.h"
15 
16 #include "lexbor/dom/interfaces/document.h"
17 #include "lexbor/dom/interfaces/node.h"
18 #include "lexbor/dom/collection.h"
19 #include "lexbor/dom/interfaces/attr.h"
20 
21 #include "lexbor/tag/tag.h"
22 
23 
24 typedef enum {
25     LXB_DOM_ELEMENT_CUSTOM_STATE_UNDEFINED      = 0x00,
26     LXB_DOM_ELEMENT_CUSTOM_STATE_FAILED         = 0x01,
27     LXB_DOM_ELEMENT_CUSTOM_STATE_UNCUSTOMIZED   = 0x02,
28     LXB_DOM_ELEMENT_CUSTOM_STATE_CUSTOM         = 0x03
29 }
30 lxb_dom_element_custom_state_t;
31 
32 struct lxb_dom_element {
33     lxb_dom_node_t                 node;
34 
35     /* For example: <LalAla:DiV Fix:Me="value"> */
36 
37     /* uppercase, with prefix: LALALA:DIV */
38     lxb_dom_attr_id_t              upper_name;
39 
40     /* original, with prefix: LalAla:DiV */
41     lxb_dom_attr_id_t              qualified_name;
42 
43     lexbor_str_t                   *is_value;
44 
45     lxb_dom_attr_t                 *first_attr;
46     lxb_dom_attr_t                 *last_attr;
47 
48     lxb_dom_attr_t                 *attr_id;
49     lxb_dom_attr_t                 *attr_class;
50 
51     lxb_dom_element_custom_state_t custom_state;
52 };
53 
54 
55 LXB_API lxb_dom_element_t *
56 lxb_dom_element_interface_create(lxb_dom_document_t *document);
57 
58 LXB_API lxb_dom_element_t *
59 lxb_dom_element_interface_clone(lxb_dom_document_t *document,
60                                 const lxb_dom_element_t *element);
61 
62 LXB_API lxb_dom_element_t *
63 lxb_dom_element_interface_destroy(lxb_dom_element_t *element);
64 
65 LXB_API lxb_status_t
66 lxb_dom_element_interface_copy(lxb_dom_element_t *dst,
67                                const lxb_dom_element_t *src);
68 
69 LXB_API lxb_dom_element_t *
70 lxb_dom_element_create(lxb_dom_document_t *document,
71                        const lxb_char_t *local_name, size_t lname_len,
72                        const lxb_char_t *ns_name, size_t ns_len,
73                        const lxb_char_t *prefix, size_t prefix_len,
74                        const lxb_char_t *is, size_t is_len,
75                        bool sync_custom);
76 
77 LXB_API lxb_dom_element_t *
78 lxb_dom_element_destroy(lxb_dom_element_t *element);
79 
80 LXB_API bool
81 lxb_dom_element_has_attributes(lxb_dom_element_t *element);
82 
83 LXB_API lxb_dom_attr_t *
84 lxb_dom_element_set_attribute(lxb_dom_element_t *element,
85                               const lxb_char_t *qualified_name, size_t qn_len,
86                               const lxb_char_t *value, size_t value_len);
87 
88 LXB_API const lxb_char_t *
89 lxb_dom_element_get_attribute(lxb_dom_element_t *element,
90                               const lxb_char_t *qualified_name, size_t qn_len,
91                               size_t *value_len);
92 
93 LXB_API lxb_status_t
94 lxb_dom_element_remove_attribute(lxb_dom_element_t *element,
95                                  const lxb_char_t *qualified_name, size_t qn_len);
96 
97 LXB_API bool
98 lxb_dom_element_has_attribute(lxb_dom_element_t *element,
99                               const lxb_char_t *qualified_name, size_t qn_len);
100 
101 LXB_API lxb_status_t
102 lxb_dom_element_attr_append(lxb_dom_element_t *element, lxb_dom_attr_t *attr);
103 
104 LXB_API lxb_status_t
105 lxb_dom_element_attr_remove(lxb_dom_element_t *element, lxb_dom_attr_t *attr);
106 
107 LXB_API lxb_dom_attr_t *
108 lxb_dom_element_attr_by_name(lxb_dom_element_t *element,
109                              const lxb_char_t *qualified_name, size_t length);
110 
111 LXB_API lxb_dom_attr_t *
112 lxb_dom_element_attr_by_local_name_data(lxb_dom_element_t *element,
113                                         const lxb_dom_attr_data_t *data);
114 
115 LXB_API lxb_dom_attr_t *
116 lxb_dom_element_attr_by_id(lxb_dom_element_t *element,
117                            lxb_dom_attr_id_t attr_id);
118 
119 LXB_API lxb_dom_attr_t *
120 lxb_dom_element_attr_by_data(lxb_dom_element_t *element,
121                              const lxb_dom_attr_data_t *data);
122 
123 LXB_API bool
124 lxb_dom_element_compare(lxb_dom_element_t *first, lxb_dom_element_t *second);
125 
126 LXB_API lxb_dom_attr_t *
127 lxb_dom_element_attr_is_exist(lxb_dom_element_t *element,
128                               const lxb_char_t *qualified_name, size_t length);
129 
130 LXB_API lxb_status_t
131 lxb_dom_element_is_set(lxb_dom_element_t *element,
132                        const lxb_char_t *is, size_t is_len);
133 
134 LXB_API lxb_status_t
135 lxb_dom_elements_by_tag_name(lxb_dom_element_t *root,
136                              lxb_dom_collection_t *collection,
137                              const lxb_char_t *qualified_name, size_t len);
138 
139 LXB_API lxb_status_t
140 lxb_dom_elements_by_class_name(lxb_dom_element_t *root,
141                                lxb_dom_collection_t *collection,
142                                const lxb_char_t *class_name, size_t len);
143 
144 LXB_API lxb_status_t
145 lxb_dom_elements_by_attr(lxb_dom_element_t *root,
146                          lxb_dom_collection_t *collection,
147                          const lxb_char_t *qualified_name, size_t qname_len,
148                          const lxb_char_t *value, size_t value_len,
149                          bool case_insensitive);
150 
151 LXB_API lxb_status_t
152 lxb_dom_elements_by_attr_begin(lxb_dom_element_t *root,
153                                lxb_dom_collection_t *collection,
154                                const lxb_char_t *qualified_name, size_t qname_len,
155                                const lxb_char_t *value, size_t value_len,
156                                bool case_insensitive);
157 
158 LXB_API lxb_status_t
159 lxb_dom_elements_by_attr_end(lxb_dom_element_t *root,
160                              lxb_dom_collection_t *collection,
161                              const lxb_char_t *qualified_name, size_t qname_len,
162                              const lxb_char_t *value, size_t value_len,
163                              bool case_insensitive);
164 
165 LXB_API lxb_status_t
166 lxb_dom_elements_by_attr_contain(lxb_dom_element_t *root,
167                                  lxb_dom_collection_t *collection,
168                                  const lxb_char_t *qualified_name, size_t qname_len,
169                                  const lxb_char_t *value, size_t value_len,
170                                  bool case_insensitive);
171 
172 LXB_API const lxb_char_t *
173 lxb_dom_element_qualified_name(lxb_dom_element_t *element, size_t *len);
174 
175 LXB_API const lxb_char_t *
176 lxb_dom_element_qualified_name_upper(lxb_dom_element_t *element, size_t *len);
177 
178 LXB_API const lxb_char_t *
179 lxb_dom_element_local_name(lxb_dom_element_t *element, size_t *len);
180 
181 LXB_API const lxb_char_t *
182 lxb_dom_element_prefix(lxb_dom_element_t *element, size_t *len);
183 
184 LXB_API const lxb_char_t *
185 lxb_dom_element_tag_name(lxb_dom_element_t *element, size_t *len);
186 
187 
188 /*
189  * Inline functions
190  */
191 lxb_inline const lxb_char_t *
lxb_dom_element_id(lxb_dom_element_t * element,size_t * len)192 lxb_dom_element_id(lxb_dom_element_t *element, size_t *len)
193 {
194     if (element->attr_id == NULL) {
195         if (len != NULL) {
196             *len = 0;
197         }
198 
199         return NULL;
200     }
201 
202     return lxb_dom_attr_value(element->attr_id, len);
203 }
204 
205 lxb_inline const lxb_char_t *
lxb_dom_element_class(lxb_dom_element_t * element,size_t * len)206 lxb_dom_element_class(lxb_dom_element_t *element, size_t *len)
207 {
208     if (element->attr_class == NULL) {
209         if (len != NULL) {
210             *len = 0;
211         }
212 
213         return NULL;
214     }
215 
216     return lxb_dom_attr_value(element->attr_class, len);
217 }
218 
219 lxb_inline bool
lxb_dom_element_is_custom(lxb_dom_element_t * element)220 lxb_dom_element_is_custom(lxb_dom_element_t *element)
221 {
222     return element->custom_state & LXB_DOM_ELEMENT_CUSTOM_STATE_CUSTOM;
223 }
224 
225 lxb_inline bool
lxb_dom_element_custom_is_defined(lxb_dom_element_t * element)226 lxb_dom_element_custom_is_defined(lxb_dom_element_t *element)
227 {
228     return element->custom_state & LXB_DOM_ELEMENT_CUSTOM_STATE_CUSTOM
229         || element->custom_state & LXB_DOM_ELEMENT_CUSTOM_STATE_UNCUSTOMIZED;
230 }
231 
232 lxb_inline lxb_dom_attr_t *
lxb_dom_element_first_attribute(lxb_dom_element_t * element)233 lxb_dom_element_first_attribute(lxb_dom_element_t *element)
234 {
235     return element->first_attr;
236 }
237 
238 lxb_inline lxb_dom_attr_t *
lxb_dom_element_next_attribute(lxb_dom_attr_t * attr)239 lxb_dom_element_next_attribute(lxb_dom_attr_t *attr)
240 {
241     return attr->next;
242 }
243 
244 lxb_inline lxb_dom_attr_t *
lxb_dom_element_prev_attribute(lxb_dom_attr_t * attr)245 lxb_dom_element_prev_attribute(lxb_dom_attr_t *attr)
246 {
247     return attr->prev;
248 }
249 
250 lxb_inline lxb_dom_attr_t *
lxb_dom_element_last_attribute(lxb_dom_element_t * element)251 lxb_dom_element_last_attribute(lxb_dom_element_t *element)
252 {
253     return element->last_attr;
254 }
255 
256 lxb_inline lxb_dom_attr_t *
lxb_dom_element_id_attribute(lxb_dom_element_t * element)257 lxb_dom_element_id_attribute(lxb_dom_element_t *element)
258 {
259     return element->attr_id;
260 }
261 
262 lxb_inline lxb_dom_attr_t *
lxb_dom_element_class_attribute(lxb_dom_element_t * element)263 lxb_dom_element_class_attribute(lxb_dom_element_t *element)
264 {
265     return element->attr_class;
266 }
267 
268 lxb_inline lxb_tag_id_t
lxb_dom_element_tag_id(lxb_dom_element_t * element)269 lxb_dom_element_tag_id(lxb_dom_element_t *element)
270 {
271     return lxb_dom_interface_node(element)->local_name;
272 }
273 
274 lxb_inline lxb_ns_id_t
lxb_dom_element_ns_id(lxb_dom_element_t * element)275 lxb_dom_element_ns_id(lxb_dom_element_t *element)
276 {
277     return lxb_dom_interface_node(element)->ns;
278 }
279 
280 
281 /*
282  * No inline functions for ABI.
283  */
284 LXB_API const lxb_char_t *
285 lxb_dom_element_id_noi(lxb_dom_element_t *element, size_t *len);
286 
287 LXB_API const lxb_char_t *
288 lxb_dom_element_class_noi(lxb_dom_element_t *element, size_t *len);
289 
290 LXB_API bool
291 lxb_dom_element_is_custom_noi(lxb_dom_element_t *element);
292 
293 LXB_API bool
294 lxb_dom_element_custom_is_defined_noi(lxb_dom_element_t *element);
295 
296 LXB_API lxb_dom_attr_t *
297 lxb_dom_element_first_attribute_noi(lxb_dom_element_t *element);
298 
299 LXB_API lxb_dom_attr_t *
300 lxb_dom_element_next_attribute_noi(lxb_dom_attr_t *attr);
301 
302 LXB_API lxb_dom_attr_t *
303 lxb_dom_element_prev_attribute_noi(lxb_dom_attr_t *attr);
304 
305 LXB_API lxb_dom_attr_t *
306 lxb_dom_element_last_attribute_noi(lxb_dom_element_t *element);
307 
308 LXB_API lxb_dom_attr_t *
309 lxb_dom_element_id_attribute_noi(lxb_dom_element_t *element);
310 
311 LXB_API lxb_dom_attr_t *
312 lxb_dom_element_class_attribute_noi(lxb_dom_element_t *element);
313 
314 
315 #ifdef __cplusplus
316 } /* extern "C" */
317 #endif
318 
319 #endif /* LEXBOR_DOM_ELEMENT_H */
320