Raw File
xpath.c
#include "RS_XML.h"

#include <libxml/xpath.h>

#include "Utils.h"



SEXP
convertNodeSetToR(xmlNodeSetPtr obj)
{
  SEXP ans;
  int i;

  if(!obj)
     return(NULL_USER_OBJECT);

  PROTECT(ans = NEW_LIST(obj->nodeNr));

  for(i = 0; i < obj->nodeNr; i++) {
     SET_VECTOR_ELT(ans, i, R_createXMLNodeRef(obj->nodeTab[i]));
  }

  SET_CLASS(ans, mkString("XMLNodeSet"));
  UNPROTECT(1);

  return(ans);
}

SEXP
convertXPathObjectToR(xmlXPathObjectPtr obj)
{
  SEXP ans = NULL_USER_OBJECT;

  switch(obj->type) {

    case XPATH_NODESET:
	ans = convertNodeSetToR(obj->nodesetval);
	break;
    case XPATH_BOOLEAN:
	ans = ScalarLogical(obj->boolval);
	break;
    case XPATH_NUMBER:
	ans = ScalarReal(obj->floatval);
	if(xmlXPathIsInf(obj->floatval))
	    REAL(ans)[0] = xmlXPathIsInf(obj->floatval) < 0 ? R_NegInf : R_PosInf;
        else if(xmlXPathIsNaN(obj->floatval))
	    REAL(ans)[0] = NA_REAL;
	break;
    case XPATH_STRING:
	ans = mkString(XMLCHAR_TO_CHAR(obj->stringval));
	break;
    case XPATH_POINT:
    case XPATH_RANGE:
    case XPATH_LOCATIONSET:
    case XPATH_USERS:
	PROBLEM "unsupported xmlXPathObject type %d in convertXPathObjectToR", obj->type
        WARN
    default:
	ans = R_NilValue;
  }

  return(ans);
}


xmlNsPtr *
R_namespaceArray(SEXP namespaces)
{
 int i, n;
 SEXP names = GET_NAMES(namespaces);
 xmlNsPtr *els;

 n = GET_LENGTH(namespaces);
 els = xmlMallocAtomic(sizeof(xmlNsPtr) * n);
 if(!els) {
   PROBLEM  "Failed to allocated space for namespaces"
   ERROR;
 }

 for(i = 0; i < n; i++) {
/*XXX who owns these strings. */
   els[i] = xmlNewNs(NULL, CHAR_TO_XMLCHAR(strdup(CHAR_DEREF(STRING_ELT(namespaces, i)))),
                           CHAR_TO_XMLCHAR(strdup(CHAR_DEREF(STRING_ELT(names, i)))));
 }

 return(els);
}


SEXP
RS_XML_xpathEval(SEXP sdoc, SEXP path, SEXP namespaces)
{
 xmlXPathContextPtr ctxt = NULL;
 xmlXPathObjectPtr result;
 SEXP ans = NULL_USER_OBJECT;

/*XXX */
 xmlDocPtr doc = (xmlDocPtr) R_ExternalPtrAddr(sdoc);
 ctxt = xmlXPathNewContext(doc);

 if(GET_LENGTH(namespaces)) {
    ctxt->namespaces =  R_namespaceArray(namespaces); /* xmlCopyNamespaceList(doc); */
    ctxt->nsNr = GET_LENGTH(namespaces);
 }


 result = xmlXPathEvalExpression(CHAR_TO_XMLCHAR(CHAR_DEREF(STRING_ELT(path, 0))), ctxt);

 if(result)
     ans = convertXPathObjectToR(result);
 
 xmlXPathFreeObject(result);
 xmlXPathFreeContext(ctxt);

 if(!result) {
   PROBLEM  "error evaluating xpath expression %s", CHAR_DEREF(STRING_ELT(path, 0))
   ERROR;
 }

 return(ans);
}
back to top