#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cx/utils.h>
#include <cx/printf.h>
#include "xml.h"
static DavXmlNodeType convert_type(xmlElementType type) {
DavXmlNodeType ct;
switch(type) {
default: ct =
DAV_XML_NONE;
break;
case XML_ELEMENT_NODE: ct =
DAV_XML_ELEMENT;
break;
case XML_TEXT_NODE: ct =
DAV_XML_TEXT;
}
return ct;
}
typedef struct {
xmlNode *node;
DavXmlNode *parent;
} ConvXmlElm;
DavXmlNode* dav_convert_xml(DavSession *sn, xmlNode *node) {
if(!node) {
return NULL;
}
DavXmlNodeType newnt = convert_type(node->type);
if(newnt ==
DAV_XML_NONE) {
return NULL;
}
const CxAllocator *a = sn->mp->allocator;
ConvXmlElm ce;
ce.node = node;
ce.parent =
NULL;
CxList *stack = cxLinkedListCreate(cxDefaultAllocator,
NULL,
sizeof(ConvXmlElm));
if(!stack) {
return NULL;
}
cxListInsert(stack,
0, &ce);
DavXmlNode *ret =
NULL;
while(cxListSize(stack) >
0) {
ConvXmlElm *c = cxListAt(stack,
0);
xmlNode *n = c->node;
DavXmlNode *c_parent = c->parent;
DavXmlNode *prev =
NULL;
cxListRemove(stack,
0);
while(n) {
DavXmlNode *newxn = cxCalloc(a,
1,
sizeof(DavXmlNode));
if(!ret) {
ret = newxn;
}
newxn->type = convert_type(n->type);
newxn->parent = c_parent;
if(c_parent && !c_parent->children) {
c_parent->children = newxn;
}
newxn->prev = prev;
if(prev) {
prev->next = newxn;
}
if(newxn->type ==
DAV_XML_ELEMENT) {
newxn->name = dav_session_strdup(sn, (
char*)n->name);
if(n->ns && n->ns->href) {
newxn->namespace = dav_session_strdup(sn, (
char*)n->ns->href);
}
xmlAttr *attr = n->properties;
DavXmlAttr *newattr =
NULL;
DavXmlAttr *newattr_last =
NULL;
while(attr) {
DavXmlAttr *na = cxCalloc(a,
1,
sizeof(DavXmlAttr));
na->name = dav_session_strdup(sn, (
char*)attr->name);
if(attr->children && attr->children->type ==
XML_TEXT_NODE) {
na->value = dav_session_strdup(sn, (
char*)attr->children->content);
}
if(!newattr) {
newattr = na;
}
else {
newattr_last->next = na;
}
newattr_last = na;
attr = attr->next;
}
newxn->attributes = newattr;
if(n->children) {
ConvXmlElm convc;
convc.node = n->children;
convc.parent = newxn;
cxListInsert(stack,
0, &convc);
}
}
else if(newxn->type ==
DAV_XML_TEXT) {
cxmutstr content = cx_strdup_a(a, cx_str((
char*)n->content));
newxn->content = content.ptr;
newxn->contentlength = content.length;
}
prev = newxn;
n = n->next;
}
}
return ret;
}
void dav_print_xml(DavXmlNode *node) {
if(node->type ==
DAV_XML_ELEMENT) {
printf(
"<%s", node->name);
DavXmlAttr *attr = node->attributes;
while(attr) {
printf(
" %s=\"%s\"", attr->name, attr->value);
attr = attr->next;
}
putchar(
'>');
DavXmlNode *child = node->children;
if(child) {
dav_print_xml(child);
}
printf(
"</%s>", node->name);
}
else {
fwrite(node->content,
1, node->contentlength, stdout);
fflush(stdout);
}
if(node->next) {
dav_print_xml(node->next);
}
}
void dav_print_node(
void *stream, cx_write_func writef, CxMap *nsmap, DavXmlNode *node) {
while(node) {
if(node->type ==
DAV_XML_ELEMENT) {
char *tagend = node->children ?
">" :
" />";
char *prefix =
NULL;
char *prefix_fr =
NULL;
if(node->namespace) {
prefix = cxMapGet(nsmap, cx_hash_key_str(node->namespace));
if(!prefix) {
cxmutstr newpre = cx_asprintf(
"x%zu", cxMapSize(nsmap)+
1);
prefix = newpre.ptr;
prefix_fr = prefix;
cx_fprintf(
stream,
writef,
"<%s:%s xmlns:%s=\"%s\"",
prefix,
node->name,
prefix,
node->namespace);
}
else {
cx_fprintf(stream, writef,
"<%s:%s", prefix, node->name);
}
}
else {
cx_fprintf(stream, writef,
"<%s", node->name);
}
DavXmlAttr *attr = node->attributes;
while(attr) {
cx_fprintf(stream, writef,
" %s=\"%s\"", attr->name, attr->value);
attr = attr->next;
}
writef(tagend,
1, strlen(tagend), stream);
if(node->children) {
dav_print_node(stream, writef, nsmap, node->children);
if(prefix) {
cx_fprintf(stream, writef,
"</%s:%s>", prefix, node->name);
}
else {
cx_fprintf(stream, writef,
"</%s>", node->name);
}
}
if(prefix_fr) {
free(prefix_fr);
}
}
else if(node->type ==
DAV_XML_TEXT) {
writef(node->content,
1, node->contentlength, stream);
}
node = node->next;
}
}
char* dav_xml_getstring(DavXmlNode *node) {
if(node && node->type ==
DAV_XML_TEXT) {
return node->content;
}
else {
return NULL;
}
}
DavBool dav_xml_isstring(DavXmlNode *node) {
if(node && node->type ==
DAV_XML_TEXT && !node->next) {
return TRUE;
}
else {
return FALSE;
}
}
DavXmlNode* dav_xml_nextelm(DavXmlNode *node) {
node = node->next;
while(node) {
if(node->type ==
DAV_XML_ELEMENT) {
return node;
}
node = node->next;
}
return NULL;
}
DavXmlNode* dav_text_node(DavSession *sn,
const char *text) {
const CxAllocator *a = sn->mp->allocator;
DavXmlNode *newxn = cxCalloc(a,
1,
sizeof(DavXmlNode));
newxn->type =
DAV_XML_TEXT;
cxmutstr content = cx_strdup_a(a, cx_str(text));
newxn->content = content.ptr;
newxn->contentlength = content.length;
return newxn;
}
DavXmlNode* dav_text_element(DavSession *sn,
const char *ns,
const char *name,
const char *text) {
const CxAllocator *a = sn->mp->allocator;
DavXmlNode *newelm = cxCalloc(a,
1,
sizeof(DavXmlNode));
newelm->type =
DAV_XML_ELEMENT;
newelm->namespace = cx_strdup_a(a, cx_str(ns)).ptr;
newelm->name = cx_strdup_a(a, cx_str(name)).ptr;
newelm->children = dav_text_node(sn, text);
return newelm;
}
static void dav_free_xml_node_a(
const CxAllocator *a, DavXmlNode *node) {
if(node->name) cxFree(a, node->name);
if(node->namespace) cxFree(a, node->namespace);
if(node->content) cxFree(a, node->content);
DavXmlAttr *attr = node->attributes;
while(attr) {
if(attr->name) cxFree(a, attr->name);
if(attr->value) cxFree(a, attr->value);
attr = attr->next;
}
DavXmlNode *children = node->children;
while(children) {
DavXmlNode *next_ch = children->next;
dav_free_xml_node_a(a, children);
children = next_ch;
}
cxFree(a, node);
}
void dav_free_xml_node_sn(DavSession *sn, DavXmlNode *node) {
dav_free_xml_node_a(sn->mp->allocator, node);
}
void dav_free_xml_node(DavXmlNode *node) {
dav_free_xml_node_a(cxDefaultAllocator, node);
}
DavXmlAttr* dav_copy_xml_attr(DavXmlAttr *attr) {
if(!attr) {
return NULL;
}
DavXmlAttr *newattr =
NULL;
DavXmlAttr *prev =
NULL;
while(attr) {
DavXmlAttr *n = calloc(
1,
sizeof(DavXmlAttr));
n->name = strdup(attr->name);
n->value = strdup(attr->value);
if(prev) {
prev->next = n;
}
else {
newattr = n;
}
prev = n;
attr = attr->next;
}
return newattr;
}
DavXmlNode* dav_copy_node(DavXmlNode *node) {
DavXmlNode *ret =
NULL;
DavXmlNode *prev =
NULL;
while(node) {
DavXmlNode *copy = calloc(
1,
sizeof(DavXmlNode));
copy->type = node->type;
if(node->type ==
DAV_XML_ELEMENT) {
copy->namespace = strdup(node->namespace);
copy->name = strdup(node->name);
copy->children = dav_copy_node(node->children);
copy->attributes = dav_copy_xml_attr(node->attributes);
}
else {
copy->contentlength = node->contentlength;
copy->content = malloc(node->contentlength+
1);
memcpy(copy->content, node->content, node->contentlength);
copy->content[copy->contentlength] =
0;
}
if(!ret) {
ret = copy;
}
if(prev) {
prev->next = copy;
copy->prev = prev;
}
prev = copy;
node = node->next;
}
return ret;
}
DavXmlNode* dav_xml_createnode(
const char *ns,
const char *name) {
DavXmlNode *node = calloc(
1,
sizeof(DavXmlNode));
node->type =
DAV_XML_ELEMENT;
node->namespace = strdup(ns);
node->name = strdup(name);
return node;
}
DavXmlNode* dav_xml_createnode_with_text(
const char *ns,
const char *name,
const char *text) {
DavXmlNode *node = calloc(
1,
sizeof(DavXmlNode));
node->type =
DAV_XML_ELEMENT;
node->namespace = strdup(ns);
node->name = strdup(name);
DavXmlNode *textnode = dav_xml_createtextnode(text);
node->children = textnode;
return node;
}
DavXmlNode* dav_xml_createtextnode(
const char *text) {
DavXmlNode *node = calloc(
1,
sizeof(DavXmlNode));
node->type =
DAV_XML_TEXT;
cxmutstr content = cx_strdup(cx_str((
char*)text));
node->content = content.ptr;
node->contentlength = content.length;
return node;
}
void dav_xml_add_child(DavXmlNode *node, DavXmlNode *child) {
DavXmlNode *last_child =
NULL;
DavXmlNode *c = node->children;
while(c) {
last_child = c;
c = c->next;
}
if(last_child) {
last_child->next = child;
child->prev = last_child;
}
else {
node->children = child;
}
}
void dav_xml_add_attr(DavXmlNode *node,
const char *name,
const char *value) {
DavXmlAttr *attr = calloc(
1,
sizeof(DavXmlAttr));
attr->name = strdup(name);
attr->value = strdup(value);
if(node->attributes) {
DavXmlAttr *end = node->attributes;
DavXmlAttr* last = end;
while(end) {
last = end;
end = end->next;
}
last->next = attr;
}
else {
node->attributes = attr;
}
}
char* dav_xml_get_attr(DavXmlNode *node,
const char *name) {
DavXmlAttr *attr = node->attributes;
while(attr) {
if(!strcmp(attr->name, name)) {
return attr->value;
}
attr = attr->next;
}
return NULL;
}
DavXmlNode* dav_parse_xml(DavSession *sn,
const char *str,
size_t len) {
xmlDoc *doc = xmlReadMemory(str, len,
NULL,
NULL,
0);
if(!doc) {
return NULL;
}
xmlNode *xml_root = xmlDocGetRootElement(doc);
if(!xml_root) {
xmlFreeDoc(doc);
return NULL;
}
DavXmlNode *x = dav_convert_xml(sn, xml_root);
xmlFreeDoc(doc);
return x;
}