| /******************************************************************************* |
| * Copyright (C) 2004-2006 Intel Corp. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * - Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * - 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. |
| * |
| * - Neither the name of Intel Corp. nor the names of its |
| * contributors may be used to endorse or promote products derived from this |
| * software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 Intel Corp. OR THE 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. |
| *******************************************************************************/ |
| |
| /** |
| * @author Anas Nashif |
| * @author Eugene Yarmosh |
| */ |
| #ifdef HAVE_CONFIG_H |
| #include <wsman_config.h> |
| #endif |
| |
| |
| #include "u/libu.h" |
| #include "wsman-xml-api.h" |
| #include "wsman-client-api.h" |
| #include "wsman-soap.h" |
| #include "wsman-xml.h" |
| #include "wsman-xml-binding.h" |
| #include "wsman-names.h" |
| /** |
| * @defgroup XMLParserGeneric Generic XML Parser Interface |
| * @brief Generic XML Parser interface functions |
| * |
| * @{ |
| */ |
| |
| /** |
| * Create default namespace prefix |
| * @param node XML node |
| * @param uri Namespace URI |
| * @param buf Text buffer |
| * @param bufsize Buffer size |
| */ |
| struct __WsXmlNsData |
| { |
| char* uri; |
| char* prefix; |
| }; |
| typedef struct __WsXmlNsData WsXmlNsData; |
| |
| static WsXmlNsData g_wsNsData[] = |
| { |
| {XML_NS_SOAP_1_2, "s"}, |
| {XML_NS_ADDRESSING, "wsa"}, |
| {XML_NS_EVENTING, "wse"}, |
| {XML_NS_ENUMERATION, "wsen"}, |
| {XML_NS_SCHEMA_INSTANCE, "xsi"}, |
| {XML_NS_CIM_SCHEMA, "cim"}, |
| {XML_NS_WS_MAN_CAT, "cat"}, |
| {XML_NS_WSMAN_ID, "wsmid"}, |
| {XML_NS_XML_SCHEMA, "xs"}, |
| {XML_NS_WS_MAN, "wsman"}, |
| {XML_NS_CIM_BINDING, "wsmb"}, |
| {XML_NS_OPENWSMAN, "owsman"}, |
| {XML_NS_TRANSFER, "wxf"}, |
| {XML_NS_XML_NAMESPACES,"xml"}, |
| {NULL, NULL} |
| }; |
| |
| void |
| ws_xml_make_default_prefix(WsXmlNodeH node, |
| const char *uri, char *buf, int bufsize) |
| { |
| WsXmlDocH doc = xml_parser_get_doc(node); |
| int i = 0; |
| if (doc != NULL && uri != NULL) { |
| for (i = 0; g_wsNsData[i].uri != NULL; i++) { |
| WsXmlNsData *nsd = &g_wsNsData[i]; |
| if (strcmp(uri, nsd->uri) == 0 && nsd->prefix) { |
| snprintf(buf, bufsize, "%s", nsd->prefix ); |
| return; |
| } |
| } |
| } |
| if(g_wsNsData[i].uri == NULL && bufsize >= 12) |
| snprintf(buf, bufsize, "n%lu", ++doc->prefixIndex); |
| else |
| buf[0] = 0; |
| } |
| |
| static int is_xml_val_true(const char *text) |
| { |
| int retVal = 0; |
| |
| if (text) { |
| const char *ptr = text; |
| |
| while (isdigit(*ptr)) |
| ptr++; |
| |
| if (*ptr) { |
| if (!strcasecmp(text, "true") || |
| !strcasecmp(text, "yes")) |
| retVal = 1; |
| } else { |
| if (atoi(text) != 0) |
| retVal = 1; |
| } |
| } |
| |
| return retVal; |
| } |
| |
| /** |
| * Enumerate namespaces in a node |
| * @param node XML node |
| * @param callback Namespace Enumeration callback |
| * @param data Callback data |
| */ |
| static int |
| ns_enum_at_node(WsXmlNodeH node, WsXmlNsEnumCallback callback, void *data) |
| { |
| int retVal = 0; |
| |
| if (node) { |
| int i; |
| WsXmlNsH ns; |
| |
| for (i = 0; (ns = ws_xml_get_ns(node, i)) != NULL; i++) { |
| if ((retVal = callback(node, ns, data)) != 0) |
| break; |
| } |
| } |
| return retVal; |
| } |
| |
| |
| static char *make_qname(WsXmlNodeH node, const char *uri, const char *name) |
| { |
| char *buf = NULL; |
| if (name && uri && name) { |
| size_t len = 1 + strlen(name); |
| WsXmlNsH ns = xml_parser_ns_find(node, uri, NULL, 1, 1); |
| const char *prefix = |
| (!ns) ? NULL : ws_xml_get_ns_prefix(ns); |
| |
| if (prefix != NULL) |
| len += 1 + strlen(prefix); |
| |
| if ((buf = u_malloc(len)) != NULL) { |
| if (prefix != NULL && name != NULL) |
| sprintf(buf, "%s:%s", prefix, name); |
| else |
| strcpy(buf, name); |
| } |
| } |
| return buf; |
| } |
| |
| |
| /** |
| * Add QName attribute |
| * @param node Parent XML node |
| * @param nameNs Child Namespace |
| * @param name Child Name |
| * @param valueNs Namespace for value |
| * @param value Child Value |
| * @return Child XML node |
| * @note |
| * if namespaces has been changed after this function is called, itis caller's |
| * responsibility to update QName fields accordingly |
| */ |
| WsXmlAttrH ws_xml_add_qname_attr(WsXmlNodeH node, |
| const char *nameNs, |
| const char *name, |
| const char *valueNs, const char *value) |
| { |
| WsXmlAttrH attr = NULL; |
| |
| if (name && node && valueNs && value) { |
| char *buf = make_qname(node, valueNs, value); |
| if (buf != NULL) { |
| attr = |
| ws_xml_add_node_attr(node, nameNs, name, buf); |
| u_free(buf); |
| } |
| } |
| |
| return attr; |
| } |
| |
| /** |
| * Enumerate namespaces |
| * @param node XML node |
| * @param callback enumeration callback |
| * @param data Callback data |
| * @param bWalkUpTree Flag FIXME |
| * @brief Enumerates all namespaces defined at the node and optionally (if bIncludeParents isn't zero) |
| * walks up the parent chain |
| */ |
| void ws_xml_ns_enum(WsXmlNodeH node, |
| WsXmlNsEnumCallback callback, |
| void *data, int bWalkUpTree) |
| { |
| while (node) { |
| if (ns_enum_at_node(node, callback, data) || !bWalkUpTree) |
| break; |
| node = ws_xml_get_node_parent(node); |
| } |
| } |
| |
| |
| |
| /** |
| * Create an empty envelope with a <b>Header</b> and a <b>Body</b> |
| * @param soap Soap handler |
| * @param soapVersion The SOAP version to be used for creating the envelope |
| * @return An XMl document |
| */ |
| WsXmlDocH ws_xml_create_envelope( void ) |
| { |
| WsXmlDocH doc = NULL; |
| |
| if ((doc = ws_xml_create_doc(XML_NS_SOAP_1_2, SOAP_ENVELOPE)) != NULL) { |
| WsXmlNodeH root = ws_xml_get_doc_root(doc); |
| |
| if (root == NULL || |
| ws_xml_add_child(root, XML_NS_SOAP_1_2, "Header", NULL) == NULL || |
| ws_xml_add_child(root, XML_NS_SOAP_1_2, "Body", NULL) == NULL) { |
| ws_xml_destroy_doc(doc); |
| doc = NULL; |
| } |
| } |
| |
| return doc; |
| } |
| |
| |
| /** |
| * Duplicate an XML document |
| * @param dstSoap Destination SOAP handle |
| * @param srcDoc the Source document |
| * @return The new XML document |
| */ |
| WsXmlDocH ws_xml_duplicate_doc( WsXmlDocH srcDoc) |
| { |
| WsXmlDocH dst = NULL; |
| WsXmlNodeH srcRoot = NULL; |
| const char *name, *nsUri; |
| |
| if (!srcDoc) |
| return NULL; |
| |
| srcRoot = ws_xml_get_doc_root(srcDoc); |
| |
| if (!srcRoot) |
| return NULL; |
| |
| name = ws_xml_get_node_local_name(srcRoot); |
| nsUri = ws_xml_get_node_name_ns(srcRoot); |
| if ((dst = ws_xml_create_doc(nsUri, name)) != NULL) { |
| int i; |
| WsXmlNodeH node; |
| WsXmlNodeH dstRoot = ws_xml_get_doc_root(dst); |
| |
| for (i = 0; (node = ws_xml_get_child(srcRoot, |
| i, NULL, NULL)) != NULL; i++) { |
| ws_xml_duplicate_tree(dstRoot, node); |
| } |
| } |
| return dst; |
| } |
| |
| |
| /** |
| * Duplicate an XML attribute |
| * @param dstNode Destination XML node |
| * @param srcNode Source Node |
| */ |
| void ws_xml_duplicate_attr(WsXmlNodeH dstNode, WsXmlNodeH srcNode) |
| { |
| int i; |
| WsXmlAttrH attr; |
| for (i = 0; (attr = ws_xml_get_node_attr(srcNode, i)) != NULL; i++) { |
| ws_xml_add_node_attr(dstNode, |
| ws_xml_get_attr_ns(attr), |
| ws_xml_get_attr_name(attr), |
| ws_xml_get_attr_value(attr)); |
| } |
| } |
| |
| /** |
| * Duplicate children of an XML node |
| * @param dstNode Destination XML node |
| * @param srcNode Source XML node |
| */ |
| int ws_xml_duplicate_children(WsXmlNodeH dstNode, WsXmlNodeH srcNode) |
| { |
| int i; |
| WsXmlNodeH child; |
| for (i = 0; |
| (child = ws_xml_get_child(srcNode, i, NULL, NULL)) != NULL; |
| i++) { |
| ws_xml_duplicate_tree(dstNode, child); |
| } |
| return i; |
| } |
| |
| |
| /** |
| * Duplication complete XML tree |
| * @param dstNode Destination XML node |
| * @param srcNode Source XML node |
| */ |
| void ws_xml_duplicate_tree(WsXmlNodeH dstNode, WsXmlNodeH srcNode) |
| { |
| WsXmlNodeH node; |
| if (!srcNode || !dstNode) { |
| error("NULL arguments: dst = %p; src = %p", dstNode, |
| srcNode); |
| return; |
| } |
| node = ws_xml_add_child(dstNode, |
| ws_xml_get_node_name_ns(srcNode), |
| ws_xml_get_node_local_name(srcNode), NULL); |
| if (!node) { |
| error("could not add node"); |
| return; |
| } |
| ws_xml_duplicate_attr(node, srcNode); |
| if (ws_xml_duplicate_children(node, srcNode) == 0) { |
| // no children |
| ws_xml_set_node_text(node, ws_xml_get_node_text(srcNode)); |
| } |
| } |
| |
| |
| void ws_xml_copy_node(WsXmlNodeH src, WsXmlNodeH dst) |
| { |
| xml_parser_copy_node(src, dst); |
| } |
| |
| |
| int ws_xml_utf8_strlen(char *buf) |
| { |
| return xml_parser_utf8_strlen(buf); |
| } |
| |
| /** |
| * Dump XML document contents into a Text buffer |
| * @param doc XML document |
| * @param buf The target buffer |
| * @param ptrSize the size of the buffer |
| * @param encoding The encoding to be used |
| */ |
| void ws_xml_dump_memory_enc(WsXmlDocH doc, char **buf, int *ptrSize, |
| const char *encoding) |
| { |
| xml_parser_doc_to_memory(doc, buf, ptrSize, encoding); |
| } |
| |
| |
| |
| /** |
| * Free Memory |
| * @param ptr Pointer to be freed |
| */ |
| void ws_xml_free_memory(void *ptr) |
| { |
| xml_parser_free_memory(ptr); |
| } |
| |
| WsXmlDocH ws_xml_clone_and_create_doc(WsXmlDocH doc, |
| const char *rootNsUri, |
| const char *rootName ) |
| { |
| return ws_xml_create_doc(rootNsUri, rootName); |
| } |
| |
| /** |
| * Initialize XML Parser |
| * @param soap SOAP handle |
| * @param nsData Array with namespace data |
| */ |
| int ws_xml_parser_initialize() |
| { |
| xml_parser_initialize(); |
| return 1; |
| } |
| |
| |
| void ws_xml_parser_destroy() |
| { |
| xml_parser_destroy(); |
| } |
| |
| |
| |
| /** |
| * Get SOAP envelope header |
| * @param doc XML document (Envelope) |
| * @return XML node of the Header |
| */ |
| WsXmlNodeH ws_xml_get_soap_header(WsXmlDocH doc) |
| { |
| return ws_xml_get_soap_element(doc, SOAP_HEADER); |
| } |
| |
| |
| /** |
| * Enumerate Children |
| * @param parent XML node parent |
| * @param callback Enumeration callback |
| * @param data Callback data |
| * @param bRecursive Recursive flag |
| * @return |
| * |
| */ |
| int |
| ws_xml_enum_children(WsXmlNodeH parent, |
| WsXmlEnumCallback callback, |
| void *data, int bRecursive) |
| { |
| int retVal = 0; |
| int i; |
| WsXmlNodeH child; |
| |
| for (i = 0; |
| (child = ws_xml_get_child(parent, i, NULL, NULL)) != NULL; i++) { |
| if ((retVal = |
| ws_xml_enum_tree(child, callback, data, |
| bRecursive))) { |
| break; |
| } |
| } |
| return retVal; |
| } |
| |
| |
| /** |
| * Get count of children |
| * @param parent XML Node parent |
| * @return Count of children in node |
| */ |
| int ws_xml_get_child_count(WsXmlNodeH parent) |
| { |
| int count = 0; |
| if (parent) |
| count = xml_parser_get_count(parent, XML_COUNT_NODE, 0); |
| return count; |
| } |
| |
| |
| /** |
| * Enumerate XML tree |
| * @param top Top XML node |
| * @param callback Emumeration callback |
| * @param data Callback data |
| * @param bRecursive Recursive flag |
| */ |
| int ws_xml_enum_tree(WsXmlNodeH top, WsXmlEnumCallback callback, |
| void *data, int bRecursive) |
| { |
| int retVal = 0; |
| if (top) { |
| if (!(retVal = callback(top, data)) && bRecursive) { |
| retVal = ws_xml_enum_children(top, callback, data, bRecursive); |
| } |
| } |
| return retVal; |
| } |
| |
| |
| /** |
| * Get node namespace |
| * @param node XML node |
| * @return Namespace of node |
| */ |
| char *ws_xml_get_node_name_ns(WsXmlNodeH node) |
| { |
| char *uri = NULL; |
| if (node) |
| uri = xml_parser_node_query(node, XML_NS_URI); |
| |
| return uri; |
| } |
| |
| |
| /** |
| * Get node local name |
| * @param node XML node |
| * @return Node local name |
| */ |
| char *ws_xml_get_node_local_name(WsXmlNodeH node) |
| { |
| char *name = NULL; |
| if (node) |
| name = xml_parser_node_query(node, XML_LOCAL_NAME); |
| return name; |
| } |
| |
| |
| /** |
| * Get XML Document root |
| * @param doc XML document |
| * @return XML root node |
| */ |
| WsXmlNodeH ws_xml_get_doc_root(WsXmlDocH doc) |
| { |
| WsXmlNodeH node = NULL; |
| if (doc != NULL) |
| node = xml_parser_get_root(doc); |
| return node; |
| } |
| |
| /** |
| * Get Node text |
| * @param node XML node |
| * @return XML node text |
| */ |
| char *ws_xml_get_node_text(WsXmlNodeH node) |
| { |
| char *text = NULL; |
| if (node) { |
| text = xml_parser_node_query(node, XML_TEXT_VALUE); |
| } |
| return text; |
| } |
| |
| /** |
| * Read memory buffer into an XMl document |
| * @param soap SOAP handler |
| * @param buf Text buffer with XML string |
| * @param size Buffer size |
| * @param encoding Buffer encoding |
| * @param options Parser options |
| * @return XML document |
| */ |
| WsXmlDocH ws_xml_read_memory( const char *buf, size_t size, const char *encoding, |
| unsigned long options) |
| { |
| return xml_parser_memory_to_doc(buf, size, encoding, options); |
| } |
| |
| |
| WsXmlDocH ws_xml_read_file(const char *filename, |
| const char *encoding, unsigned long options) |
| { |
| return xml_parser_file_to_doc( filename, encoding, options); |
| } |
| |
| |
| /** |
| * Create XML document |
| * @param soap SOAP handler |
| * @param rootNsUri Root Namespace URI |
| * @param rootName Root node name |
| * @return XML document |
| */ |
| WsXmlDocH |
| ws_xml_create_doc( const char *rootNsUri, const char *rootName) |
| { |
| WsXmlDocH wsDoc = (WsXmlDocH) u_zalloc(sizeof(*wsDoc)); |
| WsXmlNodeH rootNode; |
| WsXmlNsH ns; |
| char prefix[12]; |
| |
| if (wsDoc == NULL) { |
| error("No memory"); |
| return NULL; |
| } |
| if (!xml_parser_create_doc(wsDoc, rootName) ) { |
| error("xml_parser_create_doc failed"); |
| u_free(wsDoc); |
| return NULL; |
| } |
| |
| if (rootNsUri == NULL) { |
| return wsDoc; |
| } |
| |
| rootNode = ws_xml_get_doc_root((WsXmlDocH) wsDoc); |
| |
| ws_xml_make_default_prefix(rootNode, rootNsUri, prefix, |
| sizeof(prefix)); |
| ns = xml_parser_ns_add(rootNode, rootNsUri, prefix); |
| if (ns == NULL) { |
| error("xml_parser_ns_add failed"); |
| ws_xml_destroy_doc(wsDoc); |
| return NULL; |
| } |
| ws_xml_set_node_name(rootNode, rootNsUri, NULL); |
| return wsDoc; |
| } |
| |
| |
| |
| /** |
| * Set node name |
| * @param node XML node |
| * @param nsUri Namespace URI |
| * @param name Node name |
| * @return status |
| * |
| */ |
| int ws_xml_set_node_name(WsXmlNodeH node, const char *nsUri, |
| const char *name) |
| { |
| int retVal = -1; |
| |
| if (node && (name || nsUri)) { |
| if (name) |
| retVal = |
| xml_parser_node_set(node, XML_LOCAL_NAME, |
| name); |
| else |
| retVal = 0; |
| |
| if (!retVal && nsUri) |
| retVal = |
| xml_parser_node_set(node, XML_NS_URI, nsUri); |
| } |
| |
| return retVal; |
| } |
| |
| |
| |
| |
| /** |
| * Destroy XML document |
| * @param doc XML document |
| */ |
| void ws_xml_destroy_doc(WsXmlDocH doc) |
| { |
| if (doc) { |
| xml_parser_destroy_doc(doc); |
| u_free(doc); |
| } |
| } |
| |
| |
| |
| /** |
| * Callback for finding objects in tree |
| * @param node XML node |
| * @param _data Callback data |
| * @return status |
| */ |
| static int find_in_tree_callback(WsXmlNodeH node, void *_data) |
| { |
| FindInTreeCallbackData *data = (FindInTreeCallbackData *) _data; |
| int retVal = ws_xml_is_node_qname(node, data->ns, data->name); |
| |
| if (retVal) |
| data->node = node; |
| |
| return retVal; |
| } |
| |
| /** |
| * Find node in XML tree |
| * @param head Head XML node |
| * @param nsUri Namespace URI, NULL for wildcard |
| * @param localName Node local name |
| * @param bRecursive Recursive flag |
| * @return Result XML node |
| */ |
| WsXmlNodeH ws_xml_find_in_tree(WsXmlNodeH head, const char *nsUri, |
| const char *localName, int bRecursive) |
| { |
| FindInTreeCallbackData data; |
| |
| data.node = NULL; |
| data.ns = nsUri; |
| data.name = localName; |
| |
| ws_xml_enum_tree(head, find_in_tree_callback, &data, bRecursive); |
| |
| return data.node; |
| } |
| |
| |
| /** |
| * Get SOAP body |
| * @param doc XML document |
| * @return Result XML node |
| */ |
| WsXmlNodeH ws_xml_get_soap_body(WsXmlDocH doc) |
| { |
| return ws_xml_get_soap_element(doc, SOAP_BODY); |
| } |
| |
| |
| |
| /** |
| * Get SOAP element |
| * @param doc XML document |
| * @param name Node name |
| * @return Result XML node |
| */ |
| WsXmlNodeH ws_xml_get_soap_element(WsXmlDocH doc, const char *name) |
| { |
| WsXmlNodeH node = NULL; |
| WsXmlNodeH env = ws_xml_get_soap_envelope(doc); |
| char *soapUri = NULL; |
| |
| if (!env) |
| return NULL; |
| soapUri = ws_xml_get_node_name_ns(env); |
| node = ws_xml_get_child(env, 0, NULL, NULL); |
| if (!node) |
| return NULL; |
| if (!ws_xml_is_node_qname(node, soapUri, name)) { |
| if (strcmp(name, SOAP_HEADER) != 0) { |
| node = ws_xml_get_child(env, 1, NULL, NULL); |
| if (node) { |
| if (!ws_xml_is_node_qname(node, soapUri, name)) |
| node = NULL; |
| } |
| } |
| } |
| return node; |
| } |
| |
| /** |
| * Get XML child of a node |
| * @param parent Parent node |
| * @param index Index of the node to be returned |
| * @param nsUri Namespace URI |
| * @param localName Local name of the node |
| * @return Result XML node |
| */ |
| WsXmlNodeH |
| ws_xml_get_child(WsXmlNodeH parent, |
| int index, const char *nsUri, const char *localName) |
| { |
| WsXmlNodeH node = NULL; |
| |
| if (parent && index >= 0) { |
| if (nsUri == NULL && localName == NULL) |
| node = xml_parser_node_get(parent, index); |
| else { |
| int count = 0; |
| node = xml_parser_get_first_child(parent); |
| while (node != NULL) { |
| if (ws_xml_is_node_qname (node, nsUri, localName)) { |
| if (count == index) |
| break; |
| count++; |
| } |
| node = xml_parser_get_next_child(node); |
| } |
| } |
| } |
| |
| return node; |
| } |
| |
| /** |
| * Is the XML node a qualified name |
| * @param node XML node |
| * @param nsUri Namespace URI |
| * @param name node name |
| * @return Returns 1 if node is QName |
| * @brief Shortcats for QName manipulation name can be NULL, in this case just check namespace |
| */ |
| int ws_xml_is_node_qname(WsXmlNodeH node, const char *nsUri, |
| const char *name) |
| { |
| int retVal = 0; |
| char *nodeNsUri = NULL; |
| if (!node) |
| return 0; |
| nodeNsUri = ws_xml_get_node_name_ns(node); |
| if ((nsUri == NULL) |
| || (nsUri == nodeNsUri) |
| || (nsUri != NULL && nodeNsUri != NULL && !strcmp(nodeNsUri, nsUri))) { |
| if (name == NULL || !strcmp(name, ws_xml_get_node_local_name(node))) |
| retVal = 1; |
| } |
| return retVal; |
| } |
| |
| |
| /** |
| * Count number of XML node children with same qualified name |
| * (used to represent array elements) |
| * @param parent XML node |
| * @param nsUri Namespace URI |
| * @param name children name to look for |
| * @return Returns number of children of parent with this name |
| * @brief Identical to ws_xml_get_child_count() if nsUri==NULL and name==NULL |
| */ |
| int |
| ws_xml_get_child_count_by_qname(WsXmlNodeH parent, |
| const char *nsUri, const char *name) |
| { |
| WsXmlNodeH node; |
| int count; |
| |
| if (!parent) |
| return 0; |
| if (nsUri == NULL && name == NULL) { |
| return ws_xml_get_child_count(parent); |
| } |
| node = xml_parser_get_first_child(parent); |
| count = 0; |
| while (node != NULL) { |
| if (ws_xml_is_node_qname(node, nsUri, name)) { |
| count++; |
| } |
| node = xml_parser_get_next_child(node); |
| } |
| return count; |
| } |
| |
| |
| WsXmlDocH ws_xml_create_soap_envelope(void) |
| { |
| return ws_xml_create_envelope(); |
| } |
| |
| |
| /** |
| * Get SOAP envelope |
| * @param doc XML document |
| * @return XML node with envelope |
| */ |
| WsXmlNodeH ws_xml_get_soap_envelope(WsXmlDocH doc) |
| { |
| WsXmlNodeH root = ws_xml_get_doc_root(doc); |
| if (ws_xml_is_node_qname(root, XML_NS_SOAP_1_2, SOAP_ENVELOPE) |
| || ws_xml_is_node_qname(root, XML_NS_SOAP_1_1, SOAP_ENVELOPE)) { |
| return root; |
| } |
| return NULL; |
| } |
| |
| |
| |
| /** |
| * Get Node parent |
| * @param node XML node |
| * @return Node parent |
| */ |
| WsXmlNodeH ws_xml_get_node_parent(WsXmlNodeH node) |
| { |
| WsXmlNodeH parent = NULL; |
| if (node != NULL) |
| parent = xml_parser_node_get(node, XML_ELEMENT_PARENT); |
| |
| return parent; |
| } |
| |
| /** |
| * Callback for finding Namespaces |
| * @param node XML node |
| * @param ns Namespace |
| * @param _data Callback Data |
| * @return status |
| */ |
| static int |
| ws_xml_find_ns_callback(WsXmlNodeH node, WsXmlNsH ns, void *_data) |
| { |
| WsXmlFindNsData *data = (WsXmlFindNsData *) _data; |
| char *curUri = ws_xml_get_ns_uri(ns); |
| char *curPrefix = ws_xml_get_ns_prefix(ns); |
| // debug("uri: %s prefix: %s", curUri, curPrefix ); |
| |
| if ((data->nsUri != NULL && !strcmp(curUri, data->nsUri)) |
| || |
| (data->prefix != NULL && curPrefix != NULL && |
| !strcmp(curPrefix, data->prefix)) |
| || (data->nsUri == NULL && data->prefix == NULL && |
| curPrefix == NULL)) { |
| data->node = node; |
| data->ns = ns; |
| } |
| |
| return (data->ns != NULL); |
| } |
| |
| |
| /** |
| * Find namespace in an XML node |
| * @param node XML node |
| * @param nsUri Namespace URI |
| * @param prefix Prefix |
| * @param bWalkUpTree Flag FIXME |
| * @brief |
| * Looks up nsUri defined at the node and optionally |
| * (if bIncludeParents isn't zero) walks up the parent chain |
| * returns prefix for the namespace and node where it defined |
| */ |
| WsXmlNsH |
| ws_xml_find_ns(WsXmlNodeH node, |
| const char *nsUri, const char *prefix, int bWalkUpTree) |
| { |
| WsXmlFindNsData data; |
| |
| data.node = NULL; |
| data.ns = NULL; |
| data.nsUri = nsUri; |
| data.prefix = prefix; |
| |
| if ((nsUri || prefix) && node) |
| ws_xml_ns_enum(node, ws_xml_find_ns_callback, &data, |
| bWalkUpTree); |
| |
| return data.ns; |
| } |
| |
| |
| char *ws_xml_get_node_name_ns_prefix(WsXmlNodeH node) |
| { |
| char *prefix = NULL; |
| if (node) |
| prefix = xml_parser_node_query(node, XML_NS_PREFIX); |
| return prefix; |
| |
| } |
| |
| char *ws_xml_get_node_name_ns_uri(WsXmlNodeH node) |
| { |
| char *uri = NULL; |
| if (node) |
| uri = xml_parser_node_query(node, XML_NS_URI); |
| return uri; |
| |
| } |
| |
| |
| /** |
| * Get count of Namespaces |
| * @param node XML node |
| * @param bWalkUpTree Tree Flag |
| * @return Count |
| */ |
| int ws_xml_get_ns_count(WsXmlNodeH node, int bWalkUpTree) |
| { |
| int count = xml_parser_get_count(node, XML_COUNT_NS, bWalkUpTree); |
| |
| return count; |
| } |
| |
| |
| /** |
| * Get Namespace Prefix |
| * @param ns Namespace |
| * @return Prefix of Namespace |
| */ |
| char *ws_xml_get_ns_prefix(WsXmlNsH ns) |
| { |
| if (ns) |
| return xml_parser_ns_query(ns, XML_NS_PREFIX); |
| return NULL; |
| } |
| |
| |
| /** |
| * Get Namespace URI |
| * @param ns Namespace |
| * @return URI of namespace, NULL of not found |
| */ |
| char *ws_xml_get_ns_uri(WsXmlNsH ns) |
| { |
| if (ns) |
| return xml_parser_ns_query(ns, XML_NS_URI); |
| return NULL; |
| } |
| |
| |
| |
| /** |
| * Get Namespace from a node |
| * @param node XML node |
| * @param index Index |
| * @return Namespace |
| */ |
| WsXmlNsH ws_xml_get_ns(WsXmlNodeH node, int index) |
| { |
| if (node) |
| return xml_parser_ns_get(node, index); |
| return NULL; |
| } |
| |
| /** |
| * Add child to an XML node |
| * @param node XML node |
| * @param nsUri Namespace URI |
| * @param localName local name |
| * @param val Value of the node |
| * @return New XML node |
| */ |
| WsXmlNodeH |
| ws_xml_add_child(WsXmlNodeH node, |
| const char *nsUri, const char *localName, const char *val) |
| { |
| WsXmlNodeH newNode = xml_parser_node_add(node, XML_LAST_CHILD, nsUri, |
| localName, val, 0); |
| return newNode; |
| } |
| |
| /** |
| *** Add a previous sibling to an XML node |
| *** @param node XML node |
| *** @param nsUri Namespace URI |
| *** @param localName local name |
| *** @param val Value of the node |
| *** @return New XML node |
| ***/ |
| WsXmlNodeH |
| ws_xml_add_prev_sibling(WsXmlNodeH node, |
| const char *nsUri, const char *localName, const char *val) |
| { |
| WsXmlNodeH newNode = xml_parser_node_add(node, XML_ELEMENT_PREV, nsUri, |
| localName, val, 0); |
| return newNode; |
| } |
| |
| WsXmlNodeH |
| ws_xml_add_child_sort(WsXmlNodeH node, |
| const char *nsUri, const char *localName, const char *val, int xmlescape) |
| { |
| int i; |
| WsXmlNodeH child, newNode = NULL; |
| int count = ws_xml_get_child_count(node) ; |
| if ( count == 0 ) { |
| newNode = xml_parser_node_add(node, XML_LAST_CHILD, nsUri, localName, val, xmlescape); |
| } else { |
| for (i = 0; (child = ws_xml_get_child(node, i, NULL, NULL)) != NULL; i++) { |
| char *name = ws_xml_get_node_local_name(child); |
| if (strcmp(localName, name) < 0 ) { |
| newNode = xml_parser_node_add(child, XML_ELEMENT_PREV, nsUri, localName, val, xmlescape); |
| break; |
| } |
| } |
| if (newNode == NULL) { |
| newNode = xml_parser_node_add(node, XML_LAST_CHILD, nsUri, localName, val, xmlescape); |
| } |
| } |
| return newNode; |
| } |
| |
| WsXmlNodeH |
| ws_xml_add_empty_child_format(WsXmlNodeH node, const char *nsUri, |
| const char *format, ...) |
| { |
| WsXmlNodeH newNode; |
| va_list args; |
| char buf[4096]; |
| va_start(args, format); |
| vsnprintf(buf, 4096, format, args); |
| va_end(args); |
| newNode = |
| xml_parser_node_add(node, XML_LAST_CHILD, nsUri, buf, NULL, 0); |
| |
| return newNode; |
| } |
| |
| WsXmlNodeH |
| ws_xml_add_child_format(WsXmlNodeH node, const char *nsUri, |
| const char *localName, const char *format, ...) |
| { |
| WsXmlNodeH newNode; |
| va_list args; |
| char buf[4096]; |
| va_start(args, format); |
| vsnprintf(buf, 4096, format, args); |
| va_end(args); |
| newNode = |
| xml_parser_node_add(node, XML_LAST_CHILD, nsUri, localName, |
| buf, 0); |
| |
| return newNode; |
| } |
| |
| |
| /** |
| * Check of namespace prefix is OK. |
| * @param ns Namespace |
| * @param newPrefix New prefix |
| * @param bDefault FIXME |
| * @return 1 if Ok, 0 if not |
| */ |
| static int |
| is_ns_prefix_ok(WsXmlNsH ns, const char *newPrefix, int bDefault) |
| { |
| int retVal = 0; |
| char *curPrefix = xml_parser_ns_query(ns, XML_NS_PREFIX); |
| |
| if (bDefault) { |
| if (curPrefix == NULL) |
| retVal = 1; |
| } else { |
| if ((newPrefix == NULL && curPrefix != NULL) |
| || |
| (newPrefix && curPrefix && |
| !strcmp(newPrefix, curPrefix))) { |
| retVal = 1; |
| } |
| } |
| |
| return retVal; |
| } |
| |
| |
| |
| |
| /** |
| * Define Namespace |
| * @param node XML node |
| * @param nsUri Namespace URI |
| * @param nsPrefix Namespace Prefix |
| * @param bDefault FIXME |
| * @return New Namespace |
| * @todo if ns is present, it should work as replace, walk through the tree and |
| * update QName values and attributes |
| */ |
| WsXmlNsH |
| ws_xml_define_ns(WsXmlNodeH node, const char *nsUri, const char *nsPrefix, |
| int bDefault) |
| { |
| WsXmlNsH ns = NULL; |
| |
| if (node && nsUri) { |
| ns = ws_xml_find_ns(node, nsUri, NULL, 0); |
| if (ns == NULL || !is_ns_prefix_ok(ns, nsPrefix, bDefault)) { |
| char buf[12]; |
| if (!bDefault && nsPrefix == NULL) { |
| ws_xml_make_default_prefix(node, nsUri, |
| buf, |
| sizeof(buf)); |
| nsPrefix = buf; |
| } |
| ns = xml_parser_ns_add(node, nsUri, nsPrefix); |
| } |
| } |
| return ns; |
| } |
| |
| /** |
| * Add QName child |
| * @param parent Parent XML node |
| * @param nameNs Child Namespace |
| * @param name Child Name |
| * @param valueNs Namespace for value |
| * @param value Child Value |
| * @return Child XML node |
| * @note if namespaces has been changed after this function is called, it is caller's |
| * responsibility to update QName fields accordingly |
| * |
| */ |
| WsXmlNodeH |
| ws_xml_add_qname_child(WsXmlNodeH parent, |
| const char *nameNs, |
| const char *name, |
| const char *valueNs, const char *value) |
| { |
| WsXmlNodeH node = ws_xml_add_child(parent, nameNs, name, NULL); |
| if (node == NULL) { |
| ws_xml_set_node_qname_val(node, valueNs, value); |
| } |
| return node; |
| } |
| |
| |
| int ws_xml_get_node_attr_count(WsXmlNodeH node) |
| { |
| int count = 0; |
| if (node) |
| count = xml_parser_get_count(node, XML_COUNT_ATTR, 0); |
| |
| return count; |
| } |
| |
| |
| WsXmlAttrH |
| ws_xml_add_node_attr(WsXmlNodeH node, |
| const char *nsUri, |
| const char *name, const char *value) |
| { |
| WsXmlAttrH attr = NULL; |
| if (node && name) |
| attr = xml_parser_attr_add(node, nsUri, name, value); |
| |
| return (WsXmlAttrH) attr; |
| } |
| |
| |
| void ws_xml_remove_node_attr(WsXmlAttrH attr) |
| { |
| if (attr) |
| xml_parser_attr_remove(attr); |
| } |
| |
| |
| WsXmlAttrH ws_xml_get_node_attr(WsXmlNodeH node, int index) |
| { |
| return xml_parser_attr_get(node, index); |
| } |
| |
| WsXmlAttrH |
| ws_xml_find_node_attr(WsXmlNodeH node, const char *attrNs, |
| const char *attrName) |
| { |
| WsXmlAttrH attr = NULL; |
| if (node && attrName) { |
| int i = 0; |
| |
| for (i = 0; (attr = ws_xml_get_node_attr(node, i)) != NULL; |
| i++) { |
| char *curNsUri = ws_xml_get_attr_ns(attr); |
| char *curName = ws_xml_get_attr_name(attr); |
| |
| if ((attrNs == curNsUri) |
| || |
| (attrNs != NULL |
| && |
| curNsUri != NULL |
| && !strcmp(curNsUri, attrNs))) { |
| if (!strcmp(attrName, curName)) |
| break; |
| } |
| } |
| } |
| |
| return attr; |
| } |
| |
| |
| unsigned long ws_xml_get_node_ulong(WsXmlNodeH node) |
| { |
| unsigned long val = 0; |
| char *text = ws_xml_get_node_text(node); |
| |
| if (text) |
| val = atoi(text); |
| return val; |
| } |
| |
| |
| int ws_xml_set_node_ulong(WsXmlNodeH node, unsigned long uVal) |
| { |
| int retVal = -1; |
| if (node) { |
| char buf[12]; |
| sprintf(buf, "%lu", uVal); |
| retVal = ws_xml_set_node_text(node, buf); |
| } |
| return retVal; |
| } |
| |
| int ws_xml_set_node_long(WsXmlNodeH node, long Val) |
| { |
| int retVal = -1; |
| if (node) { |
| char buf[12]; |
| sprintf(buf, "%ld", Val); |
| retVal = ws_xml_set_node_text(node, buf); |
| } |
| return retVal; |
| } |
| |
| int ws_xml_set_node_real(WsXmlNodeH node, double Val) |
| { |
| int retVal = -1; |
| if (node) { |
| char buf[12]; |
| sprintf(buf, "%E", Val); |
| retVal = ws_xml_set_node_text(node, buf); |
| } |
| return retVal; |
| } |
| |
| char *ws_xml_get_attr_name(WsXmlAttrH attr) |
| { |
| char *name = NULL; |
| if (attr) |
| name = xml_parser_attr_query(attr, XML_LOCAL_NAME); |
| return name; |
| } |
| |
| char *ws_xml_get_attr_ns(WsXmlAttrH attr) |
| { |
| char *nsUri = NULL; |
| |
| if (attr) |
| nsUri = xml_parser_attr_query(attr, XML_NS_URI); |
| |
| return nsUri; |
| } |
| |
| char *ws_xml_get_attr_ns_prefix(WsXmlAttrH attr) |
| { |
| char *prefix = NULL; |
| |
| if (attr) |
| prefix = xml_parser_attr_query(attr, XML_NS_PREFIX); |
| |
| return prefix; |
| } |
| |
| |
| char *ws_xml_get_attr_value(WsXmlAttrH attr) |
| { |
| char *val = NULL; |
| if (attr) |
| val = xml_parser_attr_query(attr, XML_TEXT_VALUE); |
| return val; |
| } |
| |
| |
| char *ws_xml_find_attr_value(WsXmlNodeH node, const char *ns, |
| const char *attrName) |
| { |
| char *val = NULL; |
| WsXmlAttrH attr = ws_xml_find_node_attr(node, ns, attrName); |
| |
| if (attr) |
| val = ws_xml_get_attr_value(attr); |
| |
| return val; |
| } |
| |
| int ws_xml_find_attr_bool(WsXmlNodeH node, const char *ns, |
| const char *attrName) |
| { |
| int retVal = 0; |
| char *val = ws_xml_find_attr_value(node, ns, attrName); |
| |
| if (val != NULL) |
| retVal = is_xml_val_true(val); |
| |
| return retVal; |
| } |
| |
| |
| unsigned long ws_xml_find_attr_ulong(WsXmlNodeH node, const char *ns, |
| const char *attrName) |
| { |
| unsigned long retVal = 0; |
| char *val = ws_xml_find_attr_value(node, ns, attrName); |
| |
| if (val != NULL) |
| retVal = atoi(val); |
| |
| return retVal; |
| } |
| |
| |
| // if ns is not defined at the node or at any of its parents, it will be defined at the root |
| // if namespaces has been changed after this function is called, itis caller's |
| // responsibility to update QName fields accordingly |
| int ws_xml_set_node_qname_val(WsXmlNodeH node, const char *valNsUri, |
| const char *valName) |
| { |
| int retVal = -1; |
| if (node && valName && valNsUri) { |
| char *buf = make_qname(node, valNsUri, valName); |
| |
| if (buf != NULL) { |
| retVal = ws_xml_set_node_text(node, buf); |
| u_free(buf); |
| } |
| } |
| return retVal; |
| } |
| |
| WsXmlDocH ws_xml_get_node_doc(WsXmlNodeH node) |
| { |
| WsXmlDocH doc = NULL; |
| |
| if (node != NULL) |
| doc = xml_parser_get_doc(node); |
| |
| return doc; |
| } |
| |
| |
| int ws_xml_set_node_text(WsXmlNodeH node, const char *text) |
| { |
| int retVal = -1; |
| |
| if (node) |
| retVal = xml_parser_node_set(node, XML_TEXT_VALUE, text); |
| |
| return retVal; |
| } |
| |
| void ws_xml_set_node_lang(WsXmlNodeH node, const char *lang) |
| { |
| xml_parser_node_set_lang(node, lang); |
| } |
| |
| |
| void ws_xml_dump_node_tree(FILE * f, WsXmlNodeH node) |
| { |
| WsXmlDocH doc = xml_parser_get_doc(node); |
| xml_parser_doc_dump(f, doc); |
| return; |
| } |
| |
| void ws_xml_dump_memory_node_tree(WsXmlNodeH node, char **buf, |
| int *ptrSize) |
| { |
| WsXmlDocH doc = xml_parser_get_doc(node); |
| xml_parser_doc_dump_memory(doc, buf, ptrSize); |
| return; |
| } |
| |
| void ws_xml_dump_memory_node_tree_enc(WsXmlNodeH node, char **buf, |
| int *ptrSize, const char *encoding) |
| { |
| WsXmlDocH doc = xml_parser_get_doc(node); |
| xml_parser_doc_dump_memory_enc(doc, buf, ptrSize, encoding); |
| return; |
| } |
| |
| void ws_xml_dump_doc(FILE * f, WsXmlDocH doc) |
| { |
| xml_parser_doc_dump(f, doc); |
| return; |
| } |
| |
| |
| WsXmlNsH |
| ws_xml_ns_add(WsXmlNodeH node, const char *uri, const char *prefix) |
| { |
| return xml_parser_ns_add(node, uri, prefix); |
| } |
| |
| |
| |
| int ws_xml_check_xpath(WsXmlDocH doc, const char *xpath_expr) |
| { |
| return xml_parser_check_xpath(doc, xpath_expr); |
| } |
| |
| |
| char *ws_xml_get_xpath_value(WsXmlDocH doc, char *expression) |
| { |
| return xml_parser_get_xpath_value(doc, expression); |
| } |
| |
| |
| |
| WsXmlDocH ws_xml_create_doc_by_import(WsXmlNodeH node) |
| { |
| WsXmlDocH wsDoc = (WsXmlDocH) u_zalloc(sizeof(*wsDoc)); |
| xml_parser_create_doc_by_import(wsDoc, node); |
| return wsDoc; |
| } |
| |
| |
| void ws_xml_unlink_node(WsXmlNodeH node) |
| { |
| xml_parser_unlink_node(node); |
| } |
| |
| void ws_xml_set_ns(WsXmlNodeH r, const char* namespace, const char* prefix) |
| { |
| WsXmlNsH ns = ws_xml_ns_add(r, namespace, prefix); |
| xml_parser_set_ns(r, ns, prefix); |
| } |
| |
| int check_envelope_size(WsXmlDocH doc, unsigned int size, const char *charset) |
| { |
| char *buf; |
| int len; |
| if(size == 0) return 0; |
| ws_xml_dump_memory_enc(doc, &buf, &len, charset); |
| ws_xml_free_memory(buf); |
| if(len > size) return 1; |
| return 0; |
| } |
| |
| /** @} */ |