/* * XML Catalog Manager (xmlcatmgr) * $Id: xmlnode.c,v 1.1 2004/08/31 19:07:23 jmmv Exp $ * * Copyright (c) 2003, 2004 Julio M. Merino Vidal. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of the author nor the names of contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * This file implements several functions to handle 'xmlattr' and * 'xmlnode' objects. */ #include "system.h" #ifndef lint __RCSID("$Id: xmlnode.c,v 1.1 2004/08/31 19:07:23 jmmv Exp $"); #endif #include "mem.h" #include "linklist.h" #include "xmlnode.h" /* --------------------------------------------------------------------- */ /* * Creates a new xmlattr object. 'name' and 'value' must be pointers to * memory regions allocated by malloc(3), as they will be free(3)'d when * calling xmlattr_free. */ struct xmlattr * xmlattr_new(char *name, char *value) { struct xmlattr *xa; assert(name != NULL && value != NULL); xa = (struct xmlattr *)malloc(sizeof(struct xmlattr)); if (xa != NULL) { xa->xa_name = name; xa->xa_value = value; } return xa; } /* --------------------------------------------------------------------- */ /* * Destroys an xmlattr object. */ void xmlattr_free(struct xmlattr *xa) { assert(xa != NULL); free(xa->xa_name); free(xa->xa_value); free(xa); } /* --------------------------------------------------------------------- */ /* * Dumps an xmlattr object to a stream. */ bool xmlattr_write(struct xmlattr *xa, FILE *f) { assert(xa != NULL && f != NULL); return fprintf(f, "%s=\"%s\"", xa->xa_name, xa->xa_value) != -1; } /* --------------------------------------------------------------------- */ /* * Creates a new xmlnode object. 'tag' must be a pointer to a memory * region allocated by malloc(3), as it will be free(3)'d by xmlnode_free. */ struct xmlnode * xmlnode_new(int type, char *tag) { struct xmlnode *xn; assert(tag != NULL); xn = (struct xmlnode *)malloc(sizeof(struct xmlnode)); if (xn != NULL) { xn->xn_type = type; xn->xn_tag = tag; xn->xn_text = NULL; xn->xn_parent = NULL; LINKLIST_INIT(&xn->xn_attrs); LINKLIST_INIT(&xn->xn_childs); } return xn; } /* --------------------------------------------------------------------- */ /* * Destroys an xmlnode object. This also destroys all related attributes * and all attached childs (recursively). */ void xmlnode_free(struct xmlnode *xn) { assert(xn != NULL); free(xn->xn_tag); switch (xn->xn_type) { case XMLNODE_TYPE_COMMENT: case XMLNODE_TYPE_TEXT: if (xn->xn_text != NULL) free(xn->xn_text); break; case XMLNODE_TYPE_ELEMENT: case XMLNODE_TYPE_ROOT: if (!LINKLIST_EMPTY(&xn->xn_attrs)) { struct xmlattr *xa; xa = LINKLIST_FIRST(&xn->xn_attrs); while (xa != NULL) { struct xmlattr *tmp; tmp = LINKLIST_NEXT(xa); xmlattr_free(xa); xa = tmp; } } if (!LINKLIST_EMPTY(&xn->xn_childs)) { struct xmlnode *xn2; xn2 = LINKLIST_FIRST(&xn->xn_childs); while (xn2 != NULL) { struct xmlnode *tmp; tmp = LINKLIST_NEXT(xn2); xmlnode_free(xn2); xn2 = tmp; } } break; default: assert(false); } free(xn); } /* --------------------------------------------------------------------- */ /* * Search for an attribute in the given xmlnode, based on its name, and * return its value. */ char * xmlnode_get_attr_value(struct xmlnode *xn, const char *name) { struct xmlattr *xa; assert(xn != NULL && name != NULL); XMLNODE_FOREACH_ATTR(xa, xn) { if (strcmp(xa->xa_name, name) == 0) return xa->xa_value; } return NULL; } /* --------------------------------------------------------------------- */ /* * Set the text field associated to the node. Only valid when the node * is a comment or a text node. Any information previously stored in it * is discarded. */ void xmlnode_set_text(struct xmlnode *xn, char *text) { assert(xn != NULL && (xn->xn_type == XMLNODE_TYPE_COMMENT || xn->xn_type == XMLNODE_TYPE_TEXT) && text != NULL); if (xn->xn_text != NULL) free(xn->xn_text); xn->xn_text = text; } /* --------------------------------------------------------------------- */ /* * Turn a regular element node into a root node. */ void xmlnode_become_root(struct xmlnode *xn) { assert(xn != NULL && xn->xn_type == XMLNODE_TYPE_ELEMENT); xn->xn_type = XMLNODE_TYPE_ROOT; } /* --------------------------------------------------------------------- */ /* * Dump the given node to a stream. If it is an element node or a root * node, its attributes and childs are also dumped recursively. */ bool xmlnode_write(struct xmlnode *xn, FILE *f) { bool res; struct xmlattr *aiter; struct xmlnode *niter; assert(xn != NULL && f != NULL); res = true; switch (xn->xn_type) { case XMLNODE_TYPE_COMMENT: res &= fprintf(f, "\n", xn->xn_text) != -1; break; case XMLNODE_TYPE_TEXT: res &= fprintf(f, "%s\n", xn->xn_text) != -1; break; case XMLNODE_TYPE_ELEMENT: case XMLNODE_TYPE_ROOT: res &= fprintf(f, "<%s", xn->xn_tag) != -1; XMLNODE_FOREACH_ATTR(aiter, xn) { res &= fprintf(f, " ") != -1; res &= xmlattr_write(aiter, f); } if (LINKLIST_EMPTY(&(xn->xn_childs))) res &= fprintf(f, " />\n") != -1; else { res &= fprintf(f, ">\n") != -1; XMLNODE_FOREACH_CHILD(niter, xn) { res &= xmlnode_write(niter, f); } res &= fprintf(f, "\n", xn->xn_tag) != -1; } break; default: assert(false); } return res; } /* * Local Variables: *** * mode: c *** * c-file-style: "stroustrup" *** * End: *** * vim: syntax=c:expandtab:shiftwidth=4:softtabstop=4 */