RTL8710_SDK_GCC_VERSION/component/common/utilities/xml.c
RtlduinoMan 905d81784e GCC SDK RTL8710 basic version (including the window platform cygwin installation and Ubuntu platform Linux Installation routines),
including cross compilation of the installation, compile, link, run, debug, and so on.
SDK implementation of the function:
1, WiFi connection settings (including AP mode and STA mode).
2, peripheral resource control (including GPIO, SPI, UART, IIC, etc.).
3, the user uses the sample method.
2016-09-08 18:11:26 +08:00

1376 lines
34 KiB
C

/*
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 ::= '</' Name S? '>'
* 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, "</%s:%s>", prefix, name);
end_tag2 = (char *) xml_malloc(strlen(prefix) + strlen(name) + 5);
sprintf(end_tag2, "</%s:%s ", prefix, name);
}
else {
end_tag1 = (char *) xml_malloc(strlen(name) + 4);
sprintf(end_tag1, "</%s>", name);
end_tag2 = (char *) xml_malloc(strlen(name) + 4);
sprintf(end_tag2, "</%s ", name);
}
if(xml_strstr(tag_rear + 1, end_tag1) || xml_strstr(tag_rear + 1, end_tag2)) {
*doc_name = name;
*doc_prefix = prefix;
*doc_uri = uri;
ret = 0;
cur_pos = xml_buf + doc_len;
}
else {
xml_free(name);
if(prefix) xml_free(prefix);
if(uri) xml_free(uri);
cur_pos = tag_rear + 1;
}
xml_free(end_tag1);
xml_free(end_tag2);
}
}
else {
cur_pos = xml_buf + doc_len;
}
}
else {
cur_pos = xml_buf + doc_len;
}
}
xml_free(xml_buf);
return ret;
}
struct xml_node *_xml_parse_doc(char *doc_buf, int doc_len, struct xml_node *root)
{
char *xml_buf, *cur_pos;
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)) {
char *tag_front, *tag_rear;
struct xml_node *node;
if((tag_front = strchr(cur_pos, '<')) != NULL) {
tag_front ++;
if((tag_rear = strchr(tag_front, '>')) != 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, "</%s:%s>", prefix, name);
end_tag2 = (char *) xml_malloc(strlen(prefix) + strlen(name) + 5);
sprintf(end_tag2, "</%s:%s ", prefix, name);
}
else {
end_tag1 = (char *) xml_malloc(strlen(name) + 4);
sprintf(end_tag1, "</%s>", name);
end_tag2 = (char *) xml_malloc(strlen(name) + 4);
sprintf(end_tag2, "</%s ", name);
}
if(xml_strstr(doc_front, end_tag1))
doc_rear = xml_strstr(doc_front, end_tag1);
else if(xml_strstr(doc_front, end_tag2))
doc_rear = xml_strstr(doc_front, end_tag2);
else
doc_rear = NULL;
if(doc_rear) {
node = _xml_new_element(prefix, name, uri, attr);
if(root) {
xml_add_child(root, node);
_xml_parse_doc(doc_front, doc_rear - doc_front, node);
cur_pos = strchr(doc_rear, '>') + 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, "</%s:%s>", doc_prefix, doc_name);
}
else {
end_tag = (char *) xml_malloc(strlen(doc_name) + 4);
sprintf(end_tag, "</%s>", 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, "<?")) != NULL) {
pos = strchr(proc_inst, '>') + 1;
}
else {
proc_inst = pos;
break;
}
}
pos = doc_buf;
while(pos < (doc_buf + doc_len)) {
if((comment = xml_strstr(pos, "<!")) != NULL) {
pos = strchr(comment, '>') + 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)
/* <prefix:name attr> */
start_size = strlen(root->prefix) + strlen(root->name) + strlen(root->attr) + 4;
else if(root->prefix)
/* <prefix:name> */
start_size = strlen(root->prefix) + strlen(root->name) + 3;
else if(root->attr)
/* <name attr> */
start_size = strlen(root->name) + strlen(root->attr) + 3;
else
/* <name> */
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)
/* </prefix:name> */
end_size = strlen(root->prefix) + strlen(root->name) + 4;
else
/* </name> */
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, "</");
strcat(xml_buf, root->prefix);
strcat(xml_buf, ":");
strcat(xml_buf, root->name);
strcat(xml_buf, ">");
}
else {
strcat(xml_buf, "</");
strcat(xml_buf, root->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;
}