2008-11-01 21:10:07 +00:00
|
|
|
/*
|
|
|
|
* Asterisk -- An open source telephony toolkit.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008, Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
|
|
|
|
*
|
|
|
|
* See http://www.asterisk.org for more information about
|
|
|
|
* the Asterisk project. Please do not directly contact
|
|
|
|
* any of the maintainers of this project for assistance;
|
|
|
|
* the project provides a web site, mailing lists and IRC
|
|
|
|
* channels for your use.
|
|
|
|
*
|
|
|
|
* This program is free software, distributed under the terms of
|
|
|
|
* the GNU General Public License Version 2. See the LICENSE file
|
|
|
|
* at the top of the source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \file
|
|
|
|
*
|
|
|
|
* \brief XML abstraction layer
|
|
|
|
*
|
|
|
|
* \author Eliel C. Sardanons (LU1ALY) <eliels@gmail.com>
|
|
|
|
*/
|
|
|
|
|
2012-06-15 16:20:16 +00:00
|
|
|
/*** MODULEINFO
|
|
|
|
<support_level>core</support_level>
|
|
|
|
***/
|
|
|
|
|
2008-11-01 21:10:07 +00:00
|
|
|
#include "asterisk.h"
|
|
|
|
#include "asterisk/xml.h"
|
Merge Call completion support into trunk.
From Reviewboard:
CCSS stands for Call Completion Supplementary Services. An admittedly out-of-date
overview of the architecture can be found in the file doc/CCSS_architecture.pdf
in the CCSS branch. Off the top of my head, the big differences between what is
implemented and what is in the document are as follows:
1. We did not end up modifying the Hangup application at all.
2. The document states that a single call completion monitor may be used across
multiple calls to the same device. This proved to not be such a good idea
when implementing protocol-specific monitors, and so we ended up using one
monitor per-device per-call.
3. There are some configuration options which were conceived after the document
was written. These are documented in the ccss.conf.sample that is on this
review request.
For some basic understanding of terminology used throughout this code, see the
ccss.tex document that is on this review.
This implements CCBS and CCNR in several flavors.
First up is a "generic" implementation, which can work over any channel technology
provided that the channel technology can accurately report device state. Call
completion is requested using the dialplan application CallCompletionRequest and can
be canceled using CallCompletionCancel. Device state subscriptions are used in order
to monitor the state of called parties.
Next, there is a SIP-specific implementation of call completion. This method uses the
methods outlined in draft-ietf-bliss-call-completion-06 to implement call completion
using SIP signaling. There are a few things to note here:
* The agent/monitor terminology used throughout Asterisk sometimes is the reverse of
what is defined in the referenced draft.
* Implementation of the draft required support for SIP PUBLISH. I attempted to write
this in a generic-enough fashion such that if someone were to want to write PUBLISH
support for other event packages, such as dialog-state or presence, most of the effort
would be in writing callbacks specific to the event package.
* A subportion of supporting PUBLISH reception was that we had to implement a PIDF
parser. The PIDF support added is a bit minimal. I first wrote a validation
routine to ensure that the PIDF document is formatted properly. The rest of the
PIDF reading is done in-line in the call-completion-specific PUBLISH-handling
code. In other words, while there is PIDF support here, it is not in any state
where it could easily be applied to other event packages as is.
Finally, there are a variety of ISDN-related call completion protocols supported. These
were written by Richard Mudgett, and as such I can't really say much about their
implementation. There are notes in the CHANGES file that indicate the ISDN protocols
over which call completion is supported.
Review: https://reviewboard.asterisk.org/r/523
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@256528 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-04-09 15:31:32 +00:00
|
|
|
#include "asterisk/logger.h"
|
2013-02-15 13:38:12 +00:00
|
|
|
#include "asterisk/utils.h"
|
2013-08-01 17:07:52 +00:00
|
|
|
#include "asterisk/autoconfig.h"
|
2008-11-01 21:10:07 +00:00
|
|
|
|
|
|
|
#if defined(HAVE_LIBXML2)
|
|
|
|
#include <libxml/parser.h>
|
|
|
|
#include <libxml/tree.h>
|
2009-05-16 20:01:22 +00:00
|
|
|
#include <libxml/xinclude.h>
|
2013-02-15 13:38:12 +00:00
|
|
|
#include <libxml/xpath.h>
|
2008-11-01 21:10:07 +00:00
|
|
|
/* libxml2 ast_xml implementation. */
|
2013-08-01 17:07:52 +00:00
|
|
|
#ifdef HAVE_LIBXSLT
|
|
|
|
#include <libxslt/xsltInternals.h>
|
|
|
|
#include <libxslt/transform.h>
|
|
|
|
#endif /* HAVE_LIBXSLT */
|
2008-11-01 21:10:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
int ast_xml_init(void)
|
|
|
|
{
|
|
|
|
LIBXML_TEST_VERSION
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ast_xml_finish(void)
|
|
|
|
{
|
|
|
|
xmlCleanupParser();
|
2013-10-03 18:00:15 +00:00
|
|
|
#ifdef HAVE_LIBXSLT_CLEANUP
|
|
|
|
xsltCleanupGlobals();
|
|
|
|
#endif
|
2008-11-01 21:10:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_doc *ast_xml_open(char *filename)
|
|
|
|
{
|
|
|
|
xmlDoc *doc;
|
|
|
|
|
|
|
|
if (!filename) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
|
2013-08-01 17:07:52 +00:00
|
|
|
if (!doc) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* process xinclude elements. */
|
|
|
|
if (xmlXIncludeProcess(doc) < 0) {
|
|
|
|
xmlFreeDoc(doc);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBXSLT
|
|
|
|
{
|
|
|
|
xsltStylesheetPtr xslt = xsltLoadStylesheetPI(doc);
|
|
|
|
if (xslt) {
|
|
|
|
xmlDocPtr tmpdoc = xsltApplyStylesheet(xslt, doc, NULL);
|
|
|
|
xsltFreeStylesheet(xslt);
|
2009-05-16 20:01:22 +00:00
|
|
|
xmlFreeDoc(doc);
|
2013-08-01 17:07:52 +00:00
|
|
|
if (!tmpdoc) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
doc = tmpdoc;
|
2009-05-16 20:01:22 +00:00
|
|
|
}
|
|
|
|
}
|
2013-08-01 17:07:52 +00:00
|
|
|
#else /* no HAVE_LIBXSLT */
|
|
|
|
ast_log(LOG_NOTICE, "XSLT support not found. XML documentation may be incomplete.\n");
|
|
|
|
#endif /* HAVE_LIBXSLT */
|
2008-11-01 21:10:07 +00:00
|
|
|
|
2017-12-01 14:29:43 +00:00
|
|
|
/* Optimize for XPath */
|
|
|
|
xmlXPathOrderDocElems(doc);
|
|
|
|
|
2008-11-01 21:10:07 +00:00
|
|
|
return (struct ast_xml_doc *) doc;
|
|
|
|
}
|
|
|
|
|
2010-04-22 18:07:02 +00:00
|
|
|
struct ast_xml_doc *ast_xml_new(void)
|
|
|
|
{
|
|
|
|
xmlDoc *doc;
|
|
|
|
|
|
|
|
doc = xmlNewDoc((const xmlChar *) "1.0");
|
|
|
|
return (struct ast_xml_doc *) doc;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_new_node(const char *name)
|
|
|
|
{
|
|
|
|
xmlNode *node;
|
|
|
|
if (!name) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
node = xmlNewNode(NULL, (const xmlChar *) name);
|
|
|
|
|
|
|
|
return (struct ast_xml_node *) node;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_new_child(struct ast_xml_node *parent, const char *child_name)
|
|
|
|
{
|
|
|
|
xmlNode *child;
|
|
|
|
|
|
|
|
if (!parent || !child_name) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
child = xmlNewChild((xmlNode *) parent, NULL, (const xmlChar *) child_name, NULL);
|
|
|
|
return (struct ast_xml_node *) child;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_add_child(struct ast_xml_node *parent, struct ast_xml_node *child)
|
|
|
|
{
|
|
|
|
if (!parent || !child) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return (struct ast_xml_node *) xmlAddChild((xmlNode *) parent, (xmlNode *) child);
|
|
|
|
}
|
|
|
|
|
2018-07-20 11:20:25 +00:00
|
|
|
struct ast_xml_node *ast_xml_add_child_list(struct ast_xml_node *parent, struct ast_xml_node *child)
|
|
|
|
{
|
|
|
|
if (!parent || !child) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return (struct ast_xml_node *) xmlAddChildList((xmlNode *) parent, (xmlNode *) child);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_copy_node_list(struct ast_xml_node *list)
|
|
|
|
{
|
|
|
|
if (!list) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return (struct ast_xml_node *) xmlCopyNodeList((xmlNode *) list);
|
|
|
|
}
|
|
|
|
|
Merge Call completion support into trunk.
From Reviewboard:
CCSS stands for Call Completion Supplementary Services. An admittedly out-of-date
overview of the architecture can be found in the file doc/CCSS_architecture.pdf
in the CCSS branch. Off the top of my head, the big differences between what is
implemented and what is in the document are as follows:
1. We did not end up modifying the Hangup application at all.
2. The document states that a single call completion monitor may be used across
multiple calls to the same device. This proved to not be such a good idea
when implementing protocol-specific monitors, and so we ended up using one
monitor per-device per-call.
3. There are some configuration options which were conceived after the document
was written. These are documented in the ccss.conf.sample that is on this
review request.
For some basic understanding of terminology used throughout this code, see the
ccss.tex document that is on this review.
This implements CCBS and CCNR in several flavors.
First up is a "generic" implementation, which can work over any channel technology
provided that the channel technology can accurately report device state. Call
completion is requested using the dialplan application CallCompletionRequest and can
be canceled using CallCompletionCancel. Device state subscriptions are used in order
to monitor the state of called parties.
Next, there is a SIP-specific implementation of call completion. This method uses the
methods outlined in draft-ietf-bliss-call-completion-06 to implement call completion
using SIP signaling. There are a few things to note here:
* The agent/monitor terminology used throughout Asterisk sometimes is the reverse of
what is defined in the referenced draft.
* Implementation of the draft required support for SIP PUBLISH. I attempted to write
this in a generic-enough fashion such that if someone were to want to write PUBLISH
support for other event packages, such as dialog-state or presence, most of the effort
would be in writing callbacks specific to the event package.
* A subportion of supporting PUBLISH reception was that we had to implement a PIDF
parser. The PIDF support added is a bit minimal. I first wrote a validation
routine to ensure that the PIDF document is formatted properly. The rest of the
PIDF reading is done in-line in the call-completion-specific PUBLISH-handling
code. In other words, while there is PIDF support here, it is not in any state
where it could easily be applied to other event packages as is.
Finally, there are a variety of ISDN-related call completion protocols supported. These
were written by Richard Mudgett, and as such I can't really say much about their
implementation. There are notes in the CHANGES file that indicate the ISDN protocols
over which call completion is supported.
Review: https://reviewboard.asterisk.org/r/523
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@256528 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-04-09 15:31:32 +00:00
|
|
|
struct ast_xml_doc *ast_xml_read_memory(char *buffer, size_t size)
|
|
|
|
{
|
|
|
|
xmlDoc *doc;
|
|
|
|
|
|
|
|
if (!buffer) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(doc = xmlParseMemory(buffer, (int) size))) {
|
|
|
|
/* process xinclude elements. */
|
|
|
|
if (xmlXIncludeProcess(doc) < 0) {
|
|
|
|
xmlFreeDoc(doc);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (struct ast_xml_doc *) doc;
|
|
|
|
}
|
|
|
|
|
2008-11-01 21:10:07 +00:00
|
|
|
void ast_xml_close(struct ast_xml_doc *doc)
|
|
|
|
{
|
|
|
|
if (!doc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlFreeDoc((xmlDoc *) doc);
|
|
|
|
doc = NULL;
|
|
|
|
}
|
|
|
|
|
2010-04-22 18:07:02 +00:00
|
|
|
void ast_xml_set_root(struct ast_xml_doc *doc, struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
if (!doc || !node) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlDocSetRootElement((xmlDoc *) doc, (xmlNode *) node);
|
|
|
|
}
|
2008-11-01 21:10:07 +00:00
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_get_root(struct ast_xml_doc *doc)
|
|
|
|
{
|
|
|
|
xmlNode *root_node;
|
|
|
|
|
|
|
|
if (!doc) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
root_node = xmlDocGetRootElement((xmlDoc *) doc);
|
|
|
|
|
|
|
|
return (struct ast_xml_node *) root_node;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ast_xml_free_node(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
if (!node) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlFreeNode((xmlNode *) node);
|
|
|
|
node = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ast_xml_free_attr(const char *attribute)
|
|
|
|
{
|
|
|
|
if (attribute) {
|
|
|
|
xmlFree((char *) attribute);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ast_xml_free_text(const char *text)
|
|
|
|
{
|
|
|
|
if (text) {
|
|
|
|
xmlFree((char *) text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname)
|
|
|
|
{
|
|
|
|
xmlChar *attrvalue;
|
|
|
|
|
|
|
|
if (!node) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!attrname) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
attrvalue = xmlGetProp((xmlNode *) node, (xmlChar *) attrname);
|
|
|
|
|
|
|
|
return (const char *) attrvalue;
|
|
|
|
}
|
|
|
|
|
2010-04-22 18:07:02 +00:00
|
|
|
int ast_xml_set_attribute(struct ast_xml_node *node, const char *name, const char *value)
|
|
|
|
{
|
|
|
|
if (!name || !value) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!xmlSetProp((xmlNode *) node, (xmlChar *) name, (xmlChar *) value)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-11-01 21:10:07 +00:00
|
|
|
struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue)
|
|
|
|
{
|
|
|
|
struct ast_xml_node *cur;
|
|
|
|
const char *attr;
|
|
|
|
|
|
|
|
if (!root_node) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cur = root_node; cur; cur = ast_xml_node_get_next(cur)) {
|
|
|
|
/* Check if the name matchs */
|
|
|
|
if (strcmp(ast_xml_node_get_name(cur), name)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* We need to check for a specific attribute name? */
|
|
|
|
if (!attrname || !attrvalue) {
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
/* Get the attribute, we need to compare it. */
|
|
|
|
if ((attr = ast_xml_get_attribute(cur, attrname))) {
|
|
|
|
/* does attribute name/value matches? */
|
|
|
|
if (!strcmp(attr, attrvalue)) {
|
|
|
|
ast_xml_free_attr(attr);
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
ast_xml_free_attr(attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-04-22 18:07:02 +00:00
|
|
|
struct ast_xml_doc *ast_xml_get_doc(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
if (!node) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (struct ast_xml_doc *) ((xmlNode *)node)->doc;
|
|
|
|
}
|
|
|
|
|
Merge Call completion support into trunk.
From Reviewboard:
CCSS stands for Call Completion Supplementary Services. An admittedly out-of-date
overview of the architecture can be found in the file doc/CCSS_architecture.pdf
in the CCSS branch. Off the top of my head, the big differences between what is
implemented and what is in the document are as follows:
1. We did not end up modifying the Hangup application at all.
2. The document states that a single call completion monitor may be used across
multiple calls to the same device. This proved to not be such a good idea
when implementing protocol-specific monitors, and so we ended up using one
monitor per-device per-call.
3. There are some configuration options which were conceived after the document
was written. These are documented in the ccss.conf.sample that is on this
review request.
For some basic understanding of terminology used throughout this code, see the
ccss.tex document that is on this review.
This implements CCBS and CCNR in several flavors.
First up is a "generic" implementation, which can work over any channel technology
provided that the channel technology can accurately report device state. Call
completion is requested using the dialplan application CallCompletionRequest and can
be canceled using CallCompletionCancel. Device state subscriptions are used in order
to monitor the state of called parties.
Next, there is a SIP-specific implementation of call completion. This method uses the
methods outlined in draft-ietf-bliss-call-completion-06 to implement call completion
using SIP signaling. There are a few things to note here:
* The agent/monitor terminology used throughout Asterisk sometimes is the reverse of
what is defined in the referenced draft.
* Implementation of the draft required support for SIP PUBLISH. I attempted to write
this in a generic-enough fashion such that if someone were to want to write PUBLISH
support for other event packages, such as dialog-state or presence, most of the effort
would be in writing callbacks specific to the event package.
* A subportion of supporting PUBLISH reception was that we had to implement a PIDF
parser. The PIDF support added is a bit minimal. I first wrote a validation
routine to ensure that the PIDF document is formatted properly. The rest of the
PIDF reading is done in-line in the call-completion-specific PUBLISH-handling
code. In other words, while there is PIDF support here, it is not in any state
where it could easily be applied to other event packages as is.
Finally, there are a variety of ISDN-related call completion protocols supported. These
were written by Richard Mudgett, and as such I can't really say much about their
implementation. There are notes in the CHANGES file that indicate the ISDN protocols
over which call completion is supported.
Review: https://reviewboard.asterisk.org/r/523
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@256528 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2010-04-09 15:31:32 +00:00
|
|
|
struct ast_xml_ns *ast_xml_find_namespace(struct ast_xml_doc *doc, struct ast_xml_node *node, const char *ns_name) {
|
|
|
|
xmlNsPtr ns = xmlSearchNs((xmlDocPtr) doc, (xmlNodePtr) node, (xmlChar *) ns_name);
|
|
|
|
return (struct ast_xml_ns *) ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *ast_xml_get_ns_href(struct ast_xml_ns *ns)
|
|
|
|
{
|
|
|
|
return (const char *) ((xmlNsPtr) ns)->href;
|
|
|
|
}
|
|
|
|
|
2008-11-01 21:10:07 +00:00
|
|
|
const char *ast_xml_get_text(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
if (!node) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (const char *) xmlNodeGetContent((xmlNode *) node);
|
|
|
|
}
|
|
|
|
|
2010-04-22 18:07:02 +00:00
|
|
|
void ast_xml_set_text(struct ast_xml_node *node, const char *content)
|
|
|
|
{
|
|
|
|
if (!node || !content) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlNodeSetContent((xmlNode *) node, (const xmlChar *) content);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ast_xml_doc_dump_file(FILE *output, struct ast_xml_doc *doc)
|
|
|
|
{
|
|
|
|
return xmlDocDump(output, (xmlDocPtr)doc);
|
|
|
|
}
|
|
|
|
|
2008-11-01 21:10:07 +00:00
|
|
|
const char *ast_xml_node_get_name(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
return (const char *) ((xmlNode *) node)->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_node_get_children(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
return (struct ast_xml_node *) ((xmlNode *) node)->children;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_node_get_next(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
return (struct ast_xml_node *) ((xmlNode *) node)->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_node_get_prev(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
return (struct ast_xml_node *) ((xmlNode *) node)->prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_node *ast_xml_node_get_parent(struct ast_xml_node *node)
|
|
|
|
{
|
|
|
|
return (struct ast_xml_node *) ((xmlNode *) node)->parent;
|
|
|
|
}
|
|
|
|
|
2013-02-15 13:38:12 +00:00
|
|
|
struct ast_xml_node *ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
|
|
|
|
{
|
|
|
|
return (struct ast_xml_node *) ((xmlXPathObjectPtr) results)->nodesetval->nodeTab[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
|
|
|
|
{
|
|
|
|
xmlXPathFreeObject((xmlXPathObjectPtr) results);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ast_xml_xpath_num_results(struct ast_xml_xpath_results *results)
|
|
|
|
{
|
|
|
|
return ((xmlXPathObjectPtr) results)->nodesetval->nodeNr;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_xml_xpath_results *ast_xml_query(struct ast_xml_doc *doc, const char *xpath_str)
|
|
|
|
{
|
|
|
|
xmlXPathContextPtr context;
|
|
|
|
xmlXPathObjectPtr result;
|
|
|
|
if (!(context = xmlXPathNewContext((xmlDoc *) doc))) {
|
|
|
|
ast_log(LOG_ERROR, "Could not create XPath context!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
result = xmlXPathEvalExpression((xmlChar *) xpath_str, context);
|
|
|
|
xmlXPathFreeContext(context);
|
|
|
|
if (!result) {
|
|
|
|
ast_log(LOG_WARNING, "Error for query: %s\n", xpath_str);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
|
|
|
|
xmlXPathFreeObject(result);
|
|
|
|
ast_debug(5, "No results for query: %s\n", xpath_str);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return (struct ast_xml_xpath_results *) result;
|
|
|
|
}
|
|
|
|
|
2008-11-01 21:10:07 +00:00
|
|
|
#endif /* defined(HAVE_LIBXML2) */
|