updated api docs
Revision 1.5 2001/09/29 21:58:05 danda
adding cvs log to history section
10/15/2000 -- danda -- adding robodoc documentation
TODO
Nicer external API. Get rid of macros. Make opaque types, etc.
PORTABILITY
Coded on RedHat Linux 6.2. Builds on Solaris x86. Should build on just
about anything with minor mods.
NOTES
This code incorporates ideas from expat-ensor from http://xml.ensor.org.
It was coded primarily to act as a go-between for expat and xmlrpc. To this
end, it stores xml elements, their sub-elements, and their attributes in an
in-memory tree. When expat is done parsing, the tree can be walked, thus
retrieving the values. The code can also be used to build a tree via API then
write out the tree to a buffer, thus "serializing" the xml.
It turns out this is useful for other purposes, such as parsing config files.
YMMV.
Some Features:
- output option for xml escaping data. Choices include no escaping, entity escaping,
or CDATA sections.
- output option for character encoding. Defaults to (none) utf-8.
- output option for verbosity/readability. ultra-compact, newlines, pretty/level indented.
BUGS
there must be some.
NAME
xml_elem_free
SYNOPSIS
void xml_elem_free(xml_element* root)
FUNCTION
free an xml element and all of its child elements
INPUTS
root - the root of an xml tree you would like to free
RESULT
void
NOTES
SEE ALSO
xml_elem_free_non_recurse ()
xml_elem_new ()
SOURCE
void xml_elem_free(xml_element* root) {
if(root) {
xml_element* kids = Q_Head(&root->children);
while(kids) {
xml_elem_free(kids);
kids = Q_Next(&root->children);
}
xml_elem_free_non_recurse(root);
}
}
NAME
xml_elem_free_non_recurse
SYNOPSIS
void xml_elem_free_non_recurse(xml_element* root)
FUNCTION
free a single xml element. child elements will not be freed.
INPUTS
root - the element to free
RESULT
void
NOTES
SEE ALSO
xml_elem_free ()
xml_elem_new ()
SOURCE
void xml_elem_free_non_recurse(xml_element* root) {
if(root) {
xml_element_attr* attrs = Q_Head(&root->attrs);
while(attrs) {
my_free(attrs->key);
my_free(attrs->val);
my_free(attrs);
attrs = Q_Next(&root->attrs);
}
Q_Destroy(&root->children);
Q_Destroy(&root->attrs);
my_free((char*)root->name);
simplestring_free(&root->text);
my_free(root);
}
}
NAME
xml_elem_new
SYNOPSIS
xml_element* xml_elem_new()
FUNCTION
allocates and initializes a new xml_element
INPUTS
none
RESULT
xml_element* or NULL. NULL indicates an out-of-memory condition.
NOTES
SEE ALSO
xml_elem_free ()
xml_elem_free_non_recurse ()
SOURCE
xml_element* xml_elem_new() {
xml_element* elem = calloc(1, sizeof(xml_element));
if(elem) {
Q_Init(&elem->children);
Q_Init(&elem->attrs);
simplestring_init(&elem->text);
/* init empty string in case we don't find any char data */
simplestring_addn(&elem->text, "", 0);
}
return elem;
}
NAME
xml_elem_parse_buf
SYNOPSIS
xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error)
FUNCTION
parse a buffer containing XML into an xml_element in-memory tree
INPUTS
in_buf - buffer containing XML document
len - length of buffer
options - input options. optional
error - error result data. optional. check if result is null.
RESULT
void
NOTES
The returned data must be free'd by caller
SEE ALSO
xml_elem_serialize_to_string ()
xml_elem_free ()
SOURCE
xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error)
{
xml_element* xReturn = NULL;
char buf[100] = "";
static STRUCT_XML_ELEM_INPUT_OPTIONS default_opts = {encoding_utf_8};
if(!options) {
options = &default_opts;
}
if(in_buf) {
XML_Parser parser;
xml_elem_data mydata = {0};
parser = XML_ParserCreate(NULL);
mydata.root = xml_elem_new();
mydata.current = mydata.root;
mydata.input_options = options;
mydata.needs_enc_conversion = options->encoding && strcmp(options->encoding, encoding_utf_8);
XML_SetElementHandler(parser, startElement, endElement);
XML_SetCharacterDataHandler(parser, charHandler);
/* pass the xml_elem_data struct along */
XML_SetUserData(parser, (void*)&mydata);
if(!len) {
len = strlen(in_buf);
}
/* parse the XML */
if(XML_Parse(parser, in_buf, len, 1) == 0) {
enum XML_Error err_code = XML_GetErrorCode(parser);
int line_num = XML_GetCurrentLineNumber(parser);
int col_num = XML_GetCurrentColumnNumber(parser);
long byte_idx = XML_GetCurrentByteIndex(parser);
int byte_total = XML_GetCurrentByteCount(parser);
const XML_LChar XMLPARSEAPI * error_str = XML_ErrorString(err_code);
if(byte_idx >= 0) {
snprintf(buf,
sizeof(buf),
"\n\tdata beginning %i before byte index: %s\n",
byte_idx > 10 ? 10 : byte_idx,
in_buf + (byte_idx > 10 ? byte_idx - 10 : byte_idx));
}
fprintf(stderr, "expat reports error code %i\n"
"\tdescription: %s\n"
"\tline: %i\n"
"\tcolumn: %i\n"
"\tbyte index: %i\n"
"\ttotal bytes: %i\n%s ",
err_code, error_str, line_num,
col_num, byte_idx, byte_total, buf);
/* error condition */
if(error) {
error->parser_code = (long)err_code;
error->line = line_num;
error->column = col_num;
error->byte_index = byte_idx;
error->parser_error = error_str;
}
}
else {
xReturn = (xml_element*)Q_Head(&mydata.root->children);
}
XML_ParserFree(parser);
xml_elem_free_non_recurse(mydata.root);
}
return xReturn;
}
NAME
xml_elem_serialize_to_stream
SYNOPSIS
void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options)
FUNCTION
writes element tree as XML into a stream (typically an opened file)
INPUTS
el - root element of tree
output - stream handle
options - options determining how output is written. see XML_ELEM_OUTPUT_OPTIONS
RESULT
void
NOTES
SEE ALSO
xml_elem_serialize_to_string ()
xml_elem_parse_buf ()
SOURCE
void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options)
{
xml_element_serialize(el, file_out_fptr, (void *)output, options, 0);
}
NAME
xml_elem_serialize_to_string
SYNOPSIS
void xml_element_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len)
FUNCTION
writes element tree as XML into a newly allocated buffer
INPUTS
el - root element of tree
options - options determining how output is written. see XML_ELEM_OUTPUT_OPTIONS
buf_len - length of returned buffer, if not null.
RESULT
char* or NULL. Must be free'd by caller.
NOTES
SEE ALSO
xml_elem_serialize_to_stream ()
xml_elem_parse_buf ()
SOURCE
char* xml_elem_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len)
{
simplestring buf;
simplestring_init(&buf);
xml_element_serialize(el, simplestring_out_fptr, (void *)&buf, options, 0);
if(buf_len) {
*buf_len = buf.len;
}
return buf.str;
}