blob: d5005b5ff2065dcf1a650f188f93f1275aa62dac [file] [log] [blame]
/** \file roxml.h
* \brief header for libroxml.so
*
* This is the header file used to develop some
* software using the libroxml.so library.
* \author blunderer <blunderer@blunderer.org>
* \date 23 Dec 2008
*
* Copyright (C) 2009 blunderer
*
* As a special exception to the LGPL v2.1 (below), the copyright holders of
* this library give you permission to statically link this library
* with independent modules to produce an executable, regardless of the license
* terms of these independent modules, and to copy and distribute the resulting
* executable under terms of your choice, provided that you also meet, for each
* linked independent module, the terms and conditions of the license of that
* module. The resulting executable may therefore be distributed without complying
* with the LGPL terms that state that recipients of your executable must be able
* to relink against modified versions of the library.
*
* This library 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.
* The author added a static linking exception, see License.txt.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*******************************************************************************
* ==========================================================================
* $Log$
*
* 01 28 2019 cs.huang
* [MOLY00381872] [VMOLY] XCAP merge from UMOLYE
* XCAP sync from UMOLYE (OA part)
*
* 12 28 2018 howen.pu
* [MOLY00374881] Gen95 XCAP - USIR
* Gen 95 USIR - For XCAP.
*
* 12 28 2018 howen.pu
* [MOLY00374881] Gen95 XCAP - USIR
*
* Gen 95 USIR - For XCAP.
*
*
****************************************************************************/
#ifndef ROXML_H
#define ROXML_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* \def ROXML_API
*
* part of the public API
*/
#define ROXML_API
#ifndef ROXML_INT
/** \typedef node_t
*
* \brief node_t structure
*
* This is the structure for a node. This struct is very
* little as it only contains offset for node in file and
* tree links
*/
typedef struct node node_t;
#endif
/**
* \def ROXML_INVALID_NODE
*
* constant for invalid nodes
*/
#define ROXML_INVALID_NODE 0x000
/**
* \def ROXML_ATTR_NODE
*
* constant for attribute nodes
* \see roxml_add_node
*/
#define ROXML_ATTR_NODE 0x008
/**
* \def ROXML_STD_NODE
*
* \deprecated
* constant for standard nodes
*
* \see roxml_add_node
*
*/
#define ROXML_STD_NODE 0x010
/**
* \def ROXML_ELM_NODE
*
* constant for element nodes
* \see roxml_add_node
*/
#define ROXML_ELM_NODE 0x010
/**
* \def ROXML_TXT_NODE
*
* constant for text nodes
* \see roxml_add_node
*/
#define ROXML_TXT_NODE 0x020
/**
* \def ROXML_CMT_NODE
*
* constant for comment nodes
* \see roxml_add_node
*/
#define ROXML_CMT_NODE 0x040
/**
* \def ROXML_PI_NODE
*
* constant for processing_intruction nodes
* \see roxml_add_node
*/
#define ROXML_PI_NODE 0x080
/**
* \def ROXML_NS_NODE
*
* constant for namespace nodes
* \see roxml_add_node
*/
#define ROXML_NS_NODE 0x100
/**
* \def ROXML_NSDEF_NODE
*
* constant for namespace definition nodes
* \see roxml_add_node
*/
#define ROXML_NSDEF_NODE (ROXML_NS_NODE | ROXML_ATTR_NODE)
/**
* \def ROXML_CDATA_NODE
*
* constant for cdata nodes
* \see roxml_add_node
*/
#define ROXML_CDATA_NODE (ROXML_TXT_NODE | 0x200)
/**
* \def ROXML_DOCTYPE_NODE
*
* constant for doctype nodes
* \see roxml_add_node
*/
#define ROXML_DOCTYPE_NODE 0x400
/**
* \def ROXML_ALL_NODES
*
* constant for all types of nodes
* \see roxml_add_node
*/
#define ROXML_ALL_NODES (ROXML_PI_NODE | ROXML_CMT_NODE | ROXML_TXT_NODE | ROXML_ATTR_NODE | ROXML_ELM_NODE)
/**
* \def ROXML_ALL_NODE
*
* constant for all types of nodes for backward compatibility
* \see roxml_add_node
*/
#define ROXML_ALL_NODE ROXML_ALL_NODES
/**
* \def ROXML_NODE_TYPES
*
* constant for all nodes types
* \see roxml_get_types
*/
#define ROXML_NODE_TYPES 0x05f8
/**
* \def RELEASE_ALL
*
* when used with roxml_release, release all memory allocated by current thread
* \see roxml_release
*/
#define RELEASE_ALL (void*)-1
/**
* \def RELEASE_LAST
*
* when used with roxml_release, release last variable allocated
* \see roxml_release
*
* example:
* \code
* #include <stdio.h>
* #include <roxml.h>
* int main(void)
* {
* int len;
* node_t *root = roxml_load_doc("/tmp/doc.xml");
*
* // roxml_get_content allocate a buffer and store the content in it if no buffer was given
* printf("root content = '%s'\n", roxml_get_content(root, NULL, 0, &len));
*
* // release the last allocated buffer even if no pointer is maintained by the user
* roxml_release(RELEASE_LAST);
*
* // here no memory leak can occur.
*
* roxml_close(root);
* return 0;
* }
* \endcode
*/
#define RELEASE_LAST (void*)-2
/**
* \def ROXML_INVALID_DOC
*
* constant for invalid documents
*/
#define ROXML_INVALID_DOC (node_t*)0
/** \brief load function for buffers
*
* \fn node_t* roxml_load_buf(char *buffer);
* This function load a document by parsing all the corresponding nodes.
* The document must be contained inside the char * buffer given in parameter
* and remain valid until the roxml_close() function is called
* \param buffer the XML buffer to load
* \return the root node or ROXML_INVALID_DOC (NULL). errno is set to EINVAL in case of parsing error
* \see roxml_close
* \see roxml_load_fd
* \see roxml_load_doc
*/
ROXML_API node_t * roxml_load_buf(char *buffer);
/** \brief load function for files
*
* \fn node_t* roxml_load_doc(char *filename);
* This function load a file document by parsing all the corresponding nodes
* \warning the file is not fully copied and thus, it should stay untouched until roxml_close is called on the corresponding XML tree.
* \param filename the XML document to load
* \return the root node or ROXML_INVALID_DOC (NULL). errno is set to EINVAL in case of parsing error
* \see roxml_close
* \see roxml_load_fd
* \see roxml_load_buf
*/
ROXML_API node_t * roxml_load_doc(char *filename);
/** \brief load function for file descriptors
*
* \fn node_t* roxml_load_fd(int fd);
* This function load a document by parsing all the corresponding nodes
* \param fd the opened file descriptor to XML document to load
* \return the root node or ROXML_INVALID_DOC (NULL). errno is set to EINVAL in case of parsing error
* \see roxml_close
* \see roxml_load_doc
* \see roxml_load_buf
*/
ROXML_API node_t * roxml_load_fd(int fd);
/** \brief unload function
*
* \fn void roxml_close(node_t *n);
* This function clear a document and all the corresponding nodes
* It release all memory allocated during roxml_load_doc or roxml_load_file or roxml_add_node.
* All nodes from the tree are not available anymore.
* \param n is any node of the tree to be cleaned
* \return void
* \see roxml_load_doc
* \see roxml_load_buf
* \see roxml_add_node
*/
ROXML_API void roxml_close(node_t *n);
/** \brief next sibling getter function
*
* \fn node_t* roxml_get_next_sibling(node_t *n);
* This function returns the next sibling of a given node
* \param n is one node of the tree
* \return the next sibling node
*/
ROXML_API node_t * roxml_get_next_sibling(node_t *n);
/** \brief prev sibling getter function
*
* \fn node_t* roxml_get_prev_sibling(node_t *n);
* This function returns the prev sibling of a given node
* \param n is one node of the tree
* \return the prev sibling node
*/
ROXML_API node_t * roxml_get_prev_sibling(node_t *n);
/** \brief parent getter function
*
* \fn node_t* roxml_get_parent(node_t *n);
* This function returns the parent of a given node
* \param n is one node of the tree
* \return the parent node
*/
ROXML_API node_t * roxml_get_parent(node_t *n);
/** \brief root getter function
*
* \fn node_t* roxml_get_root(node_t *n);
* This function returns the root of a tree containing the given node
* The root is defined as a virtual node that contains all first rank nodes if document is
* not a valid xml document:
* \verbatim
<data1>
<item/>
<item/>
</data1>
<data2>
<item/>
<item/>
</data2>
\endverbatim
* will be processed successfully and the root node will have 2 children: data1 and data2
*
* if document was:
* \verbatim
<?xml version="1.0">
<doc>
<data1>
<item/>
<item/>
</data1>
<data2>
<item/>
<item/>
</data2>
</doc>
\endverbatim
* In this case, the node "doc" will be the root, and will contain 2 children: data1 and data2
*
* For a document to be valid, following conditions must be met:
* <ul>
* <li>the first node is a processing instruction with the string "xml" as target application.</li>
* <li>there is only one ELM node containing all document (but there may be several process-instructions or comments)</li>
* </ul>
* \param n is one node of the tree
* \return the root node
*/
ROXML_API node_t * roxml_get_root(node_t *n);
/** \brief namespace getter function
*
* \fn node_t* roxml_get_ns(node_t *n);
* This function returns the namespace of a node
*
* \param n is one node of the tree
* \return the namespace or NULL if none are set for this node
* \see roxml_add_node
* \see roxml_set_ns
* \see roxml_get_nodes
*
* example:
* given the following xml file
* \verbatim
<xml xmlns:test="http://www.test.org">
<test:item1 test:value1="3"/>
</xml>
\endverbatim
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_load_doc("/tmp/doc.xml");
* node_t *xml = roxml_get_chld(root, NULL, 0);
* node_t *nsdef = roxml_get_attr(xml, NULL, 0);
* node_t *node1 = roxml_get_chld(xml, NULL, 0);
* node_t *attr1 = roxml_get_attr(node1, NULL, 0);
* node_t *node1_ns = roxml_get_ns(node1);
* node_t *attr1_ns = roxml_get_ns(attr1);
*
* // here node1_ns and attr1_ns are the "test:" namespace
* if(node1_ns == nsdef) {
* printf("got the correct namespace node for elem\n");
* }
* if(attr1_ns == nsdef) {
* printf("got the correct namespace node for attr\n");
* }
* if(strcmp(roxml_get_name(node1_ns, NULL, 0), "test") == 0) {
* printf("got the correct namespace alias\n");
* }
* if(strcmp(roxml_get_content(node1_ns, NULL, 0, NULL), "http://www.test.org") == 0) {
* printf("got the correct namespace\n");
* }
*
* roxml_close(root);
* return 0;
* }
*
* \endcode
*/
ROXML_API node_t * roxml_get_ns(node_t *n);
/** \brief namespace setter function
*
* \fn node_t* roxml_set_ns(node_t *n, node_t *ns);
* This function set the namespace of a node to the given namespace definition.
* The namespace must be previously defined in the xml tree in an ancestor of node n.
*
* \param n is one node of the tree
* \param ns is one nsdef node of the tree
* \return the node or ROXML_INVALID_DOC (NULL) if ns cannot be set
* \see roxml_add_node
* \see roxml_get_ns
* \see roxml_get_nodes
*
* \warning: Setting a namespace to a node is recursif:
* - it will update all element and attribute that are descendant from current node
* - namespace will be applied to all new node added as descendant as current node
*/
ROXML_API node_t * roxml_set_ns(node_t *n, node_t * ns);
/** \brief comment getter function
*
* \fn node_t* roxml_get_cmt(node_t *n, int nth);
* This function returns the nth comment of a node
*
* \param n is one node of the tree
* \param nth is the id of the cmt to get
* \return the comment corresponding to id
* \see roxml_get_cmt_nb
* \see roxml_get_nodes
*
* example:
* given the following xml file
* \verbatim
<xml>
<item1/>
<!--comment1-->
<!--comment2-->
<item2/>
<item3/>
</xml>
\endverbatim
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_load_doc("/tmp/doc.xml");
* node_t *xml = roxml_get_chld(root, NULL, 0);
* node_t *cmt1 = roxml_get_cmt(xml, 0);
* node_t *cmt2 = roxml_get_cmt(xml, 1);
*
* // here cmt1 is the "comment1" node
* if(strcmp(roxml_get_content(cmt1, NULL, 0, NULL), "comment1") == 0) {
* printf("got the first comment\n");
* }
* // and cmt2 is the "comment2" node
* if(strcmp(roxml_get_content(cmt2, NULL, 0, NULL), "comment2") == 0) {
* printf("got the second comment\n");
* }
*
* roxml_close(root);
* return 0;
* }
*
* \endcode
*/
ROXML_API node_t * roxml_get_cmt(node_t *n, int nth);
/** \brief comments number getter function
*
* \fn int roxml_get_cmt_nb(node_t *n);
* This function return the number of comments for a given node
* \param n is one node of the tree
* \return the number of comments
* \see roxml_get_cmt_nb
* \see roxml_get_nodes
*/
ROXML_API int roxml_get_cmt_nb(node_t *n);
/** \brief chld getter function
*
* \fn node_t* roxml_get_chld(node_t *n, char * name, int nth);
* This function returns a given chld of a node etheir by name, or the nth child.
*
* \param n is one node of the tree
* \param name is the name of the child to get
* \param nth is the id of the chld to get
* \return the chld corresponding to name or id (if both are set, name is used)
* \see roxml_get_chld_nb
*
* example:
* given the following xml file
* \verbatim
<xml>
<item1/>
<item2/>
<item3/>
</xml>
\endverbatim
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_load_doc("/tmp/doc.xml");
*
* node_t *child_by_name = roxml_get_chld(root, "item2", 0);
* node_t *child_by_nth = roxml_get_chld(root, NULL, 2);
*
* // here child_by_name == child_by_nth
* if(child_by_name == child_by_nth) {
* printf("Nodes are equal\n");
* }
*
* roxml_close(root);
* return 0;
* }
* \endcode
*/
ROXML_API node_t * roxml_get_chld(node_t *n, char *name, int nth);
/** \brief chlds number getter function
*
* \fn int roxml_get_chld_nb(node_t *n);
* This function return the number of chlidren for a given node
* \param n is one node of the tree
* \return the number of chlildren
*/
ROXML_API int roxml_get_chld_nb(node_t *n);
/** \brief process-instruction getter function
*
* \fn node_t* roxml_get_pi(node_t *n, int nth);
* This function returns the nth process-instruction of a node.
*
* \param n is one node of the tree
* \param nth is the id of the pi to get
* \return the process-instruction corresponding to id
* \see roxml_get_pi_nb
* \see roxml_get_nodes
*
* example:
* given the following xml file
* \verbatim
<xml>
<item1/>
<?test value="2"?>
<?test param="3"?>
<item2/>
<item3/>
</xml>
\endverbatim
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_load_doc("/tmp/doc.xml");
* node_t *xml = roxml_get_chld(root, NULL, 0);
* node_t *pi1 = roxml_get_pi(xml, 0);
* node_t *pi2 = roxml_get_pi(xml, 1);
*
* // here pi1 is the <?value="2"?> node
* if(strcmp(roxml_get_content(pi1, NULL, 0, NULL), "value=\"2\"") == 0) {
* printf("got the first process-instruction\n");
* }
* // and pi2 is the <?param="3"?> node
* if(strcmp(roxml_get_content(pi2, NULL, 0, NULL), "param=\"3\"") == 0) {
* printf("got the second process-instruction\n");
* }
*
* roxml_close(root);
* return 0;
* }
*
* \endcode
*/
ROXML_API node_t * roxml_get_pi(node_t *n, int nth);
/** \brief process-instruction number getter function
*
* \fn int roxml_get_pi_nb(node_t *n);
* This function return the number of process-instruction in a given node
* \param n is one node of the tree
* \return the number of process-instructions
* \see roxml_get_pi
* \see roxml_get_nodes_nb
*/
ROXML_API int roxml_get_pi_nb(node_t *n);
/** \brief name getter function
*
* \fn char* roxml_get_name(node_t *n, char * buffer, int size);
* This function return the name of the node or fill the current buffer with it if not NULL.
* if name is NULL, the function will allocate a buffer that user should free using
* roxml_release when no longer needed.
* depending on node type it will return:
* <ul>
* <li> ROXML_ELM_NODE: returns the node name</li>
* <li> ROXML_ATTR_NODE: returns the attribute name</li>
* <li> ROXML_PI_NODE: returns the process-instruction targeted application</li>
* <li> ROXML_TXT_NODE: returns NULL (or empty string if you provided a buffer in buffer param)</li>
* <li> ROXML_CMT_NODE: returns NULL (or empty string if you provided a buffer in buffer param)</li>
* <li> ROXML_NS_NODE: returns the namespace alias associated with the ns node </li>
* </ul>
* Be carreful as if your buffer is too short for the returned string, it will be truncated
* \param n is one node of the tree
* \param buffer a buffer pointer or NULL if has to be auto allocated
* \param size the size of buffer pointed by buffer if not NULL
* \return the name of the node (return our buffer pointer if it wasn't NULL)
* \see roxml_release
*/
ROXML_API char * roxml_get_name(node_t *n, char *buffer, int size);
/** \brief content getter function
*
* \fn char * roxml_get_content(node_t *n, char * buffer, int bufsize, int * size);
*
* This function returns the content of a node.;
* if the returned pointer is NULL then the node either has no content or this function is irrelevant for this kind of node.
* depending on node type it will return:
* <ul>
* <li> ROXML_ELM_NODE: returns the concatenation of all direct text node children</li>
* <li> ROXML_ATTR_NODE: returns the attribute value</li>
* <li> ROXML_PI_NODE: returns the process-instruction instruction</li>
* <li> ROXML_TXT_NODE: returns the text content of the node</li>
* <li> ROXML_CMT_NODE: returns the text content of the comment</li>
* <li> ROXML_NS_NODE: returns the namespace definition (usually an URL)</li>
* </ul>
* returned string should be freed using roxml_release when not used anymore
* \param n is one node of the tree
* \param buffer is the buffer where result will be written or NULL for internal allocation
* \param bufsize the size if using custom buffer
* \param size the actual size of copied result. returned size should be less that buffer size since roxml_get_content
* will add the \0. if buffer was not NULL and size == buf_size, then given buffer was too small and node content was truncated
* \return the text content
* \see roxml_release
*/
ROXML_API char * roxml_get_content(node_t *n, char *buffer, int bufsize, int *size);
/** \brief number of nodes getter function
*
* \fn int roxml_get_nodes_nb(node_t *n, int type);
*
* This function returns the number of nodes matching type flag contained in a given node
* all other roxml_get_*_nb are wrapper to this
* \param n is one node of the tree
* \param type is the bitmask of node types we want to consider
* \return the number of nodes
* \see roxml_get_attr_nb
* \see roxml_get_chld_nb
* \see roxml_get_txt_nb
* \see roxml_get_cmt_nb
* \see roxml_get_pi_nb
*
* example:
* given the following xml file
* \verbatim
<xml>
<!-- comment -->
<?value="2"?>
<product id="42" class="item"/>
<product id="43" class="item"/>
</xml>
\endverbatim
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_load_doc("/tmp/doc.xml");
*
* int all_nodes_1 = roxml_get_nodes_nb(root, ROXML_ELM_NODE | ROXML_CMT_NODE | ROXML_PI_NODE | ROXML_TXT_NODE | ROXML_ATTR_NODE);
* int all_nodes_2 = roxml_get_nodes_nb(root, ROXML_ALL_NODES);
*
* // here all_nodes_1 == all_nodes_2
* if(all_nodes_1 == all_nodes_2) {
* printf("%d Nodes are contained in root\n", all_nodes_1);
* }
*
* // let's count elm node (== children)
* int elm_nodes1 = roxml_get_nodes_nb(root, ROXML_ELM_NODE);
* int elm_nodes2 = roxml_get_chld_nb(root);
* // here elm_nodes1 == elm_nodes2 == 2
* if(elm_nodes1 == elm_nodes2) {
* printf("%d ELM Nodes are contained in root\n", elm_nodes_1);
* }
*
* // we can also count all node except elm nodes, doing:
* int almost_all_nodes = roxml_get_nodes_nb(root, ROXML_ALL_NODES & ~ROXML_ELM_NODE);
* // here almost_all_nodes = 2 since we have one comment node and one processing-instruction node
* if(almost_all_nodes == 2) {
* printf("%d non ELM Nodes are contained in root\n", almost_all_nodes_1);
* }
*
* roxml_close(root);
* return 0;
* }
* \endcode
*/
ROXML_API int roxml_get_nodes_nb(node_t *n, int type);
/** \brief nodes getter function
*
* \fn char* roxml_get_nodes(node_t *n, int type, char * name, int nth);
* This function get the nth node matching type contained in a node, or the first node named name.
* All other roxml_get_* are wrapper to this function.
* When asking for several node type (let say ROXML_ALL_NODES), all ROXML_ATTR_NODE will be
* placed first, then, all other nodes will come mixed, depending on xml document order.
*
* \param n is one node of the tree
* \param type is the bitmask of node types we want to consider
* \param name is the name of the child to get. This parameter is only relevant for node with types: \ref ROXML_ELM_NODE, \ref ROXML_ATTR_NODE, \ref ROXML_PI_NODE
* \param nth the id of attribute to read
* \return the node corresponding to name or id (if both are set, name is used)
* \see roxml_get_attr
* \see roxml_get_chld
* \see roxml_get_txt
* \see roxml_get_cmt
* \see roxml_get_pi
*/
ROXML_API node_t * roxml_get_nodes(node_t *n, int type, char *name, int nth);
/** \brief number of attribute getter function
*
* \fn int roxml_get_attr_nb(node_t *n);
*
* This function returns the number of attributes for a given node
* \param n is one node of the tree
* \return the number of attributes in node
*/
ROXML_API int roxml_get_attr_nb(node_t *n);
/** \brief attribute getter function
*
* \fn node_t* roxml_get_attr(node_t *n, char * name, int nth);
* This function get the nth attribute of a node.
* \param n is one node of the tree
* \param name is the name of the attribute to get
* \param nth the id of attribute to read
* \return the attribute corresponding to name or id (if both are set, name is used)
*
* example:
* given the following xml file
* \verbatim
<xml>
<product id="42" class="item"/>
</xml>
\endverbatim
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_load_doc("/tmp/doc.xml");
* node_t *item1 = roxml_get_chld(root, NULL, 0);
* node_t *item2 = roxml_get_chld(item1, NULL, 0);
*
* node_t *attr_by_name = roxml_get_attr(item2, "id", 0);
* node_t *attr_by_nth = roxml_get_attr(item2, NULL, 0);
*
* // here attr_by_name == attr_by_nth
* if(attr_by_name == attr_by_nth) {
* printf("Nodes are equal\n");
* }
*
* roxml_close(root);
* return 0;
* }
* \endcode
*/
ROXML_API node_t * roxml_get_attr(node_t *n, char *name, int nth);
/** \brief exec path function
*
* \fn roxml_xpath(node_t *n, char * path, int *nb_ans);
* This function return a node set (table of nodes) corresponding to a given xpath.
* resulting node set should be roxml_release when not used anymore (but not individual nodes)
* \param n is one node of the tree
* \param path the xpath to use
* \param nb_ans the number of results
* \return the node table or NULL
*
* handled xpath are described in \ref xpath
*/
ROXML_API node_t ** roxml_xpath(node_t *n, char *path, int *nb_ans);
/** \brief node type function
*
* \fn roxml_get_type(node_t *n);
* This function tells if a node is an \ref ROXML_ATTR_NODE, \ref ROXML_TXT_NODE, \ref ROXML_PI_NODE, \ref ROXML_CMT_NODE or \ref ROXML_ELM_NODE.
* Warning: ROXML_CDATA_NODE are special. They return a type as ROXML_TXT_NODE.
* \param n is the node to test
* \return the node type
*/
ROXML_API int roxml_get_type(node_t *n);
/** \brief node get position function
*
* \fn roxml_get_node_position(node_t *n);
* This function tells the index of a node between all its siblings homonyns.
* \param n is the node to test
* \return the postion between 1 and N
*/
ROXML_API int roxml_get_node_position(node_t *n);
/** \brief memory cleanning function
*
* \fn roxml_release(void * data);
* This function release the memory pointed by pointer
* just like free would but for memory allocated with roxml_malloc.
* Freeing a NULL pointer won't do
* anything. roxml_release also allow you to remove all
* previously allocated memory by using \ref RELEASE_ALL as argument.
* You can also safely use \ref RELEASE_LAST argument that will release the
* previously allocated varable within the current thread (making this
* function thread safe).
* if using roxml_release on a variable non roxml_mallocated, nothing will happen (ie variable won't be freed)
* \param data the pointer to delete or NULL or \ref RELEASE_ALL or \ref RELEASE_LAST
* \return void
*/
ROXML_API void roxml_release(void *data);
/** \brief add a node to the tree
*
* \fn roxml_add_node(node_t *parent, int position, int type, char *name, char *value);
* this function add a new node to the tree. This will not update de buffer or file,
* only the RAM loaded tree. One should call \ref roxml_commit_changes to save modifications.
* If the parent node is an \ref ROXML_ELM_NODE, then, new node will be added as a child. Else
* the node will be added as a sibling of the parent node. In the later case, position parameter describes
* the position in the sibling list, instead of position in the children list.
* \param parent the parent node
* \param position the position as a child of parent 1 is the first child, 0 for auto position at the end of children list...
* \param type the type of node between \ref ROXML_ATTR_NODE, \ref ROXML_ELM_NODE, \ref ROXML_TXT_NODE, \ref ROXML_CDATA_NODE, \ref ROXML_PI_NODE, \ref ROXML_CMT_NODE, \ref ROXML_NSDEF_NODE, \ref ROXML_NS_NODE.
* \param name the name of the node (mandatory for \ref ROXML_ATTR_NODE and \ref ROXML_ELM_NODE and \ref ROXML_PI_NODE and \ref ROXML_NSDEF_NODE and \ref ROXML_NS_NODE only)
* \param value the text content (mandatory for \ref ROXML_TXT_NODE, \ref ROXML_CDATA_NODE, \ref ROXML_CMT_NODE, \ref ROXML_ATTR_NODE and \ref ROXML_NSDEF_NODE optional for \ref ROXML_ELM_NODE, \ref ROXML_PI_NODE). The text content for an attribute is the attribute value
* \return the newly created node
* \see roxml_commit_changes
* \see roxml_commit_buffer
* \see roxml_commit_file
* \see roxml_del_node
* \see roxml_close
*
* paramaters name and value depending on node type:
* - \ref ROXML_ELM_NODE take at least a node name. the parameter value is optional and represents the text content.
* - \ref ROXML_TXT_NODE ignore the node name. the parameter value represents the text content.
* - \ref ROXML_CDATA_NODE ignore the node name. the parameter value represents the text content that will be encapsulated in CDATA tags.
* - \ref ROXML_CMT_NODE ignore the node name. the parameter value represents the comment.
* - \ref ROXML_PI_NODE take the node name as process-instruction target. the parameter value represents the content of processing-instruction.
* - \ref ROXML_ATTR_NODE take an attribute name. and the attribute value as given by parameter value.
* - \ref ROXML_NSDEF_NODE take an attribute name (empty string for default namespace). and the namespace value as given by parameter value.
* - \ref ROXML_NS_NODE take an attribute name (empty string for default namespace).
*
* some examples to obtain this xml result file
\verbatim
<root>
<!-- sample XML file -->
<item id="42">
<price>
24
</price>
</item>
</root>
\endverbatim
*
* \code
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_changes(root, "/tmp/test.xml", NULL, 1);
* roxml_close(root);
* return 0;
* }
* \endcode
* Or also:
* \code
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", NULL);
* tmp = roxml_add_node(tmp, 0, ROXML_TXT_NODE, NULL, "24");
* roxml_commit_changes(root, "/tmp/test.xml", NULL, 1);
* roxml_close(root);
* return 0;
* }
* \endcode
*
* If you need a valid XML doc, just start by adding a corresponding process-instruction.
* Example, to obtain this xml file:
* \verbatim
<?xml version="1.0" encoding="UTF-8"?>
<!--sample file-->
<doc>
basic content
<item/>
<item/>
<item/>
</doc>
\endverbatim
* \code
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_add_node(NULL, 0, ROXML_PI_NODE, "xml", "version=\"1.0\" encoding=\"UTF-8\"");
* node_t *node = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample file");
* node = roxml_add_node(root, 0, ROXML_ELM_NODE, "doc", "basic content");
* roxml_add_node(node, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(node, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(node, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_commit_changes(root, "/tmp/test.xml", NULL, 1);
* roxml_close(root);
* return 0;
* }
* \endcode
*/
ROXML_API node_t * roxml_add_node(node_t *parent, int position, int type, char *name, char *value);
/** \brief text node getter function
*
* \fn roxml_get_txt(node_t *n, int nth);
* this function return the text content of a node as a \ref ROXML_TXT_NODE
* the content of the text node can be read using the roxml_get_content function
* \param n the node that contains text
* \param nth the nth text node to retrieve
* \return the text node or ROXML_INVALID_DOC (NULL)
* \see roxml_get_txt_nb
* \see roxml_get_nodes
* \see roxml_get_content
*
* example:
* given this xml file:
* \verbatim
<xml>
This is
<item/>
an example
<item/>
of text nodes
</xml>
\endverbatim
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* int len;
* node_t *root = roxml_load_doc("/tmp/doc.xml");
* node_t *item = roxml_get_chld(root, NULL, 0);
*
* node_t *text = roxml_get_txt(item, 0);
* char * text_content = roxml_get_content(text, NULL, 0, &len);
* // HERE text_content is equal to "This is"
* printf("text_content = '%s'\n", text_content);
*
* text = roxml_get_txt(item, 1);
* text_content = roxml_get_content(text, NULL, 0, &len);
* // HERE text_content is equal to "an example"
* printf("text_content = '%s'\n", text_content);
*
* text = roxml_get_txt(item, 2);
* text_content = roxml_get_content(text, NULL, 0, &len);
* // HERE text_content is equal to "of text nodes"
* printf("text_content = '%s'\n", text_content);
*
* roxml_close(item);
* return 0;
* }
* \endcode
*/
ROXML_API node_t * roxml_get_txt(node_t *n, int nth);
/** \brief text node number getter function
*
* \fn roxml_get_txt_nb(node_t *n);
* this function return the number of text nodes in
* a standard node
* \param n the node to search into
* \return the number of text node
* \see roxml_get_txt
*/
ROXML_API int roxml_get_txt_nb(node_t *n);
/** \brief node deletion function
*
* \fn roxml_del_node(node_t *n);
* this function delete a node from the tree. The node is not really deleted
* from the file or buffer until the roxml_commit_changes is called, but it won't be
* visible anymore in the XML tree.
* \param n the node to delete
* \return
* \see roxml_add_node
* \see roxml_commit_changes
* \see roxml_commit_buffer
* \see roxml_commit_file
*
* \warning when removing a nsdef node, all node using this namespace will be updated and inherit their parent namespace
*/
ROXML_API void roxml_del_node(node_t *n);
/** \brief sync function
*
* \fn roxml_commit_changes(node_t *n, char * dest, char ** buffer, int human);
* \deprecated
* this function sync changes from the RAM tree to the given buffer or file in human or one-line format
* The tree will be processed starting with the root node 'n' and following with all its children or if n is the root, all its siblings and children.
* The tree will be dumped to a file if 'dest' is not null and contains a valid path.
* The tree will be dumped to a buffer if 'buffer' is not null. the buffer is allocated by the library
* and a pointer to it will be stored into 'buffer'. The allocated buffer can be freed usinf free()
* \warning in the case of a tree loaded using roxml_load_doc, the roxml_commit_changes cannot be done to that same file
* since it may override datas it need. This usually result in a new file filled with garbages. The solution is to write it to a temporary file and rename it after roxml_close the current tree.
*
* This function is now deprecated and one should use roxml_commit_buffer or roxml_commit_file that achieves the exact same goal.
*
* \param n the root node of the tree to write
* \param dest the path to a file to write tree to
* \param buffer the address of a buffer where the tree will be written. This buffer have to be freed after use
* \param human 0 for one-line tree, or 1 for human format (using tabs, newlines...)
* \return the number of bytes written to file or buffer
* \see roxml_commit_buffer
* \see roxml_commit_file
*
* This is a legacy function that proposes the same functionnalities as both
* \c roxml_commit_file and \c roxml_commit_buffer. New code should use the
* latter functions when needed.
*
* One should do:
* \code
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_changes(root, "/tmp/test.xml", NULL, 1);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root>
<!-- sample XML file -->
<item id="42">
<price>
24
</price>
</item>
</root>
\endverbatim
* or also
* \code
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_changes(root, "/tmp/test.xml", NULL, 0);
* roxml_close(root);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root><!-- sample XML file --><item id="42"><price>24</price></item></root>
\endverbatim
* the buffer variant works more or less the same way
* \code
* #include <stdio.h>
* #include <roxml.h>
*
* int main(void)
* {
* int len = 0;
* char * buffer = NULL;
* FILE * file_out;
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
*
* len = roxml_commit_changes(root, NULL, &buffer, 0);
*
* file_out = fopen("/tmp/test.xml", "w");
* fwrite(buffer, 1, len, file_out);
* fclose(file_out);
*
* roxml_close(root);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root><!-- sample XML file --><item id="42"><price>24</price></item></root>
\endverbatim
* \see roxml_commit_file
* \see roxml_commit_buffer
* \see roxml_commit_fd
*/
ROXML_API int roxml_commit_changes(node_t *n, char *buffer, int human);
/** \brief sync to named file function
*
* \fn roxml_commit_file(node_t *n, char * dest, int human);
* this function sync changes from the RAM tree to the given file in human or one-line format
* The tree will be processed starting with the root node 'n' and following with all its children or if n is the root, all its siblings and children.
* The tree will be dumped to a file if 'dest' is not null and contains a valid path.
* \warning in the case of a tree loaded using roxml_load_doc, the roxml_commit_file cannot be done to that same file
* since it may override datas it needs. This usually resultis in a new file filled with garbage. The solution is to write it to a temporary file and rename it after roxml_close the current tree.
*
* \param n the root node of the tree to write
* \param dest the path to a file to write tree to
* \param human 0 for one-line tree, or 1 for human format (using tabs, newlines...)
* \return the number of bytes written to file or buffer
*
* One should do:
* \code
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_file(root, "/tmp/test.xml", 1);
* roxml_close(root);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root>
<!-- sample XML file -->
<item id="42">
<price>
24
</price>
</item>
</root>
\endverbatim
* or also
* \code
* #include <roxml.h>
*
* int main(void)
* {
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_file(root, "/tmp/test.xml", 0);
* roxml_close(root);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root><!-- sample XML file --><item id="42"><price>24</price></item></root>
\endverbatim
* \see roxml_commit_changes
* \see roxml_commit_buffer
* \see roxml_commit_fd
*/
ROXML_API int roxml_commit_file(node_t *n, char *dest, int human);
/** \brief sync to a memory buffer function
*
* \fn roxml_commit_buffer(node_t *n, char ** buffer, int human);
* this function syncs changes from the RAM tree to the given buffer in human or one-line format
* The tree will be processed starting with the root node 'n' and following with all its children or if n is the root, all its siblings and children.
* The tree will be dumped to a buffer if 'buffer' is not null. the buffer is allocated by the library
* and a pointer to it will be stored into 'buffer'. The allocated buffer can be freed using free()
*
* \param n the root node of the tree to write
* \param buffer the address of a buffer where the tree will be written. This buffer have to be freed after use
* \param human 0 for one-line tree, or 1 for human format (using indentation, newlines...)
* \return the number of bytes written to file or buffer
*
* One should do:
* \code
* #include <roxml.h>
*
* int main(void)
* {
* char *buffer = NULL;
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_changes(root, &buffer, 1);
* roxml_close(root);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root>
<!-- sample XML file -->
<item id="42">
<price>
24
</price>
</item>
</root>
\endverbatim
* or also
* \code
* #include <roxml.h>
*
* int main(void)
* {
* char *buffer = NULL;
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_buffer(root, &buffer, 0);
* roxml_close(root);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root><!-- sample XML file --><item id="42"><price>24</price></item></root>
\endverbatim
* \see roxml_commit_changes
* \see roxml_commit_file
* \see roxml_commit_fd
*/
ROXML_API int roxml_commit_buffer(node_t *n, char **buffer, int human);
/** \brief sync to file descriptor function
*
* \fn roxml_commit_fd(node_t *n, int fd, int human);
* this function synchronizes changes from the RAM tree to the given file in human or one-line format.
* The tree will be processed starting with the root node 'n' and following with all its children or if n is the root, all its siblings and children.
* The tree will be dumped to a file if fd is a valid file descriptor.
* \warning in the case of a tree loaded using roxml_load_doc, the roxml_commit_fd cannot be done to that same file
* since it may override datas it needs. This usually results in a new file filled with garbage. The solution is to write it to a temporary file and rename it after roxml_close the current tree.
*
* \param n the root node of the tree to write
* \param fd the file descriptor to write tree to
* \param human 0 for one-line tree, or 1 for human format (using tabs, newlines...)
* \return the number of bytes written to file
*
* The file described by fd is not truncated so this function allows one to append an XML subtree to an existing file.
*
* One should do:
* \code
* #include <roxml.h>
*
* int main(void)
* {
* int fd = open("/tmp/test.xml", O_TRUNC|O_WRONLY, 0666);
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_fd(root, fd, 1);
* roxml_close(root);
* close(fd);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root>
<!-- sample XML file -->
<item id="42">
<price>
24
</price>
</item>
</root>
\endverbatim
* or also
* \code
* #include <roxml.h>
*
* int main(void)
* {
* int fd = open("/tmp/test.xml", O_TRUNC|O_WRONLY, 0666);
* node_t *root = roxml_add_node(NULL, 0, ROXML_ELM_NODE, "xml", NULL);
* node_t *tmp = roxml_add_node(root, 0, ROXML_CMT_NODE, NULL, "sample XML file");
* tmp = roxml_add_node(root, 0, ROXML_ELM_NODE, "item", NULL);
* roxml_add_node(tmp, 0, ROXML_ATTR_NODE, "id", "42");
* tmp = roxml_add_node(tmp, 0, ROXML_ELM_NODE, "price", "24");
* roxml_commit_fd(root, fd, 0);
* roxml_close(root);
* close(fd);
* return 0;
* }
* \endcode
* to generate the following xml bloc:
\verbatim
<root><!-- sample XML file --><item id="42"><price>24</price></item></root>
\endverbatim
* \see roxml_commit_changes
* \see roxml_commit_file
* \see roxml_commit_buffer
*/
ROXML_API int roxml_commit_fd(node_t *n, int fd, int human);
char *roxml_process_special_characters(char *input);
void roxml_init();
void roxml_clean_buffer();
ROXML_API char *roxml_get_ns_name(node_t *n, char *buffer, int bufsize);
ROXML_API char *roxml_get_ns_content(node_t *n, char *buffer, int bufsize, int *size);
ROXML_API char *roxml_get_node_name(node_t *n, char *buffer, int bufsize);
#ifdef __cplusplus
}
#endif
#endif /* ROXML_H */