Bridging: Allow channels to define bridging hooks
[asterisk/asterisk.git] / main / xml.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief XML abstraction layer
20  *
21  * \author Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
22  */
23
24 /*** MODULEINFO
25         <support_level>core</support_level>
26  ***/
27
28 #include "asterisk.h"
29 #include "asterisk/xml.h"
30 #include "asterisk/logger.h"
31 #include "asterisk/utils.h"
32 #include "asterisk/autoconfig.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #if defined(HAVE_LIBXML2)
37 #include <libxml/parser.h>
38 #include <libxml/tree.h>
39 #include <libxml/xinclude.h>
40 #include <libxml/xpath.h>
41 /* libxml2 ast_xml implementation. */
42 #ifdef HAVE_LIBXSLT
43         #include <libxslt/xsltInternals.h>
44         #include <libxslt/transform.h>
45 #endif /* HAVE_LIBXSLT */
46
47
48 int ast_xml_init(void)
49 {
50         LIBXML_TEST_VERSION
51
52         return 0;
53 }
54
55 int ast_xml_finish(void)
56 {
57         xmlCleanupParser();
58 #ifdef HAVE_LIBXSLT_CLEANUP
59         xsltCleanupGlobals();
60 #endif
61
62         return 0;
63 }
64
65 struct ast_xml_doc *ast_xml_open(char *filename)
66 {
67         xmlDoc *doc;
68
69         if (!filename) {
70                 return NULL;
71         }
72
73         doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
74         if (!doc) {
75                 return NULL;
76         }
77
78         /* process xinclude elements. */
79         if (xmlXIncludeProcess(doc) < 0) {
80                 xmlFreeDoc(doc);
81                 return NULL;
82         }
83
84 #ifdef HAVE_LIBXSLT
85         {
86                 xsltStylesheetPtr xslt = xsltLoadStylesheetPI(doc);
87                 if (xslt) {
88                         xmlDocPtr tmpdoc = xsltApplyStylesheet(xslt, doc, NULL);
89                         xsltFreeStylesheet(xslt);
90                         xmlFreeDoc(doc);
91                         if (!tmpdoc) {
92                                 return NULL;
93                         }
94                         doc = tmpdoc;
95                 }
96         }
97 #else /* no HAVE_LIBXSLT */
98         ast_log(LOG_NOTICE, "XSLT support not found. XML documentation may be incomplete.\n");
99 #endif /* HAVE_LIBXSLT */
100
101         return (struct ast_xml_doc *) doc;
102 }
103
104 struct ast_xml_doc *ast_xml_new(void)
105 {
106         xmlDoc *doc;
107
108         doc = xmlNewDoc((const xmlChar *) "1.0");
109         return (struct ast_xml_doc *) doc;
110 }
111
112 struct ast_xml_node *ast_xml_new_node(const char *name)
113 {
114         xmlNode *node;
115         if (!name) {
116                 return NULL;
117         }
118
119         node = xmlNewNode(NULL, (const xmlChar *) name);
120
121         return (struct ast_xml_node *) node;
122 }
123
124 struct ast_xml_node *ast_xml_new_child(struct ast_xml_node *parent, const char *child_name)
125 {
126         xmlNode *child;
127
128         if (!parent || !child_name) {
129                 return NULL;
130         }
131
132         child = xmlNewChild((xmlNode *) parent, NULL, (const xmlChar *) child_name, NULL);
133         return (struct ast_xml_node *) child;
134 }
135
136 struct ast_xml_node *ast_xml_add_child(struct ast_xml_node *parent, struct ast_xml_node *child)
137 {
138         if (!parent || !child) {
139                 return NULL;
140         }
141         return (struct ast_xml_node *) xmlAddChild((xmlNode *) parent, (xmlNode *) child);
142 }
143
144 struct ast_xml_doc *ast_xml_read_memory(char *buffer, size_t size)
145 {
146         xmlDoc *doc;
147
148         if (!buffer) {
149                 return NULL;
150         }
151
152         if (!(doc = xmlParseMemory(buffer, (int) size))) {
153                 /* process xinclude elements. */
154                 if (xmlXIncludeProcess(doc) < 0) {
155                         xmlFreeDoc(doc);
156                         return NULL;
157                 }
158         }
159
160         return (struct ast_xml_doc *) doc;
161 }
162
163 void ast_xml_close(struct ast_xml_doc *doc)
164 {
165         if (!doc) {
166                 return;
167         }
168
169         xmlFreeDoc((xmlDoc *) doc);
170         doc = NULL;
171 }
172
173 void ast_xml_set_root(struct ast_xml_doc *doc, struct ast_xml_node *node)
174 {
175         if (!doc || !node) {
176                 return;
177         }
178
179         xmlDocSetRootElement((xmlDoc *) doc, (xmlNode *) node);
180 }
181
182 struct ast_xml_node *ast_xml_get_root(struct ast_xml_doc *doc)
183 {
184         xmlNode *root_node;
185
186         if (!doc) {
187                 return NULL;
188         }
189
190         root_node = xmlDocGetRootElement((xmlDoc *) doc);
191
192         return (struct ast_xml_node *) root_node;
193 }
194
195 void ast_xml_free_node(struct ast_xml_node *node)
196 {
197         if (!node) {
198                 return;
199         }
200
201         xmlFreeNode((xmlNode *) node);
202         node = NULL;
203 }
204
205 void ast_xml_free_attr(const char *attribute)
206 {
207         if (attribute) {
208                 xmlFree((char *) attribute);
209         }
210 }
211
212 void ast_xml_free_text(const char *text)
213 {
214         if (text) {
215                 xmlFree((char *) text);
216         }
217 }
218
219 const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname)
220 {
221         xmlChar *attrvalue;
222
223         if (!node) {
224                 return NULL;
225         }
226
227         if (!attrname) {
228                 return NULL;
229         }
230
231         attrvalue = xmlGetProp((xmlNode *) node, (xmlChar *) attrname);
232
233         return (const char *) attrvalue;
234 }
235
236 int ast_xml_set_attribute(struct ast_xml_node *node, const char *name, const char *value)
237 {
238         if (!name || !value) {
239                 return -1;
240         }
241
242         if (!xmlSetProp((xmlNode *) node, (xmlChar *) name, (xmlChar *) value)) {
243                 return -1;
244         }
245
246         return 0;
247 }
248
249 struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue)
250 {
251         struct ast_xml_node *cur;
252         const char *attr;
253
254         if (!root_node) {
255                 return NULL;
256         }
257
258         for (cur = root_node; cur; cur = ast_xml_node_get_next(cur)) {
259                 /* Check if the name matchs */
260                 if (strcmp(ast_xml_node_get_name(cur), name)) {
261                         continue;
262                 }
263                 /* We need to check for a specific attribute name? */
264                 if (!attrname || !attrvalue) {
265                         return cur;
266                 }
267                 /* Get the attribute, we need to compare it. */
268                 if ((attr = ast_xml_get_attribute(cur, attrname))) {
269                         /* does attribute name/value matches? */
270                         if (!strcmp(attr, attrvalue)) {
271                                 ast_xml_free_attr(attr);
272                                 return cur;
273                         }
274                         ast_xml_free_attr(attr);
275                 }
276         }
277
278         return NULL;
279 }
280
281 struct ast_xml_doc *ast_xml_get_doc(struct ast_xml_node *node)
282 {
283         if (!node) {
284                 return NULL;
285         }
286
287         return (struct ast_xml_doc *) ((xmlNode *)node)->doc;
288 }
289
290 struct ast_xml_ns *ast_xml_find_namespace(struct ast_xml_doc *doc, struct ast_xml_node *node, const char *ns_name) {
291         xmlNsPtr ns = xmlSearchNs((xmlDocPtr) doc, (xmlNodePtr) node, (xmlChar *) ns_name);
292         return (struct ast_xml_ns *) ns;
293 }
294
295 const char *ast_xml_get_ns_href(struct ast_xml_ns *ns)
296 {
297         return (const char *) ((xmlNsPtr) ns)->href;
298 }
299
300 const char *ast_xml_get_text(struct ast_xml_node *node)
301 {
302         if (!node) {
303                 return NULL;
304         }
305
306         return (const char *) xmlNodeGetContent((xmlNode *) node);
307 }
308
309 void ast_xml_set_text(struct ast_xml_node *node, const char *content)
310 {
311         if (!node || !content) {
312                 return;
313         }
314
315         xmlNodeSetContent((xmlNode *) node, (const xmlChar *) content);
316 }
317
318 int ast_xml_doc_dump_file(FILE *output, struct ast_xml_doc *doc)
319 {
320         return xmlDocDump(output, (xmlDocPtr)doc);
321 }
322
323 const char *ast_xml_node_get_name(struct ast_xml_node *node)
324 {
325         return (const char *) ((xmlNode *) node)->name;
326 }
327
328 struct ast_xml_node *ast_xml_node_get_children(struct ast_xml_node *node)
329 {
330         return (struct ast_xml_node *) ((xmlNode *) node)->children;
331 }
332
333 struct ast_xml_node *ast_xml_node_get_next(struct ast_xml_node *node)
334 {
335         return (struct ast_xml_node *) ((xmlNode *) node)->next;
336 }
337
338 struct ast_xml_node *ast_xml_node_get_prev(struct ast_xml_node *node)
339 {
340         return (struct ast_xml_node *) ((xmlNode *) node)->prev;
341 }
342
343 struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node)
344 {
345         return (struct ast_xml_node *) ((xmlNode *) node)->parent;
346 }
347
348 struct ast_xml_node *ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
349 {
350         return (struct ast_xml_node *) ((xmlXPathObjectPtr) results)->nodesetval->nodeTab[0];
351 }
352
353 void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
354 {
355         xmlXPathFreeObject((xmlXPathObjectPtr) results);
356 }
357
358 int ast_xml_xpath_num_results(struct ast_xml_xpath_results *results)
359 {
360         return ((xmlXPathObjectPtr) results)->nodesetval->nodeNr;
361 }
362
363 struct ast_xml_xpath_results *ast_xml_query(struct ast_xml_doc *doc, const char *xpath_str)
364 {
365         xmlXPathContextPtr context;
366         xmlXPathObjectPtr result;
367         if (!(context = xmlXPathNewContext((xmlDoc *) doc))) {
368                 ast_log(LOG_ERROR, "Could not create XPath context!\n");
369                 return NULL;
370         }
371         result = xmlXPathEvalExpression((xmlChar *) xpath_str, context);
372         xmlXPathFreeContext(context);
373         if (!result) {
374                 ast_log(LOG_WARNING, "Error for query: %s\n", xpath_str);
375                 return NULL;
376         }
377         if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
378                 xmlXPathFreeObject(result);
379                 ast_debug(5, "No results for query: %s\n", xpath_str);
380                 return NULL;
381         }
382         return (struct ast_xml_xpath_results *) result;
383 }
384
385 #endif /* defined(HAVE_LIBXML2) */
386