00001 /* 00002 * "$Id: mxml-search.c 297 2007-09-09 07:16:52Z mike $" 00003 * 00004 * Search/navigation functions for Mini-XML, a small XML-like file 00005 * parsing library. 00006 * 00007 * Copyright 2003-2007 by Michael Sweet. 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Library General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * Contents: 00020 * 00021 * mxmlFindElement() - Find the named element. 00022 * mxmlWalkNext() - Walk to the next logical node in the tree. 00023 * mxmlWalkPrev() - Walk to the previous logical node in the tree. 00024 */ 00025 00026 /* 00027 * Include necessary headers... 00028 */ 00029 00030 #include "config.h" 00031 #include "mxml.h" 00032 00033 00034 /* 00035 * 'mxmlFindElement()' - Find the named element. 00036 * 00037 * The search is constrained by the name, attribute name, and value; any 00038 * NULL names or values are treated as wildcards, so different kinds of 00039 * searches can be implemented by looking for all elements of a given name 00040 * or all elements with a specific attribute. The descend argument determines 00041 * whether the search descends into child nodes; normally you will use 00042 * MXML_DESCEND_FIRST for the initial search and MXML_NO_DESCEND to find 00043 * additional direct descendents of the node. The top node argument 00044 * constrains the search to a particular node's children. 00045 */ 00046 00047 mxml_node_t * /* O - Element node or NULL */ 00048 mxmlFindElement(mxml_node_t *node, /* I - Current node */ 00049 mxml_node_t *top, /* I - Top node */ 00050 const char *name, /* I - Element name or NULL for any */ 00051 const char *attr, /* I - Attribute name, or NULL for none */ 00052 const char *value, /* I - Attribute value, or NULL for any */ 00053 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ 00054 { 00055 const char *temp; /* Current attribute value */ 00056 00057 00058 /* 00059 * Range check input... 00060 */ 00061 00062 if (!node || !top || (!attr && value)) 00063 return (NULL); 00064 00065 /* 00066 * Start with the next node... 00067 */ 00068 00069 node = mxmlWalkNext(node, top, descend); 00070 00071 /* 00072 * Loop until we find a matching element... 00073 */ 00074 00075 while (node != NULL) 00076 { 00077 /* 00078 * See if this node matches... 00079 */ 00080 00081 if (node->type == MXML_ELEMENT && 00082 node->value.element.name && 00083 (!name || !strcmp(node->value.element.name, name))) 00084 { 00085 /* 00086 * See if we need to check for an attribute... 00087 */ 00088 00089 if (!attr) 00090 return (node); /* No attribute search, return it... */ 00091 00092 /* 00093 * Check for the attribute... 00094 */ 00095 00096 if ((temp = mxmlElementGetAttr(node, attr)) != NULL) 00097 { 00098 /* 00099 * OK, we have the attribute, does it match? 00100 */ 00101 00102 if (!value || !strcmp(value, temp)) 00103 return (node); /* Yes, return it... */ 00104 } 00105 } 00106 00107 /* 00108 * No match, move on to the next node... 00109 */ 00110 00111 if (descend == MXML_DESCEND) 00112 node = mxmlWalkNext(node, top, MXML_DESCEND); 00113 else 00114 node = node->next; 00115 } 00116 00117 return (NULL); 00118 } 00119 00120 00121 /* 00122 * 'mxmlWalkNext()' - Walk to the next logical node in the tree. 00123 * 00124 * The descend argument controls whether the first child is considered 00125 * to be the next node. The top node argument constrains the walk to 00126 * the node's children. 00127 */ 00128 00129 mxml_node_t * /* O - Next node or NULL */ 00130 mxmlWalkNext(mxml_node_t *node, /* I - Current node */ 00131 mxml_node_t *top, /* I - Top node */ 00132 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ 00133 { 00134 if (!node) 00135 return (NULL); 00136 else if (node->child && descend) 00137 return (node->child); 00138 else if (node == top) 00139 return (NULL); 00140 else if (node->next) 00141 return (node->next); 00142 else if (node->parent && node->parent != top) 00143 { 00144 node = node->parent; 00145 00146 while (!node->next) 00147 if (node->parent == top || !node->parent) 00148 return (NULL); 00149 else 00150 node = node->parent; 00151 00152 return (node->next); 00153 } 00154 else 00155 return (NULL); 00156 } 00157 00158 00159 /* 00160 * 'mxmlWalkPrev()' - Walk to the previous logical node in the tree. 00161 * 00162 * The descend argument controls whether the previous node's last child 00163 * is considered to be the previous node. The top node argument constrains 00164 * the walk to the node's children. 00165 */ 00166 00167 mxml_node_t * /* O - Previous node or NULL */ 00168 mxmlWalkPrev(mxml_node_t *node, /* I - Current node */ 00169 mxml_node_t *top, /* I - Top node */ 00170 int descend) /* I - Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST */ 00171 { 00172 if (!node || node == top) 00173 return (NULL); 00174 else if (node->prev) 00175 { 00176 if (node->prev->last_child && descend) 00177 { 00178 /* 00179 * Find the last child under the previous node... 00180 */ 00181 00182 node = node->prev->last_child; 00183 00184 while (node->last_child) 00185 node = node->last_child; 00186 00187 return (node); 00188 } 00189 else 00190 return (node->prev); 00191 } 00192 else if (node->parent != top) 00193 return (node->parent); 00194 else 00195 return (NULL); 00196 }