@@ -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
117121const 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)
207216int retvalue = 0 ;
208217SetGlobal (" xmlvariable" ,tmessage,&retvalue);
209218char 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);
211221SendCardMessage (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
308319void 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+
21562386EXTERNAL_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)
21992451EXTERNAL_END_DECLARATIONS
22002452
22012453
0 commit comments