Skip to content

Commit 0245890

Browse files
committed
xpath functions
1 parent 88ab073 commit 0245890

File tree

7 files changed

+275
-10
lines changed

7 files changed

+275
-10
lines changed

revxml/Makefile.revxml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ include ../rules/environment.linux.makefile
55

66
SOURCES=revxml.cpp xmlattribute.cpp xmldoc.cpp xmlelement.cpp
77

8-
CUSTOM_DEFINES=
8+
CUSTOM_DEFINES=LIBXML_XPATH_ENABLED
99

1010
CUSTOM_INCLUDES=./src
1111

@@ -15,4 +15,6 @@ CUSTOM_CCFLAGS=
1515

1616
CUSTOM_LDFLAGS=
1717

18+
CUSTOM_DYNAMIC_LIBS=m
19+
1820
include ../rules/library.linux.makefile

revxml/Makefile.server-revxml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ include ../rules/environment.linux.makefile
55

66
SOURCES=revxml.cpp xmlattribute.cpp xmldoc.cpp xmlelement.cpp
77

8-
CUSTOM_DEFINES=
8+
CUSTOM_DEFINES=LIBXML_XPATH_ENABLED
99

1010
CUSTOM_INCLUDES=./src ../libxml/include
1111

1212
CUSTOM_LIBS=external xml z
13-
CUSTOM_DYNAMIC_LIBS=
13+
CUSTOM_DYNAMIC_LIBS=m
1414

1515
CUSTOM_CCFLAGS=
1616

revxml/src/cxml.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
1717
#include <libxml/xmlmemory.h>
1818
#include <libxml/parser.h>
1919
#include <libxml/HTMLparser.h>
20+
// MDW-2013-07-09: [[ xpath context ]]
21+
#include <libxml/xpath.h>
2022

2123
#include <errno.h>
2224
#include <stdio.h>
@@ -72,6 +74,9 @@ void Write(char **data, int *length,Bool isformatted);
7274
Bool GetElementByPath(CXMLElement *telement, char *tpath);
7375
Bool GetRootElement(CXMLElement *telement);
7476
xmlDocPtr GetDocPtr() {return doc;}
77+
// MDW-2013-07-09: [[ set and return xpath context ]]
78+
xmlXPathContextPtr GetXPathContext() {return xpathContext;}
79+
void SetXPathContext(xmlXPathContextPtr ctx) {xpathContext=ctx;}
7580
Bool AddDTD(char *data, unsigned long tlength);
7681
Bool ValidateDTD(char *data, unsigned long tlength);
7782
char *GetError() {return errorbuf;}
@@ -93,6 +98,8 @@ static unsigned int idcounter;
9398
unsigned int id;
9499
static char errorbuf[256];
95100
xmlDocPtr doc;
101+
// MDW-2013-07-09: [[ xpath context ]]
102+
xmlXPathContextPtr xpathContext;
96103
};
97104

98105
class CXMLElement

revxml/src/revxml.cpp

Lines changed: 254 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
2222

2323
#include <revolution/external.h>
2424
#include <revolution/support.h>
25+
#include <libxml/xpath.h>
2526

2627
#include "cxml.h"
2728

@@ -112,6 +113,9 @@ enum XMLErrs
112113
XMLERR_BADMOVE,
113114
XMLERR_BADCOPY,
114115
XMLERR_NOFILEPERMS,
116+
XPATHERR_BADDOCCONTEXT,
117+
XPATHERR_CANTRESOLVE,
118+
XPATHERR_BADDOCPOINTER,
115119
};
116120

117121
const char *xmlerrors[] = {
@@ -125,6 +129,9 @@ const char *xmlerrors[] = {
125129
"xmlerr, can't move node into itself",
126130
"xmlerr, can't copy node into itself",
127131
"xmlerr, file access not permitted",
132+
"xmlerr, couldn't assign document context",
133+
"xmlerr, can't resolve xpath",
134+
"xmlerr, bad document pointer",
128135
};
129136

130137
//HS-2010-10-11: [[ Bug 7586 ]] Reinstate libxml2 to create name spaces. Implement new liveCode commands to suppress name space creation.
@@ -145,6 +152,8 @@ class XMLDocumentList
145152
VXMLDocList::iterator theIterator;
146153
for (theIterator = doclist.begin(); theIterator != doclist.end(); theIterator++){
147154
CXMLDocument *curobject = (CXMLDocument *)(*theIterator);
155+
// MDW-2013-07-09: [[ free xpath context ]]
156+
xmlXPathFreeContext(curobject->GetXPathContext());
148157
delete curobject;
149158
}
150159
doclist.clear();
@@ -207,7 +216,8 @@ void DispatchMetaCardMessage(char *messagename,char *tmessage)
207216
int retvalue = 0;
208217
SetGlobal("xmlvariable",tmessage,&retvalue);
209218
char mcmessage[256];
210-
sprintf(mcmessage,"global xmlvariable;try;send \"%s xmlvariable\" to current card of stack the topstack;catch errno;end try;put 0 into extvariable",messagename);
219+
// MDW-2013-07-09: [[ reference to extvariable should be to xmlvariable ]]
220+
sprintf(mcmessage,"global xmlvariable;try;send \"%s xmlvariable\" to current card of stack the topstack;catch errno;end try;put 0 into xmlvariable",messagename);
211221
SendCardMessage(mcmessage, &retvalue);
212222
}
213223

