|
rpm-build |
3ee90c |
/*
|
|
rpm-build |
3ee90c |
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* This library is free software; you can redistribute it and/or
|
|
rpm-build |
3ee90c |
* modify it under the terms of the GNU Lesser General Public
|
|
rpm-build |
3ee90c |
* License as published by the Free Software Foundation; either
|
|
rpm-build |
3ee90c |
* version 2.1 of the License, or (at your option) any later version.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* This library is distributed in the hope that it will be useful,
|
|
rpm-build |
3ee90c |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
3ee90c |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
3ee90c |
* Lesser General Public License for more details.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
3ee90c |
* License along with this library; if not, write to the Free Software
|
|
rpm-build |
3ee90c |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
#include <crm_internal.h>
|
|
rpm-build |
3ee90c |
#include <stdio.h>
|
|
rpm-build |
3ee90c |
#include <string.h>
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/*
|
|
rpm-build |
3ee90c |
* From xpath2.c
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* All the elements returned by an XPath query are pointers to
|
|
rpm-build |
3ee90c |
* elements from the tree *except* namespace nodes where the XPath
|
|
rpm-build |
3ee90c |
* semantic is different from the implementation in libxml2 tree.
|
|
rpm-build |
3ee90c |
* As a result when a returned node set is freed when
|
|
rpm-build |
3ee90c |
* xmlXPathFreeObject() is called, that routine must check the
|
|
rpm-build |
3ee90c |
* element type. But node from the returned set may have been removed
|
|
rpm-build |
3ee90c |
* by xmlNodeSetContent() resulting in access to freed data.
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* This can be exercised by running
|
|
rpm-build |
3ee90c |
* valgrind xpath2 test3.xml '//discarded' discarded
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* There is 2 ways around it:
|
|
rpm-build |
3ee90c |
* - make a copy of the pointers to the nodes from the result set
|
|
rpm-build |
3ee90c |
* then call xmlXPathFreeObject() and then modify the nodes
|
|
rpm-build |
3ee90c |
* or
|
|
rpm-build |
3ee90c |
* - remove the references from the node set, if they are not
|
|
rpm-build |
3ee90c |
namespace nodes, before calling xmlXPathFreeObject().
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
void
|
|
rpm-build |
3ee90c |
freeXpathObject(xmlXPathObjectPtr xpathObj)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int lpc, max = numXpathResults(xpathObj);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (xpathObj == NULL) {
|
|
rpm-build |
3ee90c |
return;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (lpc = 0; lpc < max; lpc++) {
|
|
rpm-build |
3ee90c |
if (xpathObj->nodesetval->nodeTab[lpc] && xpathObj->nodesetval->nodeTab[lpc]->type != XML_NAMESPACE_DECL) {
|
|
rpm-build |
3ee90c |
xpathObj->nodesetval->nodeTab[lpc] = NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* _Now_ it's safe to free it */
|
|
rpm-build |
3ee90c |
xmlXPathFreeObject(xpathObj);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xmlNode *
|
|
rpm-build |
3ee90c |
getXpathResult(xmlXPathObjectPtr xpathObj, int index)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
xmlNode *match = NULL;
|
|
rpm-build |
3ee90c |
int max = numXpathResults(xpathObj);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(index >= 0, return NULL);
|
|
rpm-build |
3ee90c |
CRM_CHECK(xpathObj != NULL, return NULL);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (index >= max) {
|
|
rpm-build |
3ee90c |
crm_err("Requested index %d of only %d items", index, max);
|
|
rpm-build |
3ee90c |
return NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if(xpathObj->nodesetval->nodeTab[index] == NULL) {
|
|
rpm-build |
3ee90c |
/* Previously requested */
|
|
rpm-build |
3ee90c |
return NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
match = xpathObj->nodesetval->nodeTab[index];
|
|
rpm-build |
3ee90c |
CRM_CHECK(match != NULL, return NULL);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (xpathObj->nodesetval->nodeTab[index]->type != XML_NAMESPACE_DECL) {
|
|
rpm-build |
3ee90c |
/* See the comment for freeXpathObject() */
|
|
rpm-build |
3ee90c |
xpathObj->nodesetval->nodeTab[index] = NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (match->type == XML_DOCUMENT_NODE) {
|
|
rpm-build |
3ee90c |
/* Will happen if section = '/' */
|
|
rpm-build |
3ee90c |
match = match->children;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (match->type != XML_ELEMENT_NODE
|
|
rpm-build |
3ee90c |
&& match->parent && match->parent->type == XML_ELEMENT_NODE) {
|
|
rpm-build |
3ee90c |
/* Return the parent instead */
|
|
rpm-build |
3ee90c |
match = match->parent;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (match->type != XML_ELEMENT_NODE) {
|
|
rpm-build |
3ee90c |
/* We only support searching nodes */
|
|
rpm-build |
3ee90c |
crm_err("We only support %d not %d", XML_ELEMENT_NODE, match->type);
|
|
rpm-build |
3ee90c |
match = NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
return match;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
void
|
|
rpm-build |
3ee90c |
dedupXpathResults(xmlXPathObjectPtr xpathObj)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int lpc, max = numXpathResults(xpathObj);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (xpathObj == NULL) {
|
|
rpm-build |
3ee90c |
return;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (lpc = 0; lpc < max; lpc++) {
|
|
rpm-build |
3ee90c |
xmlNode *xml = NULL;
|
|
rpm-build |
3ee90c |
gboolean dedup = FALSE;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (xpathObj->nodesetval->nodeTab[lpc] == NULL) {
|
|
rpm-build |
3ee90c |
continue;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xml = xpathObj->nodesetval->nodeTab[lpc]->parent;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (; xml; xml = xml->parent) {
|
|
rpm-build |
3ee90c |
int lpc2 = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (lpc2 = 0; lpc2 < max; lpc2++) {
|
|
rpm-build |
3ee90c |
if (xpathObj->nodesetval->nodeTab[lpc2] == xml) {
|
|
rpm-build |
3ee90c |
xpathObj->nodesetval->nodeTab[lpc] = NULL;
|
|
rpm-build |
3ee90c |
dedup = TRUE;
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (dedup) {
|
|
rpm-build |
3ee90c |
break;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/* the caller needs to check if the result contains a xmlDocPtr or xmlNodePtr */
|
|
rpm-build |
3ee90c |
xmlXPathObjectPtr
|
|
rpm-build |
3ee90c |
xpath_search(xmlNode * xml_top, const char *path)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
xmlDocPtr doc = NULL;
|
|
rpm-build |
3ee90c |
xmlXPathObjectPtr xpathObj = NULL;
|
|
rpm-build |
3ee90c |
xmlXPathContextPtr xpathCtx = NULL;
|
|
rpm-build |
3ee90c |
const xmlChar *xpathExpr = (pcmkXmlStr) path;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_CHECK(path != NULL, return NULL);
|
|
rpm-build |
3ee90c |
CRM_CHECK(xml_top != NULL, return NULL);
|
|
rpm-build |
3ee90c |
CRM_CHECK(strlen(path) > 0, return NULL);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
doc = getDocPtr(xml_top);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xpathCtx = xmlXPathNewContext(doc);
|
|
rpm-build |
3ee90c |
CRM_ASSERT(xpathCtx != NULL);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
|
|
rpm-build |
3ee90c |
xmlXPathFreeContext(xpathCtx);
|
|
rpm-build |
3ee90c |
return xpathObj;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
/*!
|
|
rpm-build |
3ee90c |
* \brief Run a supplied function for each result of an xpath search
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* \param[in] xml XML to search
|
|
rpm-build |
3ee90c |
* \param[in] xpath XPath search string
|
|
rpm-build |
3ee90c |
* \param[in] helper Function to call for each result
|
|
rpm-build |
3ee90c |
* \param[in,out] user_data Data to pass to supplied function
|
|
rpm-build |
3ee90c |
*
|
|
rpm-build |
3ee90c |
* \note The helper function will be passed the XML node of the result,
|
|
rpm-build |
3ee90c |
* and the supplied user_data. This function does not otherwise
|
|
rpm-build |
3ee90c |
* use user_data.
|
|
rpm-build |
3ee90c |
*/
|
|
rpm-build |
3ee90c |
void
|
|
rpm-build |
3ee90c |
crm_foreach_xpath_result(xmlNode *xml, const char *xpath,
|
|
rpm-build |
3ee90c |
void (*helper)(xmlNode*, void*), void *user_data)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
xmlXPathObjectPtr xpathObj = xpath_search(xml, xpath);
|
|
rpm-build |
3ee90c |
int nresults = numXpathResults(xpathObj);
|
|
rpm-build |
3ee90c |
int i;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (i = 0; i < nresults; i++) {
|
|
rpm-build |
3ee90c |
xmlNode *result = getXpathResult(xpathObj, i);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_LOG_ASSERT(result != NULL);
|
|
rpm-build |
3ee90c |
if (result) {
|
|
rpm-build |
3ee90c |
(*helper)(result, user_data);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
freeXpathObject(xpathObj);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xmlNode *
|
|
rpm-build |
3ee90c |
get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
xmlNode *result = NULL;
|
|
rpm-build |
3ee90c |
char *xpath_full = NULL;
|
|
rpm-build |
3ee90c |
char *xpath_prefix = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (xml_obj == NULL || xpath == NULL) {
|
|
rpm-build |
3ee90c |
return NULL;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xpath_prefix = (char *)xmlGetNodePath(xml_obj);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xpath_full = crm_strdup_printf("%s%s", xpath_prefix, xpath);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
result = get_xpath_object(xpath_full, xml_obj, error_level);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
free(xpath_prefix);
|
|
rpm-build |
3ee90c |
free(xpath_full);
|
|
rpm-build |
3ee90c |
return result;
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xmlNode *
|
|
rpm-build |
3ee90c |
get_xpath_object(const char *xpath, xmlNode * xml_obj, int error_level)
|
|
rpm-build |
3ee90c |
{
|
|
rpm-build |
3ee90c |
int max;
|
|
rpm-build |
3ee90c |
xmlNode *result = NULL;
|
|
rpm-build |
3ee90c |
xmlXPathObjectPtr xpathObj = NULL;
|
|
rpm-build |
3ee90c |
char *nodePath = NULL;
|
|
rpm-build |
3ee90c |
char *matchNodePath = NULL;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (xpath == NULL) {
|
|
rpm-build |
3ee90c |
return xml_obj; /* or return NULL? */
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
xpathObj = xpath_search(xml_obj, xpath);
|
|
rpm-build |
3ee90c |
nodePath = (char *)xmlGetNodePath(xml_obj);
|
|
rpm-build |
3ee90c |
max = numXpathResults(xpathObj);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
if (max < 1) {
|
|
rpm-build |
3ee90c |
do_crm_log(error_level, "No match for %s in %s", xpath, crm_str(nodePath));
|
|
rpm-build |
3ee90c |
crm_log_xml_explicit(xml_obj, "Unexpected Input");
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else if (max > 1) {
|
|
rpm-build |
3ee90c |
int lpc = 0;
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
do_crm_log(error_level, "Too many matches for %s in %s", xpath, crm_str(nodePath));
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
for (lpc = 0; lpc < max; lpc++) {
|
|
rpm-build |
3ee90c |
xmlNode *match = getXpathResult(xpathObj, lpc);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
CRM_LOG_ASSERT(match != NULL);
|
|
rpm-build |
3ee90c |
if(match != NULL) {
|
|
rpm-build |
3ee90c |
matchNodePath = (char *)xmlGetNodePath(match);
|
|
rpm-build |
3ee90c |
do_crm_log(error_level, "%s[%d] = %s", xpath, lpc, crm_str(matchNodePath));
|
|
rpm-build |
3ee90c |
free(matchNodePath);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
crm_log_xml_explicit(xml_obj, "Bad Input");
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
} else {
|
|
rpm-build |
3ee90c |
result = getXpathResult(xpathObj, 0);
|
|
rpm-build |
3ee90c |
}
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
freeXpathObject(xpathObj);
|
|
rpm-build |
3ee90c |
free(nodePath);
|
|
rpm-build |
3ee90c |
|
|
rpm-build |
3ee90c |
return result;
|
|
rpm-build |
3ee90c |
}
|