/* * LibAxl: Another XML library * Copyright (C) 2006 Advanced Software Production Line, S.L. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * * You may find a copy of the license under this software is released * at COPYING file. This is LGPL software: you are welcome to * develop proprietary applications using this library without any * royalty or fee but returning back any change, improvement or * addition in the form of source code, project image, documentation * patches, etc. * * For commercial support on build XML enabled solutions contact us: * * Postal address: * Advanced Software Production Line, S.L. * Edificio Alius A, Oficina 102, * C/ Antonio Suarez Nº 10, * Alcalá de Henares 28802 Madrid * Spain * * Email address: * info@aspl.es - http://www.aspl.es/xml */ #include #define LOG_DOMAIN "axl-ns-node" /** * \defgroup axl_ns_node_module Axl Node Namespace: Xml 1.0 namespace support for XML nodes */ /** * \addtogroup axl_ns_node_module * @{ */ /** * @brief Allows to perform a node name (tag) checking using XML 1.0 * Namespace rules. * * This function must be used instead of \ref NODE_CMP_NAME if your application must support * XML 1.0 namespaces. * * The idea is that you declares the namespace that you will recognize * using a macro definition at some place in your headers, as follows: * \code * #define YOUR_NS "http://yourdomain.com/somepath/yourapplication" * \endcode * * Previous namespace must be unique. This is crucial to avoid tag * clashing. Now, you use this namespace identifier and the local name * of your tag to check a particular node to have a particular name as * follows: * * \code * if (axl_ns_node_cmp (node, YOUR_NS, "table")) { * // found table node inside your namespace * } * \endcode * * It is required to call first to \ref axl_ns_doc_validate in order * to make this function to properly work. * * @param node The node that will be checked. * * @param ns The namespace to use to match the node name. * * @param name The node name to be checked (without namespace * prefixes). * * @return \ref axl_true if the node name is the one expected, binded by * the namespace declaration, otherwise \ref axl_false is returned. The * function returns \ref axl_false in the of some paremeter is provided * null. */ axl_bool axl_ns_node_cmp (axlNode * node, const char * ns, const char * name) { int position; char * _name; axl_return_val_if_fail (node, axl_false); axl_return_val_if_fail (ns, axl_false); axl_return_val_if_fail (name, axl_false); /* check the name is namespace prefixed */ if (axl_ns_node_is_prefixed (node, &position)) { /* namespace bound */ _name = (char*) axl_node_get_name (node); _name[position] = 0; /* call to check */ if (! axl_ns_doc_node_check (node, _name, ns)) { /* restore the value */ _name[position] = ':'; return axl_false; } /* restore the value */ _name[position] = ':'; /* now check the node name (now we know the namespace is checked) */ return axl_cmp (name, _name + position + 1); } /* end if */ /* look for the default namespace */ if (! axl_ns_doc_check_default (node, ns)) { /* default namespace for the current node doesn't match */ return axl_false; } /* default namespace match, check the node name */ return axl_cmp (name, axl_node_get_name (node)); } /** * @brief Allows to find the first child called as provided inside the * childs (including its descendants) hold by the parent provided, * with namespace support. * * This function must be used instead of \ref * axl_node_find_called if your application must support * XML 1.0 namespaces. * * This function is similar to \ref axl_ns_node_get_child_called but * it will look for a child node called as provided not only in direct * childs hold by the parent but also on its all descendants, giving * support to configure the namespace where the lookup will be run. * * If you are looking for a function to search for a particular child * node inside direct childs stored for the provided parent, then you * must use \ref axl_ns_node_get_child_called. * * There is also a convenience function that allows to perform a * lookup using as a reference a document (using the root node from * it): \ref axl_ns_doc_find_called. * * @param parent The parent where the lookup will be produced. * * @param ns The namespace where the node will be searched * * @param name The name of the child to be looked up. * * @return A reference to the node found (first instaned matching the * name) or NULL if it fails to find a child. */ axlNode * axl_ns_node_find_called (axlNode * parent, const char * ns, const char * name) { axlNode * node; axlNode * child; /* for the first child found */ node = axl_ns_node_get_child_called (parent, ns, name); if (node != NULL) return node; /* now, for all childs, try to look for the node */ node = axl_node_get_first_child (parent); while (node != NULL) { /* make the search */ child = axl_ns_node_find_called (node, ns, name); /* child found, return the reference */ if (child != NULL) return child; /* get next */ node = axl_node_get_next (node); } /* end while */ /* child note found */ return NULL; } /** * @brief Allows to get a particular child node for the given node * (\ref axlNode), inside the provided namespace. * * This function must be used instead of \ref * axl_node_get_child_called if your application must support * XML 1.0 namespaces. * * @param parent The parent node where the child will be looked up. * * @param ns The namespace where the lookup will be run. * * @param name The name for the child to search. * * @return A refernce to a \ref axlNode or NULL if no child exists * called by the name provided, inside the node provided. */ axlNode * axl_ns_node_get_child_called (axlNode * parent, const char * ns, const char * name) { axlNode * node; /* for the first child found */ node = axl_node_get_first_child (parent); while (node != NULL) { /* check and return the node found */ if (axl_ns_node_cmp (node, ns, name)) return node; /* get next */ node = axl_node_get_next (node); } /* end while */ return NULL; } /** * @brief Allows to get the next node, following to the node provided, * matching the given name, inside the namespace configuration * provided. * * This function must be used instead of \ref * axl_node_get_next_called if your application must support * XML 1.0 namespaces. * * @param node The node that is requested to return its next sibling * node. * * @param ns The namespace value to use to perform the search. * * @param name The name to match for the next node. * * @return A reference to the next node or NULL if it fails. The * returned reference mustn't be deallocated. */ axlNode * axl_ns_node_get_next_called (axlNode * node, const char * ns, const char * name) { axlNode * next; axl_return_val_if_fail (node, NULL); axl_return_val_if_fail (ns, NULL); axl_return_val_if_fail (name, NULL); /* while there is a next node */ next = axl_node_get_next (node); while (next != NULL) { /* check the node */ if (axl_ns_node_cmp (next, ns, name)) return next; /* update to the next */ next = axl_node_get_next (next); } /* end while */ /* no node was found */ return NULL; } /** * @brief Allows to get the previous node, preceding to the node * provided, matching the given name, inside the given namespace * value. * * @param node The node that is requested to return its previous * sibling node. * * @param ns The namespace to be used to perform the lookup. * * @param name The name to match for the previous node. * * @return A reference to the previous node or NULL if it fails. The * returned reference mustn't be deallocated. */ axlNode * axl_ns_node_get_previous_called (axlNode * node, const char * ns, const char * name) { axlNode * previous; axl_return_val_if_fail (node, NULL); axl_return_val_if_fail (ns, NULL); axl_return_val_if_fail (name, NULL); /* while there is a previous node */ previous = axl_node_get_previous (node); while (previous != NULL) { /* check the node */ if (axl_ns_node_cmp (previous, ns, name)) return previous; /* update to the next */ previous = axl_node_get_previous (previous); } /* end while */ /* no node was found */ return NULL; } /** * @brief Allows to check if the provided node, has a name (tag) which is namespace prefixed. * * The following name is considered namespace prefixed * edi:price while using edi is not. * * @param node The node to be checked to have a name prefixed. * * @param position Optional variable where the position of the ":" * inside the xml node name is returned. On \ref axl_false, the value is * configured to -1. * * @return \ref axl_true if the node is prefixed, otherwise \ref axl_false is * returned. The function also returns \ref axl_false if the node * reference received is NULL. */ axl_bool axl_ns_node_is_prefixed (axlNode * node, int * position) { int iterator = 0; const char * name; axl_return_val_if_fail (node, axl_false); /* configure default position */ if (position) *position = -1; /* get the node name and check each character */ name = axl_node_get_name (node); while (name[iterator] != 0) { /* if found, notify this */ if (name[iterator] == ':') { /* configure default position */ if (position) *position = iterator; return axl_true; } /* end if */ /* go to the next character */ iterator++; } /* end while */ /* reached this point, axl_false must be returned */ return axl_false; } /** * @} */