Hello,

I have written a UDF for MySQL in C++ that allows you to use XPath 
expressions in your queries. I'd appreciate any ideas anyone might have 
about this. It seems like it could be very useful, especially for 
databases that integrate XML with relational tables. It requires 
the libxml2 library (http://libxml.org).

Peace,
Dave

--

// udf_xpath.cc - XPATH() UDF for MySQL and libxml2.
// Written by Dave Benjamin <[EMAIL PROTECTED]>.
//
// Compilation:
//     g++ -shared udf_xpath.cc -lxml2 -o udf_xpath.so
//     (you may need to add -I/usr/include/libxml2 or something similar).
//
// Installation:
//     su
//     cp udf_xpath.so /usr/lib
//     /etc/init.d/mysqld stop
//     /etc/init.d/mysqld start
//     mysql -p
//     mysql> CREATE FUNCTION xpath RETURNS STRING SONAME 'udf_xpath.so';
//
// Invocation:
//     SELECT XPATH('<a b="c">d</a>', '/a/@b');         - returns 'c'
//     SELECT XPATH('<a b="c">d</a>', '/a');            - returns 'd'
//     SELECT XPATH('<a><b/></a>',    'boolean(/a/b)'); - returns 'true'
//     SELECT XPATH('<a><b/></a>',    'boolean(/a/c)'); - returns 'false'

#include <string>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <mysql/mysql.h>
#include <sys/param.h>

#define XPATH_MAX_LENGTH 65536

extern "C" {
    my_bool xpath_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
    void    xpath_deinit(UDF_INIT *initid);
    char   *xpath(UDF_INIT *initid, UDF_ARGS *args, char *result,
                  unsigned long *length, char *is_null, char *error);
}

my_bool xpath_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    if (args->arg_count != 2) {
        strcpy(message,"XPATH() requires two arguments.");
        return 1;
    }

    // Tell MySQL to coerce arguments.
    args->arg_type[0] = STRING_RESULT;
    args->arg_type[1] = STRING_RESULT;

    // Allow NULLs.
    initid->maybe_null = 1;

    // Allocate space for result.
    initid->max_length = XPATH_MAX_LENGTH;
    initid->ptr = new char[XPATH_MAX_LENGTH];

    return 0;
}

void xpath_deinit(UDF_INIT *initid) {
    delete initid->ptr;
    xmlCleanupParser();
}

char *xpath(UDF_INIT *initid, UDF_ARGS *args, char *result,
            unsigned long *length, char *is_null, char *error) {

    // Result defaults to NULL.
    *is_null = 1;
    
    do {
        // Parse the XML document.
        xmlDocPtr doc = xmlParseMemory(args->args[0], args->lengths[0]);
        if (!doc) break;

        // Create an XPath context.        
        xmlXPathContextPtr ctxt = xmlXPathNewContext(doc);
        if (!ctxt) {
            xmlFreeDoc(doc);
            break;
        }
        
        // Evaluate the XPath expression.
        string            expr = string(args->args[1], args->lengths[1]);
        xmlXPathObjectPtr path = xmlXPathEval((xmlChar *)expr.c_str(), ctxt);
        if (!path) {
            xmlXPathFreeContext(ctxt);
            xmlFreeDoc(doc);
            break;
        }

        // No NULL result since expression evaluation was successful.
        *is_null = 0;

        // Cast the result to a string and copy.
        xmlChar *res = xmlXPathCastToString(path);
        *length = MIN(xmlStrlen(res), XPATH_MAX_LENGTH);
        memcpy(initid->ptr, (char *)res, *length);
        xmlFree(res);

        // Free used memory.
        xmlXPathFreeObject(path);
        xmlXPathFreeContext(ctxt);
        xmlFreeDoc(doc);

    } while(0);

    // Return the result string.
    return initid->ptr;
}


---------------------------------------------------------------------
Before posting, please check:
   http://www.mysql.com/manual.php   (the manual)
   http://lists.mysql.com/           (the list archive)

To request this thread, e-mail <[EMAIL PROTECTED]>
To unsubscribe, e-mail <[EMAIL PROTECTED]>
Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php

Reply via email to