@@ -303,7 +313,8 @@ extern char *strlwr(char *str);
303313
#endif
304314

305315

306-
#define REVXML_VERSIONSTRING "2.9.0"
316+
// MDW-2013-06-22: [[ update the version string as necessary ]]
317+
#define REVXML_VERSIONSTRING "6.2.0"
307318

308319
void REVXML_Version(char *args[], int nargs, char **retstring,
309320
Bool *pass, Bool *error)
@@ -2153,6 +2164,225 @@ void XML_FindElementByAttributeValue(char *args[], int nargs, char **retstring,
21532164
*retstring = (result != NULL ? result : (char *)calloc(1,1));
21542165
}
21552166

2167+
// MDW-2013-06-22: [[ XPath functions ]]
2168+
2169+
static xmlNodeSetPtr XML_Object_to_NodeSet(xmlXPathObjectPtr object)
2170+
{
2171+
return object->nodesetval;
2172+
}
2173+
2174+
/**
2175+
* XML_ObjectPtr_to_Xpaths
2176+
*
2177+
* @pObject
2178+
*/
2179+
static char *XML_ObjectPtr_to_Xpaths(xmlXPathObjectPtr pObject, char *cDelimiter)
2180+
{
2181+
int iBufferSize = 8192;
2182+
if (NULL != pObject)
2183+
{
2184+
xmlNodeSetPtr nodes = XML_Object_to_NodeSet(pObject);
2185+
if (NULL != nodes)
2186+
{
2187+
int i;
2188+
xmlNodePtr cur;
2189+
int size = (nodes) ? nodes->nodeNr : 0;
2190+
char *buffer = (char*)malloc(iBufferSize);
2191+
*buffer = (char)0; // null-terminate to start things off
2192+
2193+
for(i = 0; i < size; ++i)
2194+
{
2195+
cur = nodes->nodeTab[i];
2196+
if (NULL != cur)
2197+
{
2198+
xmlChar *cPtr = xmlGetNodePath(cur);
2199+
if (NULL != cPtr)
2200+
{
2201+
// make more room if needed
2202+
if (strlen(buffer) + strlen((char*)cPtr) > iBufferSize)
2203+
{
2204+
buffer = (char*)realloc(buffer, iBufferSize * 2);
2205+
iBufferSize = iBufferSize * 2;
2206+
}
2207+
strncat(buffer, (char*)cPtr, strlen((char*)cPtr));
2208+
strcat(buffer, cDelimiter);
2209+
free((char*)cPtr);
2210+
}
2211+
}
2212+
}
2213+
return (buffer);
2214+
}
2215+
else
2216+
return(NULL);
2217+
}
2218+
else
2219+
return(NULL);
2220+
}
2221+
2222+
static char *XML_ObjectPtr_to_Data(xmlXPathObjectPtr pObject, char *cDelimiter)
2223+
{
2224+
int iBufferSize = 8192;
2225+
if (NULL != pObject)
2226+
{
2227+
xmlNodeSetPtr nodes = XML_Object_to_NodeSet(pObject);
2228+
if (NULL != nodes)
2229+
{
2230+
int i;
2231+
xmlNodePtr cur;
2232+
int size = (nodes) ? nodes->nodeNr : 0;
2233+
char *buffer = (char*)malloc(iBufferSize);
2234+
*buffer = (char)0; // null-terminate to start things off
2235+
2236+
for(i = 0; i < size; ++i)
2237+
{
2238+
cur = nodes->nodeTab[i];
2239+
if (NULL != cur)
2240+
{
2241+
xmlChar *cPtr = xmlNodeGetContent(cur);
2242+
if (NULL != cPtr)
2243+
{
2244+
// make more room if needed
2245+
if (strlen(buffer) + strlen((char*)cPtr) > iBufferSize)
2246+
{
2247+
buffer = (char*)realloc(buffer, iBufferSize * 2);
2248+
iBufferSize = iBufferSize * 2;
2249+
}
2250+
strncat(buffer, (char*)cPtr, strlen((char*)cPtr));
2251+
strcat(buffer, cDelimiter);
2252+
free((char*)cPtr);
2253+
}
2254+
}
2255+
}
2256+
return (buffer);
2257+
}
2258+
else
2259+
return(NULL);
2260+
}
2261+
else
2262+
return(NULL);
2263+
}
2264+
2265+
/**
2266+
* XML_EvalXPath
2267+
* @pDocID : xml tree id
2268+
* @pExpression : xpath to evaluate
2269+
* @pDelimiter : [optional] delimiter between paths
2270+
*
2271+
* Returns a cr-separated list of paths which is the result of
2272+
* evaluating the expression against the xml tree
2273+
*
2274+
* Example:
2275+
* put revXMLEvaluateXPath(tDocID, "/bookstore/books/[price<50]", tab)
2276+
*/
2277+
void XML_EvalXPath(char *args[], int nargs, char **retstring, Bool *pass, Bool *error)
2278+
{
2279+
*pass = False;
2280+
*error = False;
2281+
2282+
int docID = atoi(args[0]);
2283+
CXMLDocument *xmlDocument = doclist.find(docID);
2284+
if (NULL != xmlDocument)
2285+
{
2286+
xmlDocPtr xmlDoc = xmlDocument->GetDocPtr();
2287+
if (NULL != xmlDoc)
2288+
{
2289+
xmlXPathContextPtr ctx = xmlXPathNewContext(xmlDoc);
2290+
if (NULL != ctx)
2291+
{
2292+
xmlChar *str = (xmlChar *)args[1];
2293+
2294+
xmlXPathObjectPtr result = xmlXPathEvalExpression(str, ctx);
2295+
if (NULL != result)
2296+
{
2297+
char *cDelimiter;
2298+
if (nargs > 2)
2299+
cDelimiter = args[2];
2300+
else
2301+
cDelimiter = "\n";
2302+
char *xpaths = XML_ObjectPtr_to_Xpaths(result, cDelimiter);
2303+
if (NULL != xpaths)
2304+
{
2305+
*retstring = istrdup(xpaths);
2306+
free(xpaths);
2307+
}
2308+
else
2309+
{
2310+
*retstring = istrdup(xmlerrors[XPATHERR_CANTRESOLVE]);
2311+
}
2312+
xmlXPathFreeObject(result);
2313+
}
2314+
xmlXPathFreeContext(ctx);
2315+
}
2316+
else
2317+
*retstring = istrdup(xmlerrors[XPATHERR_BADDOCCONTEXT]);
2318+
}
2319+
else
2320+
*retstring = istrdup(xmlerrors[XPATHERR_BADDOCPOINTER]);
2321+
}
2322+
else
2323+
*retstring = istrdup(xmlerrors[XMLERR_BADDOCID]);
2324+
}
2325+
2326+
/**
2327+
* XML_XPathDataFromQuery
2328+
* @pDocID : xml tree id
2329+
* @pExpression : xpath to evaluate
2330+
* @pDelimiter : optional delimiter between data elements
2331+
*
2332+
* Returns a cr-separated list of data which is the result of
2333+
* evaluating the expression against the xml tree
2334+
*
2335+
* put revXMLDataFromXPathQuery(tDocID, "/bookstore/books/[price<30]title", tab)
2336+
*/
2337+
void XML_XPathDataFromQuery(char *args[], int nargs, char **retstring, Bool *pass, Bool *error)
2338+
{
2339+
*pass = False;
2340+
*error = False;
2341+
2342+
int docID = atoi(args[0]);
2343+
CXMLDocument *xmlDocument = doclist.find(docID);
2344+
if (NULL != xmlDocument)
2345+
{
2346+
xmlDocPtr xmlDoc = xmlDocument->GetDocPtr();
2347+
if (NULL != xmlDoc)
2348+
{
2349+
xmlXPathContextPtr ctx = xmlXPathNewContext(xmlDoc);
2350+
if (NULL != ctx)
2351+
{
2352+
xmlChar *str = (xmlChar *)args[1];
2353+
2354+
xmlXPathObjectPtr result = xmlXPathEvalExpression(str, ctx);
2355+
if (NULL != result)
2356+
{
2357+
char *cDelimiter;
2358+
if (nargs > 2)
2359+
cDelimiter = args[2];
2360+
else
2361+
cDelimiter = "\n";
2362+
char *xpaths = XML_ObjectPtr_to_Data(result, cDelimiter);
2363+
if (NULL != xpaths)
2364+
{
2365+
*retstring = istrdup(xpaths);
2366+
free(xpaths);
2367+
}
2368+
else
2369+
{
2370+
*retstring = istrdup(xmlerrors[XPATHERR_CANTRESOLVE]);
2371+
}
2372+
xmlXPathFreeObject(result);
2373+
}
2374+
xmlXPathFreeContext(ctx);
2375+
}
2376+
else
2377+
*retstring = istrdup(xmlerrors[XPATHERR_BADDOCCONTEXT]);
2378+
}
2379+
else
2380+
*retstring = istrdup(xmlerrors[XPATHERR_BADDOCPOINTER]);
2381+
}
2382+
else
2383+
*retstring = istrdup(xmlerrors[XMLERR_BADDOCID]);
2384+
}
2385+
21562386
EXTERNAL_BEGIN_DECLARATIONS("revXML")
21572387
EXTERNAL_DECLARE_FUNCTION("revXMLinit", XML_Init)
21582388
EXTERNAL_DECLARE_FUNCTION("revXML_version", REVXML_Version)
@@ -2196,6 +2426,28 @@ EXTERNAL_BEGIN_DECLARATIONS("revXML")
21962426
EXTERNAL_DECLARE_FUNCTION("revXMLAttributes", XML_ListOfAttributes)
21972427
EXTERNAL_DECLARE_FUNCTION("revXMLMatchingNode", XML_FindElementByAttributeValue)
21982428
EXTERNAL_DECLARE_FUNCTION("revXMLAttributeValues", XML_ListByAttributeValue)
2429+
// MDW-2013-06-22: [[ declared preferred synonyms for consistency and sanity
2430+
// propose deprecating the old keywords ]]
2431+
EXTERNAL_DECLARE_FUNCTION("revXMLCreateTree", XML_NewDocumentNS)
2432+
EXTERNAL_DECLARE_FUNCTION("revXMLCreateTreeWithNamespaces", XML_NewDocumentNNS)
2433+
EXTERNAL_DECLARE_FUNCTION("revXMLCreateTreeFromFile", XML_NewDocumentFromFileNS)
2434+
EXTERNAL_DECLARE_FUNCTION("revXMLCreateTreeFromFileWithNamespaces", XML_NewDocumentFromFileNNS)
2435+
EXTERNAL_DECLARE_COMMAND("revXMLDeleteTree", XML_FreeDocument)
2436+
EXTERNAL_DECLARE_COMMAND("revXMLAppend", XML_AddXML)
2437+
EXTERNAL_DECLARE_COMMAND("revXMLDeleteAllTrees", XML_FreeAll)
2438+
EXTERNAL_DECLARE_COMMAND("revXMLAddNode", XML_AddElement)
2439+
EXTERNAL_DECLARE_COMMAND("revXMLDeleteNode", XML_RemoveElement)
2440+
EXTERNAL_DECLARE_COMMAND("revXMLInsertNode", XML_InsertElement)
2441+
EXTERNAL_DECLARE_COMMAND("revXMLMoveNode", XML_MoveElement)
2442+
EXTERNAL_DECLARE_COMMAND("revXMLCopyNode", XML_CopyElement)
2443+
EXTERNAL_DECLARE_COMMAND("revXMLCopyRemoteNode", XML_CopyRemoteElement)
2444+
EXTERNAL_DECLARE_COMMAND("revXMLMoveRemoteNode", XML_MoveRemoteElement)
2445+
EXTERNAL_DECLARE_COMMAND("revXMLPutIntoNode", XML_SetElementContents)
2446+
EXTERNAL_DECLARE_COMMAND("revXMLSetAttribute", XML_SetAttributeValue)
2447+
2448+
// MDW-2013-06-22: [[ XPath functions ]]
2449+
EXTERNAL_DECLARE_FUNCTION("revXMLEvaluateXPath", XML_EvalXPath)
2450+
EXTERNAL_DECLARE_FUNCTION("revXMLDataFromXPathQuery", XML_XPathDataFromQuery)
21992451
EXTERNAL_END_DECLARATIONS
22002452

22012453

revxml/src/xmlattribute.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ Bool CXMLAttribute::GoNext()
3434
Bool CXMLAttribute::GoPrev()
3535
{
3636
if (!isinited()) return False;
37-
Bool retval = attribute->next != NULL;
37+
// MDW-2013-07-09: [[ fixed: was attribute->next ]]
38+
Bool retval = attribute->prev != NULL;
3839
if (attribute->prev) attribute = attribute->prev;
3940
return retval;
4041
}

0 commit comments

Comments
 (0)