diff --git a/CHANGES b/CHANGES index 2456a17..a5382d6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,12 +1,14 @@ -README - 06/07/2003 +README - 06/14/2003 ------------------- -CHANGES IN Mini-XML 0.94 +CHANGES IN Mini-XML 1.0 - The mxmldoc program now handles function arguments, structures, unions, enumerations, classes, and - typedefs properly. Finally some documentation... + typedefs properly. + - Documentation provided via mxmldoc and more in-line + comments in the code. CHANGES IN Mini-XML 0.93 diff --git a/documentation.html b/documentation.html index 9142a11..b141ea4 100644 --- a/documentation.html +++ b/documentation.html @@ -58,7 +58,7 @@
Local functions...
+Add a node to a tree.
void @@ -165,7 +165,7 @@ mxmlFindElement(Element node or NULL
mxmlLoadFile()
-mxml_node_t *Top nodeFILE *File to read frommxml_type_tCallback functionNew nodemxml_node_t *Create a new element node.mxml_node_t *Parent nodeconst char *Name of elementNew nodemxml_node_t *Create a new integer node.mxml_node_t *Parent nodeintInteger valueNew nodemxml_node_t *Create a new opaque string.mxml_node_t *Parent nodeconst char *Opaque stringNew nodemxml_node_t *Create a new real number node.mxml_node_t *Parent nodedoubleReal number valueNew nodemxml_node_t *Create a new text fragment node.mxml_node_t *Parent nodeintLeading whitespace?const char *StringRemove a node from its parent.mxml_node_t *Node to remove0 on success, -1 on errorintSave an XML tree to a file.mxml_node_t *Node to writeFILE *File to write tointWhitespace callbackNext node or NULLmxml_node_t *Walk to the next logical node in the tree.mxml_node_t *Current nodemxml_node_t *Top nodeintDescend into tree?Previous node or NULLmxml_node_t *Walk to the previous logical node in the tree.mxml_node_t *Current nodemxml_node_t *Top nodeintDescend into tree?Data types...char *Attribute namechar *Attribute valuestruct mxml_attr_sstruct mxml_value_smxml_node_t *First child nodemxml_node_t *Last child nodemxml_node_t *Next node under same parentmxml_node_t *Parent nodemxml_node_t *Previous node under same parentmxml_type_tNode typemxml_value_tNode valuechar *Fragment stringintLeading whitespace?struct mxml_text_sNode TypeXML element with attributesInteger valueOpaque stringReal valueText fragmentAttribute ValueElement ValueText ValueNode ValueNodeC++ support...Prototypes...C++ support...End of "$Id: documentation.html,v 1.3 2003/06/07 21:27:05 mike Exp $".enum mxml_type_emxml_attr_t *Attributeschar *Name of elementintNumber of attributesunion mxml_value_umxml_element_tElementintInteger numberchar *Opaque stringdoubleReal numbermxml_text_tText fragmentmxml_node_t *Current nodemxml_node_t *Parent nodeNode typeconst char *String to writeFile to write toint(*cb)(mxml_node_t *int) intWhere valueCurrent column
+Load a file into an XML node tree.
Syntax
mxml_node_t * @@ -183,7 +183,7 @@ mxmlLoadFile((*cb)(mxml_node_t *) Callback function Returns
-Local functions...
+First node
mxmlNewElement()
Create a new element node.
@@ -370,7 +370,7 @@ mxmlWalkPrev(
mxml_attr_s
-Data types...
+Attribute Value
Definition
struct mxml_attr_s @@ -388,7 +388,7 @@ struct mxml_attr_s
mxml_node_s
-mxml_node_t *First child nodemxml_node_t *Last child nodemxml_node_t *Next node under same parentmxml_node_t *Parent nodemxml_node_t *Previous node under same parentmxml_type_tNode typemxml_value_tNode valuechar *Fragment stringintLeading whitespace?struct mxml_text_sNode TypeXML element with attributesInteger valueOpaque stringReal valueText fragmentAttribute ValueElement ValueText ValueNode ValueNodeC++ support...Prototypes...C++ support...End of "$Id: documentation.html,v 1.3 2003/06/07 21:27:05 mike Exp $".enum mxml_type_emxml_attr_t *Attributeschar *Name of elementintNumber of attributesunion mxml_value_umxml_element_tElementintInteger numberchar *Opaque stringdoubleReal numbermxml_text_tText fragmentmxml_node_t *Current nodemxml_node_t *Parent nodeNode typeconst char *String to writeFile to write toint(*cb)(mxml_node_t *int) intWhere valueCurrent column
+Node
Definition
struct mxml_node_s @@ -416,7 +416,7 @@ struct mxml_node_s
mxml_text_s
-char *Fragment stringintLeading whitespace?struct mxml_text_sNode TypeXML element with attributesInteger valueOpaque stringReal valueText fragmentAttribute ValueElement ValueText ValueNode ValueNodeC++ support...Prototypes...C++ support...End of "$Id: documentation.html,v 1.3 2003/06/07 21:27:05 mike Exp $".enum mxml_type_emxml_attr_t *Attributeschar *Name of elementintNumber of attributesunion mxml_value_umxml_element_tElementintInteger numberchar *Opaque stringdoubleReal numbermxml_text_tText fragmentmxml_node_t *Current nodemxml_node_t *Parent nodeNode typeconst char *String to writeFile to write toint(*cb)(mxml_node_t *int) intWhere valueCurrent column
+Text Value
Definition
struct mxml_text_s @@ -434,7 +434,7 @@ struct mxml_text_s
mxml_value_s
-mxml_attr_t *Attributeschar *Name of elementintNumber of attributesunion mxml_value_umxml_element_tElementintInteger numberchar *Opaque stringdoubleReal numbermxml_text_tText fragmentmxml_node_t *Current nodemxml_node_t *Parent nodeNode typeconst char *String to writeFile to write toint(*cb)(mxml_node_t *int) intWhere valueCurrent column
+Element Value
Definition
struct mxml_value_s @@ -462,30 +462,35 @@ struct mxml_value_s
mxml_attr_t
+Attribute Value
Definition
typedef struct mxml_attr_s mxml_attr_t;
mxml_element_t
+Element Value
Definition
typedef struct mxml_value_s mxml_element_t;
mxml_text_t
+Text Value
Definition
typedef struct mxml_text_s mxml_text_t;
mxml_type_t
+Node Type
Definition
typedef enum mxml_type_e mxml_type_t;
mxml_value_t
+Node Value
Definition
typedef union mxml_value_u mxml_value_t; @@ -496,7 +501,7 @@ typedef union mxml_value_u mxml_value_t;
mxml_value_u
-mxml_element_tElementintInteger numberchar *Opaque stringdoubleReal numbermxml_text_tText fragmentmxml_node_t *Current nodemxml_node_t *Parent nodeNode typeconst char *String to writeFile to write toint(*cb)(mxml_node_t *int) intWhere valueCurrent column
+Node Value
Definition
struct mxml_value_u diff --git a/mxml.xml b/mxml.xml index 86e4970..499c8a7 100644 --- a/mxml.xml +++ b/mxml.xml @@ -1,6 +1,5 @@ -- FILE * File to write to Callback function - Local functions... Add a node to a tree. mxml_node_t * Parent node int Where to add @@ -30,9 +29,10 @@ direction="I"> mxml_node_t * Child node for where mxml_node_t * Current node <const char * Attribute value, or NULL for any int Descend into tree? - Local functions... mxml_node_t + @@ -90,14 +90,16 @@ name="node" direction="I"> - First node mxml_node_t * + mxml_node_t * Top node Load a file into an XML node tree. mxml_node_t * Top node FILE * File to read from mxml_type_t Callback function mxml_node_t * Current node mxml_node_t * Top node int Descend into tree? - Data types... Attribute Value char * Attribute name char * Attribute value - struct mxml_attr_s - struct mxml_value_s + mxml_node_t -* First child node + Attribute Value struct +mxml_attr_s + Element Value struct +mxml_value_s - Node mxml_node_t * First child node mxml_node_t * Last child node mxml_node_t * Next node under same parent @@ -105,31 +107,32 @@ name="name"> mxml_node_t * Parent node char * Attribute name mxml_type_t Node type mxml_value_t Node value + char -* Fragment string - Text Value char * Fragment string int Leading whitespace? + struct mxml_text_s Text Value struct +mxml_text_s - Node Type XML element with attributes Integer value Opaque string - Real value + Text fragment Attribute Value Element Value Text Value Node Value Node C++ support... Prototypes... C++ support... End of "$Id: mxml.xml,v 1.3 2003/06/07 21:27:05 mike Exp $". Text fragment - enum mxml_type_e + mxml_attr_t -* Attributes + Node Type enum +mxml_type_e - Element Value mxml_attr_t * Attributes char * Name of element int Number of attributes - union mxml_value_u diff --git a/mxmldoc.c b/mxmldoc.c index 0e558b3..57d6cec 100644 --- a/mxmldoc.c +++ b/mxmldoc.c @@ -1,5 +1,5 @@ /* - * "$Id: mxmldoc.c,v 1.10 2003/06/07 21:27:05 mike Exp $" + * "$Id: mxmldoc.c,v 1.11 2003/06/14 22:14:17 mike Exp $" * * Documentation generator using mini-XML, a small XML-like file parsing * library. @@ -18,6 +18,16 @@ * * Contents: * + * main() - Main entry for test program. + * add_variable() - Add a variable or argument. + * scan_file() - Scan a source file. + * sort_node() - Insert a node sorted into a tree. + * update_comment() - Update a comment node. + * write_documentation() - Write HTML documentation. + * write_element() - Write an elements text nodes. + * write_string() - Write a string, quoting XHTML special chars + * as needed... + * ws_cb() - Whitespace callback for saving. */ /* @@ -465,7 +475,28 @@ scan_file(const char *filename, /* I - Filename */ type = NULL; } + if (typedefnode) + { + /* + * Copy comment for typedef as well as class/struct/union... + */ + + mxmlNewText(comment, 0, + comment->last_child->value.text.string); + description = mxmlNewElement(typedefnode, "description"); +#ifdef DEBUG + fputs(" duplicating comment for typedef...\n", stderr); +#endif /* DEBUG */ + update_comment(typedefnode, comment->last_child); + mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, + comment->last_child); + } + description = mxmlNewElement(structclass, "description"); +#ifdef DEBUG + fprintf(stderr, " adding comment to %s...\n", + structclass->value.element.name); +#endif /* DEBUG */ update_comment(structclass, comment->last_child); mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, comment->last_child); @@ -522,7 +553,27 @@ scan_file(const char *filename, /* I - Filename */ type = NULL; } + if (typedefnode) + { + /* + * Copy comment for typedef as well as class/struct/union... + */ + + mxmlNewText(comment, 0, + comment->last_child->value.text.string); + description = mxmlNewElement(typedefnode, "description"); +#ifdef DEBUG + fputs(" duplicating comment for typedef...\n", stderr); +#endif /* DEBUG */ + update_comment(typedefnode, comment->last_child); + mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, + comment->last_child); + } + description = mxmlNewElement(enumeration, "description"); +#ifdef DEBUG + fputs(" adding comment to enumeration...\n", stderr); +#endif /* DEBUG */ update_comment(enumeration, comment->last_child); mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, comment->last_child); @@ -544,6 +595,7 @@ scan_file(const char *filename, /* I - Filename */ #endif /* DEBUG */ enumeration = NULL; + constant = NULL; if (braces > 0) braces --; @@ -649,17 +701,38 @@ scan_file(const char *filename, /* I - Filename */ *bufptr = '\0'; if (comment->child != comment->last_child) + { +#ifdef DEBUG + fprintf(stderr, " removing comment %p, last comment %p...\n", + comment->child, comment->last_child); +#endif /* DEBUG */ mxmlDelete(comment->child); +#ifdef DEBUG + fprintf(stderr, " new comment %p, last comment %p...\n", + comment->child, comment->last_child); +#endif /* DEBUG */ + } + +#ifdef DEBUG + fprintf(stderr, " processing comment, variable=%p, constant=%p, tree=\"%s\"\n", + variable, constant, tree->value.element.name); +#endif /* DEBUG */ if (variable) { description = mxmlNewElement(variable, "description"); +#ifdef DEBUG + fputs(" adding comment to variable...\n", stderr); +#endif /* DEBUG */ update_comment(variable, mxmlNewText(description, 0, buffer)); } else if (constant) { description = mxmlNewElement(constant, "description"); +#ifdef DEBUG + fputs(" adding comment to constant...\n", stderr); +#endif /* DEBUG */ update_comment(constant, mxmlNewText(description, 0, buffer)); } @@ -668,12 +741,24 @@ scan_file(const char *filename, /* I - Filename */ NULL, NULL, MXML_DESCEND_FIRST)) { description = mxmlNewElement(tree, "description"); +#ifdef DEBUG + fputs(" adding comment to parent...\n", stderr); +#endif /* DEBUG */ update_comment(tree, mxmlNewText(description, 0, buffer)); } else + { +#ifdef DEBUG + fprintf(stderr, " before adding comment, child=%p, last_child=%p\n", + comment->child, comment->last_child); +#endif /* DEBUG */ mxmlNewText(comment, 0, buffer); - +#ifdef DEBUG + fprintf(stderr, " after adding comment, child=%p, last_child=%p\n", + comment->child, comment->last_child); +#endif /* DEBUG */ + } #ifdef DEBUG fprintf(stderr, "C comment: <<< %s >>>\n", buffer); #endif /* DEBUG */ @@ -706,17 +791,33 @@ scan_file(const char *filename, /* I - Filename */ *bufptr = '\0'; if (comment->child != comment->last_child) + { +#ifdef DEBUG + fprintf(stderr, " removing comment %p, last comment %p...\n", + comment->child, comment->last_child); +#endif /* DEBUG */ mxmlDelete(comment->child); +#ifdef DEBUG + fprintf(stderr, " new comment %p, last comment %p...\n", + comment->child, comment->last_child); +#endif /* DEBUG */ + } if (variable) { description = mxmlNewElement(variable, "description"); +#ifdef DEBUG + fputs(" adding comment to variable...\n", stderr); +#endif /* DEBUG */ update_comment(variable, mxmlNewText(description, 0, buffer)); } else if (constant) { description = mxmlNewElement(constant, "description"); +#ifdef DEBUG + fputs(" adding comment to constant...\n", stderr); +#endif /* DEBUG */ update_comment(constant, mxmlNewText(description, 0, buffer)); } @@ -725,6 +826,9 @@ scan_file(const char *filename, /* I - Filename */ NULL, NULL, MXML_DESCEND_FIRST)) { description = mxmlNewElement(tree, "description"); +#ifdef DEBUG + fputs(" adding comment to parent...\n", stderr); +#endif /* DEBUG */ update_comment(tree, mxmlNewText(description, 0, buffer)); } @@ -755,17 +859,33 @@ scan_file(const char *filename, /* I - Filename */ *bufptr = '\0'; if (comment->child != comment->last_child) + { +#ifdef DEBUG + fprintf(stderr, " removing comment %p, last comment %p...\n", + comment->child, comment->last_child); +#endif /* DEBUG */ mxmlDelete(comment->child); +#ifdef DEBUG + fprintf(stderr, " new comment %p, last comment %p...\n", + comment->child, comment->last_child); +#endif /* DEBUG */ + } if (variable) { description = mxmlNewElement(variable, "description"); +#ifdef DEBUG + fputs(" adding comment to variable...\n", stderr); +#endif /* DEBUG */ update_comment(variable, mxmlNewText(description, 0, buffer)); } else if (constant) { description = mxmlNewElement(constant, "description"); +#ifdef DEBUG + fputs(" adding comment to constant...\n", stderr); +#endif /* DEBUG */ update_comment(constant, mxmlNewText(description, 0, buffer)); } @@ -774,6 +894,9 @@ scan_file(const char *filename, /* I - Filename */ NULL, NULL, MXML_DESCEND_FIRST)) { description = mxmlNewElement(tree, "description"); +#ifdef DEBUG + fputs(" adding comment to parent...\n", stderr); +#endif /* DEBUG */ update_comment(tree, mxmlNewText(description, 0, buffer)); } @@ -858,12 +981,24 @@ scan_file(const char *filename, /* I - Filename */ function = mxmlNewElement(MXML_NO_PARENT, "function"); mxmlElementSetAttr(function, "name", buffer); +#ifdef DEBUG + fprintf(stderr, "function: %s\n", buffer); + fprintf(stderr, " child = (%p) %s\n", + comment->child, comment->child->value.text.string); + fprintf(stderr, " last_child = (%p) %s\n", + comment->last_child, + comment->last_child->value.text.string); +#endif /* DEBUG */ + if (!type->last_child || strcmp(type->last_child->value.text.string, "void")) { returnvalue = mxmlNewElement(function, "returnvalue"); description = mxmlNewElement(returnvalue, "description"); +#ifdef DEBUG + fputs(" adding comment to returnvalue...\n", stderr); +#endif /* DEBUG */ update_comment(returnvalue, comment->last_child); mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, comment->last_child); @@ -874,6 +1009,9 @@ scan_file(const char *filename, /* I - Filename */ mxmlDelete(type); description = mxmlNewElement(function, "description"); +#ifdef DEBUG + fputs(" adding comment to function...\n", stderr); +#endif /* DEBUG */ update_comment(function, comment->last_child); mxmlAdd(description, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, comment->last_child); @@ -937,7 +1075,7 @@ scan_file(const char *filename, /* I - Filename */ type = NULL; typedefnode = NULL; } - else + else if (!parens) { /* * Variable definition... @@ -1080,6 +1218,11 @@ update_comment(mxml_node_t *parent, /* I - Parent node */ char *ptr; /* Pointer into comment */ +#ifdef DEBUG + fprintf(stderr, "update_comment(parent=%p, comment=%p)\n", + parent, comment); +#endif /* DEBUG */ + /* * Range check the input... */ @@ -1157,6 +1300,10 @@ update_comment(mxml_node_t *parent, /* I - Parent node */ *ptr = '\0'; for (; ptr > comment->value.text.string && isspace(*ptr); ptr --) *ptr = '\0'; + +#ifdef DEBUG + fprintf(stderr, " updated comment = %s\n", comment->value.text.string); +#endif /* DEBUG */ } @@ -1779,5 +1926,5 @@ ws_cb(mxml_node_t *node, /* I - Element node */ /* - * End of "$Id: mxmldoc.c,v 1.10 2003/06/07 21:27:05 mike Exp $". + * End of "$Id: mxmldoc.c,v 1.11 2003/06/14 22:14:17 mike Exp $". */ diff --git a/testmxml.c b/testmxml.c index 9a46e6b..b37ba58 100644 --- a/testmxml.c +++ b/testmxml.c @@ -1,5 +1,5 @@ /* - * "$Id: testmxml.c,v 1.7 2003/06/04 21:19:00 mike Exp $" + * "$Id: testmxml.c,v 1.8 2003/06/14 22:14:17 mike Exp $" * * Test program for mini-XML, a small XML-like file parsing library. * @@ -46,9 +46,17 @@ int /* O - Exit status */ main(int argc, /* I - Number of command-line args */ char *argv[]) /* I - Command-line args */ { - FILE *fp; /* File to read */ - mxml_node_t *tree, /* XML tree */ - *node; /* Node which should be in test.xml */ + FILE *fp; /* File to read */ + mxml_node_t *tree, /* XML tree */ + *node; /* Node which should be in test.xml */ + static const char *types[] = /* Strings for node types */ + { + "MXML_ELEMENT", + "MXML_INTEGER", + "MXML_OPAQUE", + "MXML_REAL", + "MXML_TEXT" + }; /* @@ -61,6 +69,165 @@ main(int argc, /* I - Number of command-line args */ return (1); } + /* + * Test the basic functionality... + */ + + tree = mxmlNewElement(MXML_NO_PARENT, "element"); + + if (!tree) + { + fputs("ERROR: No parent node in basic test!\n", stderr); + return (1); + } + + if (tree->type != MXML_ELEMENT) + { + fprintf(stderr, "ERROR: Parent has type %s (%d), expected MXML_ELEMENT!\n", + tree->type < MXML_ELEMENT || tree->type > MXML_TEXT ? + "UNKNOWN" : types[tree->type], tree->type); + mxmlDelete(tree); + return (1); + } + + if (strcmp(tree->value.element.name, "element")) + { + fprintf(stderr, "ERROR: Parent value is \"%s\", expected \"element\"!\n", + tree->value.element.name); + mxmlDelete(tree); + return (1); + } + + mxmlNewInteger(tree, 123); + mxmlNewOpaque(tree, "opaque"); + mxmlNewReal(tree, 123.4f); + mxmlNewText(tree, 1, "text"); + + node = tree->child; + + if (!node) + { + fputs("ERROR: No first child node in basic test!\n", stderr); + mxmlDelete(tree); + return (1); + } + + if (node->type != MXML_INTEGER) + { + fprintf(stderr, "ERROR: First child has type %s (%d), expected MXML_INTEGER!\n", + node->type < MXML_ELEMENT || node->type > MXML_TEXT ? + "UNKNOWN" : types[node->type], node->type); + mxmlDelete(tree); + return (1); + } + + if (node->value.integer != 123) + { + fprintf(stderr, "ERROR: First child value is %d, expected 123!\n", + node->value.integer); + mxmlDelete(tree); + return (1); + } + + node = node->next; + + if (!node) + { + fputs("ERROR: No second child node in basic test!\n", stderr); + mxmlDelete(tree); + return (1); + } + + if (node->type != MXML_OPAQUE) + { + fprintf(stderr, "ERROR: Second child has type %s (%d), expected MXML_OPAQUE!\n", + node->type < MXML_ELEMENT || node->type > MXML_TEXT ? + "UNKNOWN" : types[node->type], node->type); + mxmlDelete(tree); + return (1); + } + + if (!node->value.opaque || strcmp(node->value.opaque, "opaque")) + { + fprintf(stderr, "ERROR: Second child value is \"%s\", expected \"opaque\"!\n", + node->value.opaque ? node->value.opaque : "(null)"); + mxmlDelete(tree); + return (1); + } + + node = node->next; + + if (!node) + { + fputs("ERROR: No third child node in basic test!\n", stderr); + mxmlDelete(tree); + return (1); + } + + if (node->type != MXML_REAL) + { + fprintf(stderr, "ERROR: Third child has type %s (%d), expected MXML_REAL!\n", + node->type < MXML_ELEMENT || node->type > MXML_TEXT ? + "UNKNOWN" : types[node->type], node->type); + mxmlDelete(tree); + return (1); + } + + if (node->value.real != 123.4f) + { + fprintf(stderr, "ERROR: Third child value is %f, expected 123.4!\n", + node->value.real); + mxmlDelete(tree); + return (1); + } + + node = node->next; + + if (!node) + { + fputs("ERROR: No fourth child node in basic test!\n", stderr); + mxmlDelete(tree); + return (1); + } + + if (node->type != MXML_TEXT) + { + fprintf(stderr, "ERROR: Fourth child has type %s (%d), expected MXML_TEXT!\n", + node->type < MXML_ELEMENT || node->type > MXML_TEXT ? + "UNKNOWN" : types[node->type], node->type); + mxmlDelete(tree); + return (1); + } + + if (!node->value.text.whitespace || + !node->value.text.string || strcmp(node->value.text.string, "text")) + { + fprintf(stderr, "ERROR: Fourth child value is %d,\"%s\", expected 1,\"text\"!\n", + node->value.text.whitespace, + node->value.text.string ? node->value.text.string : "(null)"); + mxmlDelete(tree); + return (1); + } + + mxmlDelete(tree->child); + mxmlDelete(tree->child); + mxmlDelete(tree->child); + mxmlDelete(tree->child); + + if (tree->child) + { + fputs("ERROR: Child pointer not NULL after deleting all children!\n", stderr); + return (1); + } + + if (tree->last_child) + { + fputs("ERROR: Last child pointer not NULL after deleting all children!\n", stderr); + return (1); + } + + mxmlDelete(tree); + /* * Open the file... */ @@ -212,5 +379,5 @@ whitespace_cb(mxml_node_t *node, /* I - Element node */ /* - * End of "$Id: testmxml.c,v 1.7 2003/06/04 21:19:00 mike Exp $". + * End of "$Id: testmxml.c,v 1.8 2003/06/14 22:14:17 mike Exp $". */ + mxml_element_t Element + Node Value union +mxml_value_u Node Value mxml_element_t Element int Integer number char * Opaque string double Real number - mxml_text_t Text fragment - mxml_node_t * Current node - mxml_node_t * Parent node Node type - const char * String to write File to write to + int(*cb)(mxml_node_t *int) int Where value Current column