/* Author: Alex Fang Tree Structure root root | ^ ^ child | | | parent parent v | | NULL<-prev-child1-next-><-prev-child2-next->NULL */ #include "platform/platform_stdlib.h" #include "FreeRTOS.h" #include "xml.h" static struct xml_node *_xml_new_element(char *prefix, char *name, char *uri, char *attr); char *xml_strstr(const char *str1, const char *str2) { char *a, *b; /* First scan quickly through the two strings looking for a * single-character match. When it's found, then compare the * rest of the substring. */ b = (char *)str2; if (*b == 0) { return (char *)str1; } for ( ; *str1 != 0; str1 += 1) { if (*str1 != *b) { continue; } a = (char *)str1; while (1) { if (*b == 0) { return (char *)str1; } if (*a++ != *b++) { break; } } b = (char *)str2; } return (char *) 0; } static void *xml_malloc(unsigned int size) { return pvPortMalloc(size); } void xml_free(void *buf) { vPortFree(buf); } static char *str_strip(char *str, unsigned int str_len) { char *front, *rear; char *strip = NULL; int strip_len; if(!str || (str_len <= 0)) return NULL; for(front = str; front < (str + str_len); front ++) if(*front != ' ') break; if(front == (str + str_len)) return NULL; for(rear = (str + str_len - 1); rear >= front; rear --) if(*rear != ' ') break; if(front == rear) { strip_len = 1; strip = (char *) xml_malloc(strip_len + 1); memcpy(strip, front, strip_len); strip[strip_len] = '\0'; } else { strip_len = rear + 1 - front; strip = (char *) xml_malloc(strip_len + 1); memcpy(strip, front, strip_len); strip[strip_len] = '\0'; } return strip; } /* TAG Format: * STag ::= '<' Name (S Attribute)* S? '>' * ETag ::= '' * EmptyElemTag ::= '<' Name (S Attribute)* S? '/>' */ static void _parse_tag(char *tag, char **prefix, char **name, char **uri, char **attr) { char *prefix_char, *ns_tag, *ns_front; int have_prefix = 0; int have_uri = 0; prefix_char = strchr(tag, ':'); if(prefix_char) { char *tag_sep = strchr(tag, ' '); if(!tag_sep) have_prefix = 1; else if(prefix_char < tag_sep) have_prefix = 1; } if(have_prefix) { *prefix = str_strip(tag, prefix_char - tag); ns_tag = (char *) xml_malloc(strlen(" xmlns:") + strlen(*prefix) + 1); sprintf(ns_tag, " xmlns:%s", *prefix); ns_front = xml_strstr(tag, ns_tag); xml_free(ns_tag); } else { *prefix = NULL; ns_tag = " xmlns"; ns_front = xml_strstr(tag, ns_tag); } if(ns_front) have_uri = 1; if(have_prefix && have_uri) { char *uri_front, *uri_rear, *tag_sep, ns_sep; int uri_len; tag_sep = strchr(prefix_char + 1, ' '); *name = str_strip(prefix_char + 1, tag_sep - (prefix_char + 1)); if(attr) *attr = str_strip(tag_sep, tag + strlen(tag) - tag_sep); if(*(strchr(ns_front, '=') + 1) == '\'') ns_sep = '\''; else ns_sep = '\"'; uri_front = strchr(ns_front, ns_sep) + 1; uri_rear = strchr(uri_front, ns_sep); uri_len = uri_rear - uri_front; *uri = (char *) xml_malloc(uri_len + 1); memcpy(*uri, uri_front, uri_len); (*uri)[uri_len] = '\0'; } else if(have_prefix) { char *tag_sep; *uri = NULL; tag_sep = strchr(prefix_char + 1, ' '); if(tag_sep) { *name = str_strip(prefix_char + 1, tag_sep - (prefix_char + 1)); if(attr) *attr = str_strip(tag_sep, tag + strlen(tag) - tag_sep); } else { *name = str_strip(prefix_char + 1, tag + strlen(tag) - (prefix_char + 1)); if(attr) *attr = NULL; } } else if(have_uri) { char *uri_front, *uri_rear, *tag_sep, ns_sep; int uri_len; tag_sep = strchr(tag, ' '); *name = str_strip(tag, tag_sep - tag); if(attr) *attr = str_strip(tag_sep, tag + strlen(tag) - tag_sep); if(*(strchr(ns_front, '=') + 1) == '\'') ns_sep = '\''; else ns_sep = '\"'; uri_front = strchr(ns_front, ns_sep) + 1; uri_rear = strchr(uri_front, ns_sep); uri_len = uri_rear - uri_front; *uri = (char *) xml_malloc(uri_len + 1); memcpy(*uri, uri_front, uri_len); (*uri)[uri_len] = '\0'; } else { char *tag_sep; *uri = NULL; tag_sep = strchr(tag, ' '); if(tag_sep) { *name = str_strip(tag, tag_sep - tag); if(attr) *attr = str_strip(tag_sep, tag + strlen(tag) - tag_sep); } else { *name = str_strip(tag, strlen(tag)); if(attr) *attr = NULL; } } } static void parse_tag(char *tag, char **prefix, char **name, char **uri) { _parse_tag(tag, prefix, name, uri, NULL); } int xml_doc_name(char *doc_buf, int doc_len, char **doc_prefix, char **doc_name, char **doc_uri) { char *xml_buf, *cur_pos, *tag_front, *tag_rear; char *start_tag, *end_tag1, *end_tag2; int tag_len, ret = -1; xml_buf = (char *) xml_malloc(doc_len + 1); memcpy(xml_buf, doc_buf, doc_len); xml_buf[doc_len] = '\0'; cur_pos = xml_buf; while(cur_pos < (xml_buf + doc_len)) { if((tag_front = strchr(cur_pos, '<')) != NULL) { tag_front ++; if((tag_rear = strchr(tag_front, '>')) != NULL) { char *prefix = NULL, *name = NULL, *uri = NULL; //Element without content if(*(tag_rear - 1) == '/') { tag_len = tag_rear - 1 - tag_front; start_tag = (char *) xml_malloc(tag_len + 1); memcpy(start_tag, tag_front, tag_len); start_tag[tag_len] = '\0'; parse_tag(start_tag, &prefix, &name, &uri); xml_free(start_tag); *doc_name = name; *doc_prefix = prefix; *doc_uri = uri; ret = 0; cur_pos = xml_buf + doc_len; } //Element with content else { tag_len = tag_rear - tag_front; start_tag = (char *) xml_malloc(tag_len + 1); memcpy(start_tag, tag_front, tag_len); start_tag[tag_len] = '\0'; parse_tag(start_tag, &prefix, &name, &uri); xml_free(start_tag); if(prefix) { end_tag1 = (char *) xml_malloc(strlen(prefix) + strlen(name) + 5); sprintf(end_tag1, "", prefix, name); end_tag2 = (char *) xml_malloc(strlen(prefix) + strlen(name) + 5); sprintf(end_tag2, "", name); end_tag2 = (char *) xml_malloc(strlen(name) + 4); sprintf(end_tag2, "')) != NULL) { char *doc_front, *doc_rear, *start_tag, *end_tag1, *end_tag2; char *prefix = NULL, *name = NULL, *uri = NULL, *attr = NULL; int tag_len; //Element without content if(*(tag_rear - 1) == '/') { doc_front = tag_rear + 1; tag_len = tag_rear - 1 - tag_front; start_tag = (char *) xml_malloc(tag_len + 1); memcpy(start_tag, tag_front, tag_len); start_tag[tag_len] = '\0'; _parse_tag(start_tag, &prefix, &name, &uri, &attr); node = _xml_new_element(prefix, name, uri, attr); if(root) { xml_add_child(root, node); cur_pos = doc_front; } else { root = node; cur_pos = xml_buf + doc_len; } } //Element with content else { doc_front = tag_rear + 1; tag_len = tag_rear - tag_front; start_tag = (char *) xml_malloc(tag_len + 1); memcpy(start_tag, tag_front, tag_len); start_tag[tag_len] = '\0'; _parse_tag(start_tag, &prefix, &name, &uri, &attr); if(prefix) { end_tag1 = (char *) xml_malloc(strlen(prefix) + strlen(name) + 5); sprintf(end_tag1, "", prefix, name); end_tag2 = (char *) xml_malloc(strlen(prefix) + strlen(name) + 5); sprintf(end_tag2, "", name); end_tag2 = (char *) xml_malloc(strlen(name) + 4); sprintf(end_tag2, "') + 1; } else { root = node; _xml_parse_doc(doc_front, doc_rear - doc_front, node); cur_pos = xml_buf + doc_len; } } else { cur_pos = doc_front; } xml_free(end_tag1); xml_free(end_tag2); } xml_free(start_tag); xml_free(name); if(prefix) xml_free(prefix); if(uri) xml_free(uri); if(attr) xml_free(attr); } else { if(root && !root->child && (strlen(cur_pos) > 0)) { node = xml_new_text(cur_pos); xml_add_child(root, node); } cur_pos = xml_buf + doc_len; } } else { if(root && !root->child && (strlen(cur_pos) > 0)) { node = xml_new_text(cur_pos); xml_add_child(root, node); } cur_pos = xml_buf + doc_len; } } xml_free(xml_buf); return root; } /* Note: xml_parse_doc can handle attribute only for namespace */ struct xml_node *xml_parse_doc(char *doc_buf, int doc_len, char *doc_prefix, char *doc_name, char *doc_uri) { struct xml_node *root = NULL; char *xml_buf, *start_tag, *end_tag, *empty_tag, *front, *rear; xml_buf = (char *) xml_malloc(doc_len + 1); memcpy(xml_buf, doc_buf, doc_len); xml_buf[doc_len] = '\0'; if(doc_prefix && doc_uri) { start_tag = (char *) xml_malloc(2 * strlen(doc_prefix) + strlen(doc_name) + strlen(doc_uri) + 14); sprintf(start_tag, "<%s:%s xmlns:%s=\"%s\">", doc_prefix, doc_name, doc_prefix, doc_uri); empty_tag = (char *) xml_malloc(2 * strlen(doc_prefix) + strlen(doc_name) + strlen(doc_uri) + 15); sprintf(empty_tag, "<%s:%s xmlns:%s=\"%s\"/>", doc_prefix, doc_name, doc_prefix, doc_uri); } else if(doc_prefix) { start_tag = (char *) xml_malloc(strlen(doc_prefix) + strlen(doc_name) + 4); sprintf(start_tag, "<%s:%s>", doc_prefix, doc_name); empty_tag = (char *) xml_malloc(strlen(doc_prefix) + strlen(doc_name) + 5); sprintf(empty_tag, "<%s:%s/>", doc_prefix, doc_name); } else if(doc_uri) { start_tag = (char *) xml_malloc(strlen(doc_name) + strlen(doc_uri) + 12); sprintf(start_tag, "<%s xmlns=\"%s\">", doc_name, doc_uri); empty_tag = (char *) xml_malloc(strlen(doc_name) + strlen(doc_uri) + 13); sprintf(empty_tag, "<%s xmlns=\"%s\"/>", doc_name, doc_uri); } else { start_tag = (char *) xml_malloc(strlen(doc_name) + 3); sprintf(start_tag, "<%s>", doc_name); empty_tag = (char *) xml_malloc(strlen(doc_name) + 4); sprintf(empty_tag, "<%s/>", doc_name); } if(doc_prefix) { end_tag = (char *) xml_malloc(strlen(doc_prefix) + strlen(doc_name) + 5); sprintf(end_tag, "", doc_prefix, doc_name); } else { end_tag = (char *) xml_malloc(strlen(doc_name) + 4); sprintf(end_tag, "", doc_name); } //Root element with content if((front = xml_strstr(xml_buf, start_tag)) != NULL) { front += strlen(start_tag); if((rear = xml_strstr(front, end_tag)) != NULL) { int xml_len = rear - front; root = xml_new_element(doc_prefix, doc_name, doc_uri); _xml_parse_doc(front, xml_len, root); } } //Root element without content else if((front = xml_strstr(xml_buf, empty_tag)) != NULL) { root = xml_new_element(doc_prefix, doc_name, doc_uri); } xml_free(start_tag); xml_free(end_tag); xml_free(empty_tag); xml_free(xml_buf); return root; } struct xml_node *xml_parse(char *doc_buf, int doc_len) { char *proc_inst, *comment, *pos, *prolog_end; /* Remove XML Prolog */ pos = doc_buf; while(pos < (doc_buf + doc_len)) { if((proc_inst = xml_strstr(pos, "') + 1; } else { proc_inst = pos; break; } } pos = doc_buf; while(pos < (doc_buf + doc_len)) { if((comment = xml_strstr(pos, "') + 1; } else { comment = pos; break; } } if(proc_inst > comment) prolog_end = proc_inst; else prolog_end = comment; return _xml_parse_doc(prolog_end, doc_buf + doc_len - prolog_end, NULL); } static struct xml_node *xml_new_node(void) { struct xml_node *node; node = (struct xml_node *) xml_malloc(sizeof(struct xml_node)); memset(node, 0, sizeof(struct xml_node)); return node; } static struct xml_node *_xml_new_element(char *prefix, char *name, char *uri, char *attr) { struct xml_node *node; node = xml_new_node(); node->name = (char *) xml_malloc(strlen(name) + 1); strcpy(node->name, name); if(prefix) { node->prefix = (char *) xml_malloc(strlen(prefix) + 1); strcpy(node->prefix, prefix); } if(uri) { node->uri = (char *) xml_malloc(strlen(uri) + 1); strcpy(node->uri, uri); } if(attr) { node->attr = (char *) xml_malloc(strlen(attr) + 1); strcpy(node->attr, attr); } return node; } struct xml_node *xml_new_element(char *prefix, char *name, char *uri) { struct xml_node *node; char *attr = NULL; if(prefix && uri) { attr = (char *) xml_malloc(strlen(prefix) + strlen(uri) + 10); sprintf(attr, "xmlns:%s=\"%s\"", prefix, uri); } else if(uri) { attr = (char *) xml_malloc(strlen(uri) + 9); sprintf(attr, "xmlns=\"%s\"", uri); } node = _xml_new_element(prefix, name, uri, attr); if(attr) xml_free(attr); return node; } struct xml_node *xml_new_text(char *text) { struct xml_node *node; char *text_buf; text_buf = (char *) xml_malloc(strlen(text) + 1); strcpy(text_buf, text); node = xml_new_node(); node->text = text_buf; return node; } int xml_is_element(struct xml_node *node) { int ret = 0; if((node->name != NULL) && (node->text == NULL)) ret = 1; return ret; } int xml_is_text(struct xml_node *node) { int ret = 0; if((node->name == NULL) && (node->text != NULL)) ret = 1; return ret; } static void _xml_copy_tree(struct xml_node *root, struct xml_node *parent) { struct xml_node *copy = NULL; if(xml_is_text(root)) { copy = xml_new_text(root->text); } else if(xml_is_element(root)) { struct xml_node *child = root->child; copy = _xml_new_element(root->prefix, root->name, root->uri, root->attr); while(child) { _xml_copy_tree(child, copy); child = child->next; } } if(copy) xml_add_child(parent, copy); } struct xml_node* xml_copy_tree(struct xml_node *root) { struct xml_node *copy = NULL; if(xml_is_text(root)) { copy = xml_new_text(root->text); } else if(xml_is_element(root)) { struct xml_node *child = root->child; copy = _xml_new_element(root->prefix, root->name, root->uri, root->attr); while(child) { _xml_copy_tree(child, copy); child = child->next; } } return copy; } void xml_delete_tree(struct xml_node *root) { if(root->name) xml_free(root->name); if(root->text) xml_free(root->text); if(root->prefix) xml_free(root->prefix); if(root->uri) xml_free(root->uri); if(root->attr) xml_free(root->attr); while(root->child) xml_delete_tree(root->child); if(root->prev) { root->prev->next = root->next; if(root->next) root->next->prev = root->prev; } else if(root->parent) { root->parent->child = root->next; if(root->next) root->next->prev = NULL; } xml_free(root); } void xml_add_child(struct xml_node *node, struct xml_node *child) { if(xml_is_element(node)) { if(node->child) { struct xml_node *last_child = node->child; while(last_child->next != NULL) last_child = last_child->next; last_child->next = child; child->prev = last_child; } else { node->child = child; } child->parent = node; } } void xml_clear_child(struct xml_node *node) { while(node->child) xml_delete_tree(node->child); } struct xml_node* xml_text_child(struct xml_node *node) { struct xml_node *child = NULL; if(node->child) { if(xml_is_text(node->child)) child = node->child; } return child; } void xml_set_text(struct xml_node *node, char *text) { if(xml_is_text(node)) { char *text_buf = (char *) xml_malloc(strlen(text) + 1); strcpy(text_buf, text); xml_free(node->text); node->text = text_buf; } } static void _xml_element_count(struct xml_node *root, char *name, int *count) { if(xml_is_element(root)) { struct xml_node *child = root->child; if(strcmp(root->name, name) == 0) { (*count) ++; } while(child) { _xml_element_count(child, name, count); child = child->next; } } } static int xml_element_count(struct xml_node *root, char *name) { int count = 0; _xml_element_count(root, name, &count); return count; } static void _xml_find_element(struct xml_node *root, char *name, struct xml_node_set *node_set) { if(xml_is_element(root)) { struct xml_node *child = root->child; if(strcmp(root->name, name) == 0) { node_set->node[node_set->count] = root; node_set->count ++; } while(child) { _xml_find_element(child, name, node_set); child = child->next; } } } struct xml_node_set* xml_find_element(struct xml_node *root, char *name) { struct xml_node_set *node_set = NULL; int node_count; node_set = (struct xml_node_set *) xml_malloc(sizeof(struct xml_node_set)); node_set->count = 0; node_count = xml_element_count(root, name); if(node_count) node_set->node = (struct xml_node **) xml_malloc(node_count * sizeof(struct xml_node *)); else node_set->node = NULL; _xml_find_element(root, name, node_set); return node_set; } static void _xml_path_count(struct xml_node *root, char *path, int *count) { if(xml_is_element(root)) { char *front = NULL, *rear = NULL; if((front = strchr(path, '/')) != NULL) { int prefix_len, name_len; char *prefix, *name, *prefix_char; int prefix_matched = 0, name_matched = 0; front ++; prefix_char = strchr(front, ':'); if((rear = strchr(front, '/')) != NULL) { if(prefix_char && (prefix_char < rear)) { prefix_len = prefix_char - front; prefix = (char *) xml_malloc(prefix_len + 1); memcpy(prefix, front, prefix_len); prefix[prefix_len] = '\0'; name_len = rear - (prefix_char + 1); name = (char *) xml_malloc(name_len + 1); memcpy(name, prefix_char + 1, name_len); name[name_len] = '\0'; } else { prefix = NULL; name_len = rear - front; name = (char *) xml_malloc(name_len + 1); memcpy(name, front, name_len); name[name_len] = '\0'; } if((!prefix && !root->prefix) || (prefix && root->prefix && (strcmp(root->prefix, prefix) == 0))) prefix_matched = 1; else prefix_matched = 0; if(strcmp(root->name, name) == 0) name_matched = 1; else name_matched = 0; if(prefix_matched && name_matched) { struct xml_node *child = root->child; while(child) { _xml_path_count(child, rear, count); child = child->next; } } } else { if(prefix_char) { prefix_len = prefix_char - front; prefix = (char *) xml_malloc(prefix_len + 1); memcpy(prefix, front, prefix_len); prefix[prefix_len] = '\0'; name_len = strlen(path) - (prefix_char + 1 - path); name = (char *) xml_malloc(name_len + 1); memcpy(name, prefix_char + 1, name_len); name[name_len] = '\0'; } else { prefix = NULL; name_len = strlen(path) - (front - path); name = (char *) xml_malloc(name_len + 1); memcpy(name, front, name_len); name[name_len] = '\0'; } if((!prefix && !root->prefix) || (prefix && root->prefix && (strcmp(root->prefix, prefix) == 0))) prefix_matched = 1; else prefix_matched = 0; if(strcmp(root->name, name) == 0) name_matched = 1; else name_matched = 0; if(prefix_matched && name_matched) (*count) ++; } if(prefix) xml_free(prefix); xml_free(name); } } } static int xml_path_count(struct xml_node *root, char *path) { int count = 0; _xml_path_count(root, path, &count); return count; } static void _xml_find_path(struct xml_node *root, char *path, struct xml_node_set *node_set) { if(xml_is_element(root)) { char *front = NULL, *rear = NULL; if((front = strchr(path, '/')) != NULL) { int prefix_len, name_len; char *prefix, *name, *prefix_char; int prefix_matched = 0, name_matched = 0; front ++; prefix_char = strchr(front, ':'); if((rear = strchr(front, '/')) != NULL) { if(prefix_char && (prefix_char < rear)) { prefix_len = prefix_char - front; prefix = (char *) xml_malloc(prefix_len + 1); memcpy(prefix, front, prefix_len); prefix[prefix_len] = '\0'; name_len = rear - (prefix_char + 1); name = (char *) xml_malloc(name_len + 1); memcpy(name, prefix_char + 1, name_len); name[name_len] = '\0'; } else { prefix = NULL; name_len = rear - front; name = (char *) xml_malloc(name_len + 1); memcpy(name, front, name_len); name[name_len] = '\0'; } if((!prefix && !root->prefix) || (prefix && root->prefix && (strcmp(root->prefix, prefix) == 0))) prefix_matched = 1; else prefix_matched = 0; if(strcmp(root->name, name) == 0) name_matched = 1; else name_matched = 0; if(prefix_matched && name_matched) { struct xml_node *child = root->child; while(child) { _xml_find_path(child, rear, node_set); child = child->next; } } } else { if(prefix_char) { prefix_len = prefix_char - front; prefix = (char *) xml_malloc(prefix_len + 1); memcpy(prefix, front, prefix_len); prefix[prefix_len] = '\0'; name_len = strlen(path) - (prefix_char + 1 - path); name = (char *) xml_malloc(name_len + 1); memcpy(name, prefix_char + 1, name_len); name[name_len] = '\0'; } else { prefix = NULL; name_len = strlen(path) - (front - path); name = (char *) xml_malloc(name_len + 1); memcpy(name, front, name_len); name[name_len] = '\0'; } if((!prefix && !root->prefix) || (prefix && root->prefix && (strcmp(root->prefix, prefix) == 0))) prefix_matched = 1; else prefix_matched = 0; if(strcmp(root->name, name) == 0) name_matched = 1; else name_matched = 0; if(prefix_matched && name_matched) { node_set->node[node_set->count] = root; node_set->count ++; } } if(prefix) xml_free(prefix); xml_free(name); } } } struct xml_node_set* xml_find_path(struct xml_node *root, char *path) { struct xml_node_set *node_set = NULL; int node_count; node_set = (struct xml_node_set *) xml_malloc(sizeof(struct xml_node_set)); node_set->count = 0; node_count = xml_path_count(root, path); if(node_count) node_set->node = (struct xml_node **) xml_malloc(node_count * sizeof(struct xml_node *)); else node_set->node = NULL; _xml_find_path(root, path, node_set); return node_set; } void xml_delete_set(struct xml_node_set *node_set) { if(node_set->node) xml_free(node_set->node); xml_free(node_set); } static int xml_tree_size(struct xml_node *root, int level, int space) { int size = 0; int next_level = (level)?(level + 1):0; if(xml_is_text(root)) { size += strlen(root->text); } else if(xml_is_element(root)) { int start_size, end_size; struct xml_node *child = root->child; int is_element_child = 0; if(root->prefix && root->attr) /* */ start_size = strlen(root->prefix) + strlen(root->name) + strlen(root->attr) + 4; else if(root->prefix) /* */ start_size = strlen(root->prefix) + strlen(root->name) + 3; else if(root->attr) /* */ start_size = strlen(root->name) + strlen(root->attr) + 3; else /* */ start_size = strlen(root->name) + 2; size += start_size; while(child) { if(((is_element_child = xml_is_element(child)) == 1) && level) { size ++; /* /n */ size += (level * space); /* space */ } size += xml_tree_size(child, next_level, space); child = child->next; } if(is_element_child && level) { size ++; /* /n */ size += ((level - 1) * space); /* space */ } if(root->prefix) /* */ end_size = strlen(root->prefix) + strlen(root->name) + 4; else /* */ end_size = strlen(root->name) + 3; size += end_size; } return size; } static void _xml_dump_tree(struct xml_node *root, char *xml_buf, int level, int space) { int next_level = (level)?(level + 1):0; if(xml_is_text(root)) { strcat(xml_buf, root->text); } else if(xml_is_element(root)) { struct xml_node *child = root->child; int is_element_child = 0; if(root->prefix && root->attr) { strcat(xml_buf, "<"); strcat(xml_buf, root->prefix); strcat(xml_buf, ":"); strcat(xml_buf, root->name); strcat(xml_buf, " "); strcat(xml_buf, root->attr); strcat(xml_buf, ">"); } else if(root->prefix) { strcat(xml_buf, "<"); strcat(xml_buf, root->prefix); strcat(xml_buf, ":"); strcat(xml_buf, root->name); strcat(xml_buf, ">"); } else if(root->attr) { strcat(xml_buf, "<"); strcat(xml_buf, root->name); strcat(xml_buf, " "); strcat(xml_buf, root->attr); strcat(xml_buf, ">"); } else { strcat(xml_buf, "<"); strcat(xml_buf, root->name); strcat(xml_buf, ">"); } while(child) { if(((is_element_child = xml_is_element(child)) == 1) && level) { char space_buf[11]; int i; strcat(xml_buf, "\n"); memset(space_buf, ' ', sizeof(space_buf)); space_buf[space] = '\0'; for(i = 0; i < level; i ++) strcat(xml_buf, space_buf); } _xml_dump_tree(child, xml_buf, next_level, space); child = child->next; } if(is_element_child && level) { char space_buf[11]; int i; strcat(xml_buf, "\n"); memset(space_buf, ' ', sizeof(space_buf)); space_buf[space] = '\0'; for(i = 0; i < (level - 1); i ++) strcat(xml_buf, space_buf); } if(root->prefix) { strcat(xml_buf, "prefix); strcat(xml_buf, ":"); strcat(xml_buf, root->name); strcat(xml_buf, ">"); } else { strcat(xml_buf, "name); strcat(xml_buf, ">"); } } } char *xml_dump_tree(struct xml_node *root) { int xml_size; char *xml_buf; xml_size = xml_tree_size(root, 0, 0); xml_buf = (char *) xml_malloc(xml_size + 1); memset(xml_buf, 0, xml_size + 1); _xml_dump_tree(root, xml_buf, 0, 0); return xml_buf; } char *xml_dump_tree_ex(struct xml_node *root, char *prolog, int new_line, int space) { int xml_size; char *xml_buf; /* Max offset of 10 for each level */ if(space > 10) space = 10; xml_size = xml_tree_size(root, 1, space); if(prolog && new_line) { xml_buf = (char *) xml_malloc(strlen(prolog) + xml_size + 2); memset(xml_buf, 0, strlen(prolog) + xml_size + 2); sprintf(xml_buf, "%s\n", prolog); _xml_dump_tree(root, xml_buf + strlen(prolog), new_line, space); } else if(prolog) { xml_buf = (char *) xml_malloc(strlen(prolog) + xml_size + 1); memset(xml_buf, 0, strlen(prolog) + xml_size + 1); strcpy(xml_buf, prolog); _xml_dump_tree(root, xml_buf + strlen(prolog), new_line, space); } else { xml_buf = (char *) xml_malloc(xml_size + 1); memset(xml_buf, 0, xml_size + 1); _xml_dump_tree(root, xml_buf, new_line, space); } return xml_buf; } void xml_set_attribute(struct xml_node *node, char *attr, char *value) { char *ns_tag, *new_attr; if(node->prefix) { ns_tag = (char *) xml_malloc(strlen("xmlns:") + strlen(node->prefix) + 1); sprintf(ns_tag, "xmlns:%s", node->prefix); if(strcmp(ns_tag, attr) == 0) { if(node->uri) xml_free(node->uri); node->uri = (char *) xml_malloc(strlen(value) + 1); strcpy(node->uri, value); } xml_free(ns_tag); } else { ns_tag = "xmlns"; if(strcmp(ns_tag, attr) == 0) { if(node->uri) xml_free(node->uri); node->uri = (char *) xml_malloc(strlen(value) + 1); strcpy(node->uri, value); } } /* attr="value" or attr='value' */ new_attr = (char *) xml_malloc(strlen(attr) + strlen(value) + 4); if(strchr(value, '\"')) sprintf(new_attr, "%s=\'%s\'", attr, value); else sprintf(new_attr, "%s=\"%s\"", attr, value); if(node->attr) { char *attr1, *attr2, *attr_pos, *all_attr, *attr_p1 = NULL, *attr_p2 = NULL; int attr_existed = 0; attr1 = (char *) xml_malloc(strlen(attr) + 4); sprintf(attr1, " %s=\'", attr); attr2 = (char *) xml_malloc(strlen(attr) + 4); sprintf(attr2, " %s=\"", attr); if(((attr_pos = xml_strstr(node->attr, attr1)) != NULL) || (xml_strstr(node->attr, attr1 + 1) == node->attr)) { attr_existed = 1; if(attr_pos) { attr_p1 = str_strip(node->attr, attr_pos - node->attr); attr_p2 = str_strip(strchr(attr_pos + strlen(attr1), '\'') + 1, node->attr + strlen(node->attr) - (strchr(attr_pos + strlen(attr1), '\'') + 1)); } else { attr_p1 = NULL; attr_p2 = str_strip(strchr(node->attr + strlen(attr1) - 1, '\'') + 1, node->attr + strlen(node->attr) - (strchr(node->attr + strlen(attr1) - 1, '\'') + 1)); } } else if(((attr_pos = xml_strstr(node->attr, attr2)) != NULL) || (xml_strstr(node->attr, attr2 + 1) == node->attr)) { attr_existed = 1; if(attr_pos) { attr_p1 = str_strip(node->attr, attr_pos - node->attr); attr_p2 = str_strip(strchr(attr_pos + strlen(attr2), '\"') + 1, node->attr + strlen(node->attr) - (strchr(attr_pos + strlen(attr2), '\"') + 1)); } else { attr_p1 = NULL; attr_p2 = str_strip(strchr(node->attr + strlen(attr2) - 1, '\"') + 1, node->attr + strlen(node->attr) - (strchr(node->attr + strlen(attr2) - 1, '\"') + 1)); } } if(attr_p1 && attr_p2) { all_attr = (char *) xml_malloc(strlen(attr_p1) + strlen(new_attr) + strlen(attr_p2) + 3); sprintf(all_attr, "%s %s %s", attr_p1, new_attr, attr_p2); } else if(attr_p1) { all_attr = (char *) xml_malloc(strlen(attr_p1) + strlen(new_attr) + 2); sprintf(all_attr, "%s %s", attr_p1, new_attr); } else if(attr_p2) { all_attr = (char *) xml_malloc(strlen(new_attr) + strlen(attr_p2) + 2); sprintf(all_attr, "%s %s", new_attr, attr_p2); } else if(attr_existed) { all_attr = (char *) xml_malloc(strlen(new_attr) + 1); sprintf(all_attr, "%s", new_attr); } else { all_attr = (char *) xml_malloc(strlen(node->attr) + strlen(new_attr) + 2); sprintf(all_attr, "%s %s", node->attr, new_attr); } xml_free(attr1); xml_free(attr2); if(attr_p1) xml_free(attr_p1); if(attr_p2) xml_free(attr_p2); xml_free(new_attr); xml_free(node->attr); node->attr = all_attr; } else { node->attr = new_attr; } } char *xml_get_attribute(struct xml_node *node, char *attr) { char *value = NULL; if(node->attr) { /* attr=' or attr=" */ char *value_front, *value_rear, *attr1, *attr2, *attr_pos; int value_len; attr1 = (char *) xml_malloc(strlen(attr) + 4); sprintf(attr1, " %s=\'", attr); attr2 = (char *) xml_malloc(strlen(attr) + 4); sprintf(attr2, " %s=\"", attr); if(((attr_pos = xml_strstr(node->attr, attr1)) != NULL) || (xml_strstr(node->attr, attr1 + 1) == node->attr)) { if(attr_pos) value_front = attr_pos + strlen(attr1); else value_front = node->attr + strlen(attr1) - 1; value_rear = strchr(value_front, '\''); value_len = value_rear - value_front; value = (char *) xml_malloc(value_len + 1); memcpy(value, value_front, value_len); value[value_len] = '\0'; } else if(((attr_pos = xml_strstr(node->attr, attr2)) != NULL) || (xml_strstr(node->attr, attr2 + 1) == node->attr)) { if(attr_pos) value_front = attr_pos + strlen(attr2); else value_front = node->attr + strlen(attr2) - 1; value_rear = strchr(value_front, '\"'); value_len = value_rear - value_front; value = (char *) xml_malloc(value_len + 1); memcpy(value, value_front, value_len); value[value_len] = '\0'; } xml_free(attr1); xml_free(attr2); } return value; }