xref: /netbsd-src/external/bsd/wpa/dist/src/utils/xml-utils.c (revision 0a73ee0a32b4208ab171f89f408b38fd4c664291)
13c260e60Schristos /*
23c260e60Schristos  * Generic XML helper functions
33c260e60Schristos  * Copyright (c) 2012-2013, Qualcomm Atheros, Inc.
43c260e60Schristos  *
53c260e60Schristos  * This software may be distributed under the terms of the BSD license.
63c260e60Schristos  * See README for more details.
73c260e60Schristos  */
83c260e60Schristos 
93c260e60Schristos #include "includes.h"
103c260e60Schristos 
113c260e60Schristos #include "common.h"
123c260e60Schristos #include "xml-utils.h"
133c260e60Schristos 
143c260e60Schristos 
get_node_uri_iter(struct xml_node_ctx * ctx,xml_node_t * root,char * uri)153c260e60Schristos static xml_node_t * get_node_uri_iter(struct xml_node_ctx *ctx,
163c260e60Schristos 				      xml_node_t *root, char *uri)
173c260e60Schristos {
183c260e60Schristos 	char *end;
193c260e60Schristos 	xml_node_t *node;
203c260e60Schristos 	const char *name;
213c260e60Schristos 
223c260e60Schristos 	end = strchr(uri, '/');
233c260e60Schristos 	if (end)
243c260e60Schristos 		*end++ = '\0';
253c260e60Schristos 
263c260e60Schristos 	node = root;
273c260e60Schristos 	xml_node_for_each_sibling(ctx, node) {
283c260e60Schristos 		xml_node_for_each_check(ctx, node);
293c260e60Schristos 		name = xml_node_get_localname(ctx, node);
303c260e60Schristos 		if (strcasecmp(name, uri) == 0)
313c260e60Schristos 			break;
323c260e60Schristos 	}
333c260e60Schristos 
343c260e60Schristos 	if (node == NULL)
353c260e60Schristos 		return NULL;
363c260e60Schristos 
373c260e60Schristos 	if (end) {
383c260e60Schristos 		return get_node_uri_iter(ctx, xml_node_first_child(ctx, node),
393c260e60Schristos 					 end);
403c260e60Schristos 	}
413c260e60Schristos 
423c260e60Schristos 	return node;
433c260e60Schristos }
443c260e60Schristos 
453c260e60Schristos 
get_node_uri(struct xml_node_ctx * ctx,xml_node_t * root,const char * uri)463c260e60Schristos xml_node_t * get_node_uri(struct xml_node_ctx *ctx, xml_node_t *root,
473c260e60Schristos 			  const char *uri)
483c260e60Schristos {
493c260e60Schristos 	char *search;
503c260e60Schristos 	xml_node_t *node;
513c260e60Schristos 
523c260e60Schristos 	search = os_strdup(uri);
533c260e60Schristos 	if (search == NULL)
543c260e60Schristos 		return NULL;
553c260e60Schristos 
563c260e60Schristos 	node = get_node_uri_iter(ctx, root, search);
573c260e60Schristos 
583c260e60Schristos 	os_free(search);
593c260e60Schristos 	return node;
603c260e60Schristos }
613c260e60Schristos 
623c260e60Schristos 
get_node_iter(struct xml_node_ctx * ctx,xml_node_t * root,const char * path)633c260e60Schristos static xml_node_t * get_node_iter(struct xml_node_ctx *ctx,
643c260e60Schristos 				  xml_node_t *root, const char *path)
653c260e60Schristos {
663c260e60Schristos 	char *end;
673c260e60Schristos 	xml_node_t *node;
683c260e60Schristos 	const char *name;
693c260e60Schristos 
703c260e60Schristos 	end = os_strchr(path, '/');
713c260e60Schristos 	if (end)
723c260e60Schristos 		*end++ = '\0';
733c260e60Schristos 
743c260e60Schristos 	xml_node_for_each_child(ctx, node, root) {
753c260e60Schristos 		xml_node_for_each_check(ctx, node);
763c260e60Schristos 		name = xml_node_get_localname(ctx, node);
773c260e60Schristos 		if (os_strcasecmp(name, path) == 0)
783c260e60Schristos 			break;
793c260e60Schristos 	}
803c260e60Schristos 
813c260e60Schristos 	if (node == NULL)
823c260e60Schristos 		return NULL;
833c260e60Schristos 	if (end)
843c260e60Schristos 		return get_node_iter(ctx, node, end);
853c260e60Schristos 	return node;
863c260e60Schristos }
873c260e60Schristos 
883c260e60Schristos 
get_node(struct xml_node_ctx * ctx,xml_node_t * root,const char * path)893c260e60Schristos xml_node_t * get_node(struct xml_node_ctx *ctx, xml_node_t *root,
903c260e60Schristos 		      const char *path)
913c260e60Schristos {
923c260e60Schristos 	char *search;
933c260e60Schristos 	xml_node_t *node;
943c260e60Schristos 
953c260e60Schristos 	search = os_strdup(path);
963c260e60Schristos 	if (search == NULL)
973c260e60Schristos 		return NULL;
983c260e60Schristos 
993c260e60Schristos 	node = get_node_iter(ctx, root, search);
1003c260e60Schristos 
1013c260e60Schristos 	os_free(search);
1023c260e60Schristos 	return node;
1033c260e60Schristos }
1043c260e60Schristos 
1053c260e60Schristos 
get_child_node(struct xml_node_ctx * ctx,xml_node_t * root,const char * path)1063c260e60Schristos xml_node_t * get_child_node(struct xml_node_ctx *ctx, xml_node_t *root,
1073c260e60Schristos 			    const char *path)
1083c260e60Schristos {
1093c260e60Schristos 	xml_node_t *node;
1103c260e60Schristos 	xml_node_t *match;
1113c260e60Schristos 
1123c260e60Schristos 	xml_node_for_each_child(ctx, node, root) {
1133c260e60Schristos 		xml_node_for_each_check(ctx, node);
1143c260e60Schristos 		match = get_node(ctx, node, path);
1153c260e60Schristos 		if (match)
1163c260e60Schristos 			return match;
1173c260e60Schristos 	}
1183c260e60Schristos 
1193c260e60Schristos 	return NULL;
1203c260e60Schristos }
1213c260e60Schristos 
1223c260e60Schristos 
node_from_file(struct xml_node_ctx * ctx,const char * name)1233c260e60Schristos xml_node_t * node_from_file(struct xml_node_ctx *ctx, const char *name)
1243c260e60Schristos {
1253c260e60Schristos 	xml_node_t *node;
1263c260e60Schristos 	char *buf, *buf2, *start;
1273c260e60Schristos 	size_t len;
1283c260e60Schristos 
1293c260e60Schristos 	buf = os_readfile(name, &len);
1303c260e60Schristos 	if (buf == NULL)
1313c260e60Schristos 		return NULL;
1323c260e60Schristos 	buf2 = os_realloc(buf, len + 1);
1333c260e60Schristos 	if (buf2 == NULL) {
1343c260e60Schristos 		os_free(buf);
1353c260e60Schristos 		return NULL;
1363c260e60Schristos 	}
1373c260e60Schristos 	buf = buf2;
1383c260e60Schristos 	buf[len] = '\0';
1393c260e60Schristos 
1403c260e60Schristos 	start = os_strstr(buf, "<!DOCTYPE ");
1413c260e60Schristos 	if (start) {
1423c260e60Schristos 		char *pos = start + 1;
1433c260e60Schristos 		int count = 1;
1443c260e60Schristos 		while (*pos) {
1453c260e60Schristos 			if (*pos == '<')
1463c260e60Schristos 				count++;
1473c260e60Schristos 			else if (*pos == '>') {
1483c260e60Schristos 				count--;
1493c260e60Schristos 				if (count == 0) {
1503c260e60Schristos 					pos++;
1513c260e60Schristos 					break;
1523c260e60Schristos 				}
1533c260e60Schristos 			}
1543c260e60Schristos 			pos++;
1553c260e60Schristos 		}
1563c260e60Schristos 		if (count == 0) {
1573c260e60Schristos 			/* Remove DOCTYPE to allow the file to be parsed */
1583c260e60Schristos 			os_memset(start, ' ', pos - start);
1593c260e60Schristos 		}
1603c260e60Schristos 	}
1613c260e60Schristos 
1623c260e60Schristos 	node = xml_node_from_buf(ctx, buf);
1633c260e60Schristos 	os_free(buf);
1643c260e60Schristos 
1653c260e60Schristos 	return node;
1663c260e60Schristos }
1673c260e60Schristos 
1683c260e60Schristos 
node_to_file(struct xml_node_ctx * ctx,const char * fname,xml_node_t * node)1693c260e60Schristos int node_to_file(struct xml_node_ctx *ctx, const char *fname, xml_node_t *node)
1703c260e60Schristos {
1713c260e60Schristos 	FILE *f;
1723c260e60Schristos 	char *str;
1733c260e60Schristos 
1743c260e60Schristos 	str = xml_node_to_str(ctx, node);
1753c260e60Schristos 	if (str == NULL)
1763c260e60Schristos 		return -1;
1773c260e60Schristos 
1783c260e60Schristos 	f = fopen(fname, "w");
1793c260e60Schristos 	if (!f) {
1803c260e60Schristos 		os_free(str);
1813c260e60Schristos 		return -1;
1823c260e60Schristos 	}
1833c260e60Schristos 
1843c260e60Schristos 	fprintf(f, "%s\n", str);
1853c260e60Schristos 	os_free(str);
1863c260e60Schristos 	fclose(f);
1873c260e60Schristos 
1883c260e60Schristos 	return 0;
1893c260e60Schristos }
1903c260e60Schristos 
1913c260e60Schristos 
get_val(struct xml_node_ctx * ctx,xml_node_t * node)1923c260e60Schristos static char * get_val(struct xml_node_ctx *ctx, xml_node_t *node)
1933c260e60Schristos {
1943c260e60Schristos 	char *val, *pos;
1953c260e60Schristos 
1963c260e60Schristos 	val = xml_node_get_text(ctx, node);
1973c260e60Schristos 	if (val == NULL)
1983c260e60Schristos 		return NULL;
1993c260e60Schristos 	pos = val;
2003c260e60Schristos 	while (*pos) {
2013c260e60Schristos 		if (*pos != ' ' && *pos != '\t' && *pos != '\r' && *pos != '\n')
2023c260e60Schristos 			return val;
2033c260e60Schristos 		pos++;
2043c260e60Schristos 	}
2053c260e60Schristos 
2063c260e60Schristos 	return NULL;
2073c260e60Schristos }
2083c260e60Schristos 
2093c260e60Schristos 
add_path(const char * prev,const char * leaf)2103c260e60Schristos static char * add_path(const char *prev, const char *leaf)
2113c260e60Schristos {
2123c260e60Schristos 	size_t len;
2133c260e60Schristos 	char *new_uri;
2143c260e60Schristos 
2153c260e60Schristos 	if (prev == NULL)
2163c260e60Schristos 		return NULL;
2173c260e60Schristos 
2183c260e60Schristos 	len = os_strlen(prev) + 1 + os_strlen(leaf) + 1;
2193c260e60Schristos 	new_uri = os_malloc(len);
2203c260e60Schristos 	if (new_uri)
2213c260e60Schristos 		os_snprintf(new_uri, len, "%s/%s", prev, leaf);
2223c260e60Schristos 
2233c260e60Schristos 	return new_uri;
2243c260e60Schristos }
2253c260e60Schristos 
2263c260e60Schristos 
node_to_tnds(struct xml_node_ctx * ctx,xml_node_t * out,xml_node_t * in,const char * uri)2273c260e60Schristos static void node_to_tnds(struct xml_node_ctx *ctx, xml_node_t *out,
2283c260e60Schristos 			 xml_node_t *in, const char *uri)
2293c260e60Schristos {
2303c260e60Schristos 	xml_node_t *node;
2313c260e60Schristos 	xml_node_t *tnds;
2323c260e60Schristos 	const char *name;
2333c260e60Schristos 	char *val;
2343c260e60Schristos 	char *new_uri;
2353c260e60Schristos 
2363c260e60Schristos 	xml_node_for_each_child(ctx, node, in) {
2373c260e60Schristos 		xml_node_for_each_check(ctx, node);
2383c260e60Schristos 		name = xml_node_get_localname(ctx, node);
2393c260e60Schristos 
2403c260e60Schristos 		tnds = xml_node_create(ctx, out, NULL, "Node");
2413c260e60Schristos 		if (tnds == NULL)
2423c260e60Schristos 			return;
2433c260e60Schristos 		xml_node_create_text(ctx, tnds, NULL, "NodeName", name);
2443c260e60Schristos 
2453c260e60Schristos 		if (uri)
2463c260e60Schristos 			xml_node_create_text(ctx, tnds, NULL, "Path", uri);
2473c260e60Schristos 
2483c260e60Schristos 		val = get_val(ctx, node);
249*0a73ee0aSchristos 		if (val || !xml_node_first_child(ctx, node))
250*0a73ee0aSchristos 			xml_node_create_text(ctx, tnds, NULL, "Value",
251*0a73ee0aSchristos 					     val ? val : "");
2523c260e60Schristos 		xml_node_get_text_free(ctx, val);
2533c260e60Schristos 
2543c260e60Schristos 		new_uri = add_path(uri, name);
2553c260e60Schristos 		node_to_tnds(ctx, new_uri ? out : tnds, node, new_uri);
2563c260e60Schristos 		os_free(new_uri);
2573c260e60Schristos 	}
2583c260e60Schristos }
2593c260e60Schristos 
2603c260e60Schristos 
add_ddfname(struct xml_node_ctx * ctx,xml_node_t * parent,const char * urn)2613c260e60Schristos static int add_ddfname(struct xml_node_ctx *ctx, xml_node_t *parent,
2623c260e60Schristos 		       const char *urn)
2633c260e60Schristos {
2643c260e60Schristos 	xml_node_t *node;
2653c260e60Schristos 
2663c260e60Schristos 	node = xml_node_create(ctx, parent, NULL, "RTProperties");
2673c260e60Schristos 	if (node == NULL)
2683c260e60Schristos 		return -1;
2693c260e60Schristos 	node = xml_node_create(ctx, node, NULL, "Type");
2703c260e60Schristos 	if (node == NULL)
2713c260e60Schristos 		return -1;
2723c260e60Schristos 	xml_node_create_text(ctx, node, NULL, "DDFName", urn);
2733c260e60Schristos 	return 0;
2743c260e60Schristos }
2753c260e60Schristos 
2763c260e60Schristos 
mo_to_tnds(struct xml_node_ctx * ctx,xml_node_t * mo,int use_path,const char * urn,const char * ns_uri)2773c260e60Schristos xml_node_t * mo_to_tnds(struct xml_node_ctx *ctx, xml_node_t *mo,
2783c260e60Schristos 			int use_path, const char *urn, const char *ns_uri)
2793c260e60Schristos {
2803c260e60Schristos 	xml_node_t *root;
2813c260e60Schristos 	xml_node_t *node;
2823c260e60Schristos 	const char *name;
2833c260e60Schristos 
2843c260e60Schristos 	root = xml_node_create_root(ctx, ns_uri, NULL, NULL, "MgmtTree");
2853c260e60Schristos 	if (root == NULL)
2863c260e60Schristos 		return NULL;
2873c260e60Schristos 
2883c260e60Schristos 	xml_node_create_text(ctx, root, NULL, "VerDTD", "1.2");
2893c260e60Schristos 
2903c260e60Schristos 	name = xml_node_get_localname(ctx, mo);
2913c260e60Schristos 
2923c260e60Schristos 	node = xml_node_create(ctx, root, NULL, "Node");
2933c260e60Schristos 	if (node == NULL)
2943c260e60Schristos 		goto fail;
2953c260e60Schristos 	xml_node_create_text(ctx, node, NULL, "NodeName", name);
2963c260e60Schristos 	if (urn)
2973c260e60Schristos 		add_ddfname(ctx, node, urn);
2983c260e60Schristos 
2993c260e60Schristos 	node_to_tnds(ctx, use_path ? root : node, mo, use_path ? name : NULL);
3003c260e60Schristos 
3013c260e60Schristos 	return root;
3023c260e60Schristos 
3033c260e60Schristos fail:
3043c260e60Schristos 	xml_node_free(ctx, root);
3053c260e60Schristos 	return NULL;
3063c260e60Schristos }
3073c260e60Schristos 
3083c260e60Schristos 
get_first_child_node(struct xml_node_ctx * ctx,xml_node_t * node,const char * name)3093c260e60Schristos static xml_node_t * get_first_child_node(struct xml_node_ctx *ctx,
3103c260e60Schristos 					 xml_node_t *node,
3113c260e60Schristos 					 const char *name)
3123c260e60Schristos {
3133c260e60Schristos 	const char *lname;
3143c260e60Schristos 	xml_node_t *child;
3153c260e60Schristos 
3163c260e60Schristos 	xml_node_for_each_child(ctx, child, node) {
3173c260e60Schristos 		xml_node_for_each_check(ctx, child);
3183c260e60Schristos 		lname = xml_node_get_localname(ctx, child);
3193c260e60Schristos 		if (os_strcasecmp(lname, name) == 0)
3203c260e60Schristos 			return child;
3213c260e60Schristos 	}
3223c260e60Schristos 
3233c260e60Schristos 	return NULL;
3243c260e60Schristos }
3253c260e60Schristos 
3263c260e60Schristos 
get_node_text(struct xml_node_ctx * ctx,xml_node_t * node,const char * node_name)3273c260e60Schristos static char * get_node_text(struct xml_node_ctx *ctx, xml_node_t *node,
3283c260e60Schristos 			    const char *node_name)
3293c260e60Schristos {
3303c260e60Schristos 	node = get_first_child_node(ctx, node, node_name);
3313c260e60Schristos 	if (node == NULL)
3323c260e60Schristos 		return NULL;
3333c260e60Schristos 	return xml_node_get_text(ctx, node);
3343c260e60Schristos }
3353c260e60Schristos 
3363c260e60Schristos 
add_mo_node(struct xml_node_ctx * ctx,xml_node_t * root,xml_node_t * node,const char * uri)3373c260e60Schristos static xml_node_t * add_mo_node(struct xml_node_ctx *ctx, xml_node_t *root,
3383c260e60Schristos 				xml_node_t *node, const char *uri)
3393c260e60Schristos {
3403c260e60Schristos 	char *nodename, *value, *path;
3413c260e60Schristos 	xml_node_t *parent;
3423c260e60Schristos 
3433c260e60Schristos 	nodename = get_node_text(ctx, node, "NodeName");
3443c260e60Schristos 	if (nodename == NULL)
3453c260e60Schristos 		return NULL;
3463c260e60Schristos 	value = get_node_text(ctx, node, "Value");
3473c260e60Schristos 
3483c260e60Schristos 	if (root == NULL) {
3493c260e60Schristos 		root = xml_node_create_root(ctx, NULL, NULL, NULL,
3503c260e60Schristos 					    nodename);
3513c260e60Schristos 		if (root && value)
3523c260e60Schristos 			xml_node_set_text(ctx, root, value);
3533c260e60Schristos 	} else {
3543c260e60Schristos 		if (uri == NULL) {
3553c260e60Schristos 			xml_node_get_text_free(ctx, nodename);
3563c260e60Schristos 			xml_node_get_text_free(ctx, value);
3573c260e60Schristos 			return NULL;
3583c260e60Schristos 		}
3593c260e60Schristos 		path = get_node_text(ctx, node, "Path");
3603c260e60Schristos 		if (path)
3613c260e60Schristos 			uri = path;
3623c260e60Schristos 		parent = get_node_uri(ctx, root, uri);
3633c260e60Schristos 		xml_node_get_text_free(ctx, path);
3643c260e60Schristos 		if (parent == NULL) {
3653c260e60Schristos 			printf("Could not find URI '%s'\n", uri);
3663c260e60Schristos 			xml_node_get_text_free(ctx, nodename);
3673c260e60Schristos 			xml_node_get_text_free(ctx, value);
3683c260e60Schristos 			return NULL;
3693c260e60Schristos 		}
3703c260e60Schristos 		if (value)
3713c260e60Schristos 			xml_node_create_text(ctx, parent, NULL, nodename,
3723c260e60Schristos 					     value);
3733c260e60Schristos 		else
3743c260e60Schristos 			xml_node_create(ctx, parent, NULL, nodename);
3753c260e60Schristos 	}
3763c260e60Schristos 
3773c260e60Schristos 	xml_node_get_text_free(ctx, nodename);
3783c260e60Schristos 	xml_node_get_text_free(ctx, value);
3793c260e60Schristos 
3803c260e60Schristos 	return root;
3813c260e60Schristos }
3823c260e60Schristos 
3833c260e60Schristos 
tnds_to_mo_iter(struct xml_node_ctx * ctx,xml_node_t * root,xml_node_t * node,const char * uri)3843c260e60Schristos static xml_node_t * tnds_to_mo_iter(struct xml_node_ctx *ctx, xml_node_t *root,
3853c260e60Schristos 				    xml_node_t *node, const char *uri)
3863c260e60Schristos {
3873c260e60Schristos 	xml_node_t *child;
3883c260e60Schristos 	const char *name;
3893c260e60Schristos 	char *nodename;
3903c260e60Schristos 
3913c260e60Schristos 	xml_node_for_each_sibling(ctx, node) {
3923c260e60Schristos 		xml_node_for_each_check(ctx, node);
3933c260e60Schristos 
3943c260e60Schristos 		nodename = get_node_text(ctx, node, "NodeName");
3953c260e60Schristos 		if (nodename == NULL)
3963c260e60Schristos 			return NULL;
3973c260e60Schristos 
3983c260e60Schristos 		name = xml_node_get_localname(ctx, node);
3993c260e60Schristos 		if (strcmp(name, "Node") == 0) {
4003c260e60Schristos 			if (root && !uri) {
4013c260e60Schristos 				printf("Invalid TNDS tree structure - "
4023c260e60Schristos 				       "multiple top level nodes\n");
4033c260e60Schristos 				xml_node_get_text_free(ctx, nodename);
4043c260e60Schristos 				return NULL;
4053c260e60Schristos 			}
4063c260e60Schristos 			root = add_mo_node(ctx, root, node, uri);
4073c260e60Schristos 		}
4083c260e60Schristos 
4093c260e60Schristos 		child = get_first_child_node(ctx, node, "Node");
4103c260e60Schristos 		if (child) {
4113c260e60Schristos 			if (uri == NULL)
4123c260e60Schristos 				tnds_to_mo_iter(ctx, root, child, nodename);
4133c260e60Schristos 			else {
4143c260e60Schristos 				char *new_uri;
4153c260e60Schristos 				new_uri = add_path(uri, nodename);
4163c260e60Schristos 				tnds_to_mo_iter(ctx, root, child, new_uri);
4173c260e60Schristos 				os_free(new_uri);
4183c260e60Schristos 			}
4193c260e60Schristos 		}
4203c260e60Schristos 		xml_node_get_text_free(ctx, nodename);
4213c260e60Schristos 	}
4223c260e60Schristos 
4233c260e60Schristos 	return root;
4243c260e60Schristos }
4253c260e60Schristos 
4263c260e60Schristos 
tnds_to_mo(struct xml_node_ctx * ctx,xml_node_t * tnds)4273c260e60Schristos xml_node_t * tnds_to_mo(struct xml_node_ctx *ctx, xml_node_t *tnds)
4283c260e60Schristos {
4293c260e60Schristos 	const char *name;
4303c260e60Schristos 	xml_node_t *node;
4313c260e60Schristos 
4323c260e60Schristos 	name = xml_node_get_localname(ctx, tnds);
4333c260e60Schristos 	if (name == NULL || os_strcmp(name, "MgmtTree") != 0)
4343c260e60Schristos 		return NULL;
4353c260e60Schristos 
4363c260e60Schristos 	node = get_first_child_node(ctx, tnds, "Node");
4373c260e60Schristos 	if (!node)
4383c260e60Schristos 		return NULL;
4393c260e60Schristos 	return tnds_to_mo_iter(ctx, NULL, node, NULL);
4403c260e60Schristos }
4413c260e60Schristos 
4423c260e60Schristos 
soap_build_envelope(struct xml_node_ctx * ctx,xml_node_t * node)4433c260e60Schristos xml_node_t * soap_build_envelope(struct xml_node_ctx *ctx, xml_node_t *node)
4443c260e60Schristos {
4453c260e60Schristos 	xml_node_t *envelope, *body;
4463c260e60Schristos 	xml_namespace_t *ns;
4473c260e60Schristos 
4483c260e60Schristos 	envelope = xml_node_create_root(
4493c260e60Schristos 		ctx, "http://www.w3.org/2003/05/soap-envelope", "soap12", &ns,
4503c260e60Schristos 		"Envelope");
4513c260e60Schristos 	if (envelope == NULL)
4523c260e60Schristos 		return NULL;
4533c260e60Schristos 	body = xml_node_create(ctx, envelope, ns, "Body");
4543c260e60Schristos 	xml_node_add_child(ctx, body, node);
4553c260e60Schristos 	return envelope;
4563c260e60Schristos }
4573c260e60Schristos 
4583c260e60Schristos 
soap_get_body(struct xml_node_ctx * ctx,xml_node_t * soap)4593c260e60Schristos xml_node_t * soap_get_body(struct xml_node_ctx *ctx, xml_node_t *soap)
4603c260e60Schristos {
4613c260e60Schristos 	xml_node_t *body, *child;
4623c260e60Schristos 
4633c260e60Schristos 	body = get_node_uri(ctx, soap, "Envelope/Body");
4643c260e60Schristos 	if (body == NULL)
4653c260e60Schristos 		return NULL;
4663c260e60Schristos 	xml_node_for_each_child(ctx, child, body) {
4673c260e60Schristos 		xml_node_for_each_check(ctx, child);
4683c260e60Schristos 		return child;
4693c260e60Schristos 	}
4703c260e60Schristos 	return NULL;
4713c260e60Schristos }
472