added a more convenient extension API for value and context managing Now

* include/libxml/xpath{,Internals}.h xpath.c: added a more
	  convenient extension API for value and context managing
	  Now handles external objects through xmlXPathPopExternal,
	  xmlXPathWrapExternal and xmlXPathReturnExternal.
	  Added functions for sets operations (intersection, etc.)
This commit is contained in:
Thomas Broyer 2001-07-16 04:52:57 +00:00
parent 220907319a
commit f06a3d8b53
4 changed files with 774 additions and 5 deletions

View File

@ -1,3 +1,11 @@
Mon Jul 16 06:32:44 CEST 2001 Thomas Broyer <tbroyer@ltgt.net>
* include/libxml/xpath{,Internals}.h xpath.c: added a more
convenient extension API for value and context managing
Now handles external objects through xmlXPathPopExternal,
xmlXPathWrapExternal and xmlXPathReturnExternal.
Added functions for sets operations (intersection, etc.)
Mon Jul 16 20:05:27 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
* include/libxml/parserInternals.h include/libxml/HTMLparser.h
@ -5,7 +13,7 @@ Mon Jul 16 20:05:27 CEST 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
HTMLparser.c: cleanup of global variables, marking some
const or private.
Sun Jul 16 00:17:15 CEST 2001 Thomas Broyer <tbroyer@ltgt.net>
Mon Jul 16 00:17:15 CEST 2001 Thomas Broyer <tbroyer@ltgt.net>
* include/libxml/xpath.h: exported xmlXPath{NAN,PINF,NINF}
fixed xmlXPathNodeSetItem when passing index=0

View File

@ -288,12 +288,40 @@ LIBXML_DLL_IMPORT extern double xmlXPathPINF;
LIBXML_DLL_IMPORT extern double xmlXPathNINF;
/* These macros may later turn into functions */
/**
* xmlXPathNodeSetGetLength:
* @ns: a node-set
*
* Implement a functionnality similar to the DOM NodeList.length
*
* Returns the number of nodes in the node-set.
*/
#define xmlXPathNodeSetGetLength(ns) ((ns) ? (ns)->nodeNr : 0)
/**
* xmlXPathNodeSetItem:
* @ns: a node-set
* @index: index of a node in the set
*
* Implements a functionnality similar to the DOM NodeList.item()
*
* Returns the xmlNodePtr at the given @index in @ns or NULL if
* @index is out of range (0 to length-1)
*/
#define xmlXPathNodeSetItem(ns, index) \
((((ns) != NULL) && \
((index) >= 0) && ((index) < (ns)->nodeNr)) ? \
(ns)->nodeTab[(index)] \
: NULL)
/**
* xmlXPathNodeSetIsEmpty:
* @ns: a node-set
*
* Checks whether @ns is empty or not
*
* Returns %TRUE if @ns is an empty node-set
*/
#define xmlXPathNodeSetIsEmpty(ns) \
(((ns) == NULL) || ((ns)->nodeNr == 0) || ((ns)->nodeTab == NULL))
void xmlXPathFreeObject (xmlXPathObjectPtr obj);

View File

@ -27,6 +27,173 @@ extern "C" {
* *
************************************************************************/
/**
* Many of these macros may later turn into functions. They
* shouldn't be used in #ifdef's preprocessor instructions.
*/
/**
* xmlXPathSetError:
* @ctxt: an XPath parser context
* @err: an xmlXPathError code
*
* Raises an error.
*/
#define xmlXPathSetError(ctxt, err) \
{ xmlXPatherror((ctxt), __FILE__, __LINE__, (err)); \
(ctxt)->error = (err); }
/**
* xmlXPathSetArityError:
* @ctxt: an XPath parser context
*
* Raises an XPATH_INVALID_ARITY error
*/
#define xmlXPathSetArityError(ctxt) \
xmlXPathSetError((ctxt), XPATH_INVALID_ARITY)
/**
* xmlXPathSetTypeError:
* @ctxt: an XPath parser context
*
* Raises an XPATH_INVALID_TYPE error
*/
#define xmlXPathSetTypeError(ctxt) \
xmlXPathSetError((ctxt), XPATH_INVALID_TYPE)
/**
* xmlXPathGetError:
* @ctxt: an XPath parser context
*
* Returns the context error
*/
#define xmlXPathGetError(ctxt) ((ctxt)->error)
/**
* xmlXPathCheckError:
* @ctxt: an XPath parser context
*
* Returns true if an error has been raised, false otherwise.
*/
#define xmlXPathCheckError(ctxt) ((ctxt)->error != XPATH_EXPRESSION_OK)
/**
* xmlXPathGetDocument:
* @ctxt: an XPath parser context
*
* Returns the context document
*/
#define xmlXPathGetDocument(ctxt) ((ctxt)->context->doc)
/**
* xmlXPathGetContextNode:
* @ctxt: an XPath parser context
*
* Returns the context node
*/
#define xmlXPathGetContextNode(ctxt) ((ctxt)->context->node)
int xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt);
double xmlXPathPopNumber (xmlXPathParserContextPtr ctxt);
xmlChar * xmlXPathPopString (xmlXPathParserContextPtr ctxt);
xmlNodeSetPtr xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt);
void * xmlXPathPopExternal (xmlXPathParserContextPtr ctxt);
/**
* xmlXPathReturnBoolean:
* @ctxt: an XPath parser context
* @val: a boolean
*
* Pushes the boolean @val on the context stack
*/
#define xmlXPathReturnBoolean(ctxt, val) \
valuePush((ctxt), xmlXPathNewBoolean(val))
/**
* xmlXPathReturnTrue:
* @ctxt: an XPath parser context
*
* Pushes true on the context stack
*/
#define xmlXPathReturnTrue(ctxt) xmlXPathReturnBoolean((ctxt), 1)
/**
* xmlXPathReturnFalse:
* @ctxt: an XPath parser context
*
* Pushes false on the context stack
*/
#define xmlXPathReturnFalse(ctxt) xmlXPathReturnBoolean((ctxt), 0)
/**
* xmlXPathReturnNumber:
* @ctxt: an XPath parser context
* @val: a double
*
* Pushes the double @val on the context stack
*/
#define xmlXPathReturnNumber(ctxt, val) \
valuePush((ctxt), xmlXPathNewFloat(val))
/**
* xmlXPathReturnString:
* @ctxt: an XPath parser context
* @str: a string
*
* Pushes the string @str on the context stack
*/
#define xmlXPathReturnString(ctxt, str) \
valuePush((ctxt), xmlXPathWrapString(str))
/**
* xmlXPathReturnEmptyString:
* @ctxt: an XPath parser context
*
* Pushes an empty string on the stack
*/
#define xmlXPathReturnEmptyString(ctxt) \
valuePush((ctxt), xmlXPathNewCString(""))
/**
* xmlXPathReturnNodeSet:
* @ctxt: an XPath parser context
* @ns: a node-set
*
* Pushes the node-set @ns on the context stack
*/
#define xmlXPathReturnNodeSet(ctxt, ns) \
valuePush((ctxt), xmlXPathWrapNodeSet(ns))
/**
* xmlXPathReturnEmptyNodeSet:
* @ctxt: an XPath parser context
*
* Pushes an empty node-set on the context stack
*/
#define xmlXPathReturnEmptyNodeSet(ctxt, ns) \
valuePush((ctxt), xmlXPathNewNodeSet(NULL))
/**
* xmlXPathReturnExternal:
* @ctxt: an XPath parser context
* @val: user data
*
* Pushes user data on the context stack
*/
#define xmlXPathReturnExternal(ctxt, val) \
valuePush((ctxt), xmlXPathWrapExternal(val))
/**
* xmlXPathStackIsNodeSet:
* @ctxt: an XPath parser context
*
* Returns true if the current object on the stack is a node-set
*/
#define xmlXPathStackIsNodeSet(ctxt) \
(((ctxt)->value != NULL) \
&& (((ctxt)->value->type == XPATH_NODESET) \
|| ((ctxt)->value->type == XPATH_XSLT_TREE)))
/**
* xmlXPathEmptyNodeSet:
* @ns: a node-set
*
* Empties a node-set
*/
#define xmlXPathEmptyNodeSet(ns) \
{ while ((ns)->nodeNr > 0) (ns)->nodeTab[(ns)->nodeNr--] = NULL; }
/**
* These macros shouldn't be used anymore. Prefer above functions
* and macros.
*/
/**
* CHECK_ERROR:
*
@ -123,7 +290,7 @@ extern "C" {
xmlXPathBooleanFunction(ctxt, 1);
/*
* Varibale Lookup forwarding
* Variable Lookup forwarding
*/
typedef xmlXPathObjectPtr
(*xmlXPathVariableLookupFunc) (void *ctxt,
@ -148,6 +315,40 @@ void xmlXPathDebugDumpObject (FILE *output,
void xmlXPathDebugDumpCompExpr(FILE *output,
xmlXPathCompExprPtr comp,
int depth);
/**
* NodeSet handling
*/
xmlNodeSetPtr xmlXPathDifference (xmlNodeSetPtr nodes1,
xmlNodeSetPtr nodes2);
xmlNodeSetPtr xmlXPathIntersection (xmlNodeSetPtr nodes1,
xmlNodeSetPtr nodes2);
xmlNodeSetPtr xmlXPathDistinctSorted (xmlNodeSetPtr nodes);
xmlNodeSetPtr xmlXPathDistinct (xmlNodeSetPtr nodes);
int xmlXPathHasSameNodes (xmlNodeSetPtr nodes1,
xmlNodeSetPtr nodes2);
xmlNodeSetPtr xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes,
xmlNodePtr node);
xmlNodeSetPtr xmlXPathLeadingSorted (xmlNodeSetPtr nodes1,
xmlNodeSetPtr nodes2);
xmlNodeSetPtr xmlXPathNodeLeading (xmlNodeSetPtr nodes,
xmlNodePtr node);
xmlNodeSetPtr xmlXPathLeading (xmlNodeSetPtr nodes1,
xmlNodeSetPtr nodes2);
xmlNodeSetPtr xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes,
xmlNodePtr node);
xmlNodeSetPtr xmlXPathTrailingSorted (xmlNodeSetPtr nodes1,
xmlNodeSetPtr nodes2);
xmlNodeSetPtr xmlXPathNodeTrailing (xmlNodeSetPtr nodes,
xmlNodePtr node);
xmlNodeSetPtr xmlXPathTrailing (xmlNodeSetPtr nodes1,
xmlNodeSetPtr nodes2);
/**
* Extending a context
*/
@ -244,6 +445,7 @@ void xmlXPathFreeNodeSet(xmlNodeSetPtr obj);
xmlXPathObjectPtr xmlXPathNewNodeSet(xmlNodePtr val);
xmlXPathObjectPtr xmlXPathNewNodeSetList(xmlNodeSetPtr val);
xmlXPathObjectPtr xmlXPathWrapNodeSet(xmlNodeSetPtr val);
xmlXPathObjectPtr xmlXPathWrapExternal(void *val);
void xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj);

537
xpath.c
View File

@ -941,6 +941,137 @@ extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
PUSH_AND_POP(xmlXPathObjectPtr, value)
/**
* xmlXPathPopBoolean:
* @ctxt: an XPath parser context
*
* Pops a boolean from the stack, handling conversion if needed.
* Check error with #xmlXPathCheckError.
*
* Returns the boolean
*/
int
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
int ret;
obj = valuePop(ctxt);
if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(0);
}
ret = xmlXPathCastToBoolean(obj);
xmlXPathFreeObject(obj);
return(ret);
}
/**
* xmlXPathPopNumber:
* @ctxt: an XPath parser context
*
* Pops a number from the stack, handling conversion if needed.
* Check error with #xmlXPathCheckError.
*
* Returns the number
*/
double
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
double ret;
obj = valuePop(ctxt);
if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(0);
}
ret = xmlXPathCastToNumber(obj);
xmlXPathFreeObject(obj);
return(ret);
}
/**
* xmlXPathPopString:
* @ctxt: an XPath parser context
*
* Pops a string from the stack, handling conversion if needed.
* Check error with #xmlXPathCheckError.
*
* Returns the string
*/
xmlChar *
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
xmlChar * ret;
obj = valuePop(ctxt);
if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
ret = xmlXPathCastToString(obj);
/* TODO: needs refactoring somewhere else */
if (obj->stringval == ret)
obj->stringval = NULL;
xmlXPathFreeObject(obj);
return(ret);
}
/**
* xmlXPathPopNodeSet:
* @ctxt: an XPath parser context
*
* Pops a node-set from the stack, handling conversion if needed.
* Check error with #xmlXPathCheckError.
*
* Returns the node-set
*/
xmlNodeSetPtr
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
xmlNodeSetPtr ret;
if (ctxt->value == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
if (!xmlXPathStackIsNodeSet(ctxt)) {
xmlXPathSetTypeError(ctxt);
return(NULL);
}
obj = valuePop(ctxt);
ret = obj->nodesetval;
xmlXPathFreeNodeSetList(obj);
return(ret);
}
/**
* xmlXPathPopExternal:
* @ctxt: an XPath parser context
*
* Pops an external oject from the stack, handling conversion if needed.
* Check error with #xmlXPathCheckError.
*
* Returns the object
*/
void *
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
void * ret;
if (ctxt->value == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
if (ctxt->value->type != XPATH_USERS) {
xmlXPathSetTypeError(ctxt);
return(NULL);
}
obj = valuePop(ctxt);
ret = obj->user;
xmlXPathFreeObject(obj);
return(ret);
}
/*
* Macros for accessing the content. Those should be used only by the parser,
* and not exported.
@ -1120,9 +1251,7 @@ const char *xmlXPathErrorMessages[] = {
* @line: the line number
* @no: the error number
*
* Create a new xmlNodeSetPtr of type double and of value @val
*
* Returns the newly created object.
* Formats an error message.
*/
void
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
@ -1320,6 +1449,26 @@ xmlXPathNodeSetCreate(xmlNodePtr val) {
return(ret);
}
/**
* xmlXPathNodeSetContains:
* @cur: the node-set
* @val: the node
*
* checks whether @cur contains @val
*
* Returns true (1) if @cur contains @val, false (0) otherwise
*/
int
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
int i;
for (i = 0; i < cur->nodeNr; i++) {
if (cur->nodeTab[i] == val)
return(1);
}
return(0);
}
/**
* xmlXPathNodeSetAdd:
* @cur: the initial node set
@ -1724,6 +1873,364 @@ xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
xmlFree(obj);
}
/**
* xmlXPathDifference:
* @nodes1: a node-set
* @nodes2: a node-set
*
* Implements the EXSLT - Sets difference() function:
* node-set set:difference (node-set, node-set)
*
* Returns the difference between the two node sets, or nodes1 if
* nodes2 is empty
*/
xmlNodeSetPtr
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
xmlNodeSetPtr ret;
int i, l1;
xmlNodePtr cur;
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
ret = xmlXPathNodeSetCreate(NULL);
if (xmlXPathNodeSetIsEmpty(nodes1))
return(ret);
l1 = xmlXPathNodeSetGetLength(nodes1);
for (i = 0; i < l1; i++) {
cur = xmlXPathNodeSetItem(nodes1, i);
if (!xmlXPathNodeSetContains(nodes2, cur))
xmlXPathNodeSetAddUnique(ret, cur);
}
return(ret);
}
/**
* xmlXPathIntersection:
* @nodes1: a node-set
* @nodes2: a node-set
*
* Implements the EXSLT - Sets intersection() function:
* node-set set:intersection (node-set, node-set)
*
* Returns a node set comprising the nodes that are within both the
* node sets passed as arguments
*/
xmlNodeSetPtr
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
int i, l1;
xmlNodePtr cur;
if (xmlXPathNodeSetIsEmpty(nodes1))
return(ret);
if (xmlXPathNodeSetIsEmpty(nodes2))
return(ret);
l1 = xmlXPathNodeSetGetLength(nodes1);
for (i = 0; i < l1; i++) {
cur = xmlXPathNodeSetItem(nodes1, i);
if (xmlXPathNodeSetContains(nodes2, cur))
xmlXPathNodeSetAddUnique(ret, cur);
}
return(ret);
}
/**
* xmlXPathDistinctSorted:
* @nodes: a node-set, sorted by document order
*
* Implements the EXSLT - Sets distinct() function:
* node-set set:distinct (node-set)
*
* Returns a subset of the nodes contained in @nodes, or @nodes if
* it is empty
*/
xmlNodeSetPtr
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
xmlNodeSetPtr ret;
xmlHashTablePtr hash;
int i, l;
xmlChar * strval;
xmlNodePtr cur;
if (xmlXPathNodeSetIsEmpty(nodes))
return(nodes);
ret = xmlXPathNodeSetCreate(NULL);
l = xmlXPathNodeSetGetLength(nodes);
hash = xmlHashCreate (l);
for (i = 0; i < l; i++) {
cur = xmlXPathNodeSetItem(nodes, i);
strval = xmlXPathCastNodeToString(cur);
if (xmlHashLookup(hash, strval) == NULL) {
xmlHashAddEntry(hash, strval, strval);
xmlXPathNodeSetAddUnique(ret, cur);
} else {
xmlFree(strval);
}
}
xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
return(ret);
}
/**
* xmlXPathDistinct:
* @nodes: a node-set
*
* Implements the EXSLT - Sets distinct() function:
* node-set set:distinct (node-set)
* @nodes is sorted by document order, then #exslSetsDistinctSorted
* is called with the sorted node-set
*
* Returns a subset of the nodes contained in @nodes, or @nodes if
* it is empty
*/
xmlNodeSetPtr
xmlXPathDistinct (xmlNodeSetPtr nodes) {
if (xmlXPathNodeSetIsEmpty(nodes))
return(nodes);
xmlXPathNodeSetSort(nodes);
return(xmlXPathDistinctSorted(nodes));
}
/**
* xmlXPathHasSameNodes:
* @nodes1: a node-set
* @nodes2: a node-set
*
* Implements the EXSLT - Sets has-same-nodes function:
* boolean set:has-same-node(node-set, node-set)
*
* Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
* otherwise
*/
int
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
int i, l;
xmlNodePtr cur;
if (xmlXPathNodeSetIsEmpty(nodes1) ||
xmlXPathNodeSetIsEmpty(nodes2))
return(0);
l = xmlXPathNodeSetGetLength(nodes1);
for (i = 0; i < l; i++) {
cur = xmlXPathNodeSetItem(nodes1, i);
if (xmlXPathNodeSetContains(nodes2, cur))
return(1);
}
return(0);
}
/**
* xmlXPathNodeLeadingSorted:
* @nodes: a node-set, sorted by document order
* @node: a node
*
* Implements the EXSLT - Sets leading() function:
* node-set set:leading (node-set, node-set)
*
* Returns the nodes in @nodes that precede @node in document order,
* @nodes if @node is NULL or an empty node-set if @nodes
* doesn't contain @node
*/
xmlNodeSetPtr
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
int i, l;
xmlNodePtr cur;
xmlNodeSetPtr ret;
if (node == NULL)
return(nodes);
ret = xmlXPathNodeSetCreate(NULL);
if (xmlXPathNodeSetIsEmpty(nodes) ||
(!xmlXPathNodeSetContains(nodes, node)))
return(ret);
l = xmlXPathNodeSetGetLength(nodes);
for (i = 0; i < l; i++) {
cur = xmlXPathNodeSetItem(nodes, i);
if (cur == node)
break;
xmlXPathNodeSetAddUnique(ret, cur);
}
return(ret);
}
/**
* xmlXPathNodeLeading:
* @nodes: a node-set
* @node: a node
*
* Implements the EXSLT - Sets leading() function:
* node-set set:leading (node-set, node-set)
* @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
* is called.
*
* Returns the nodes in @nodes that precede @node in document order,
* @nodes if @node is NULL or an empty node-set if @nodes
* doesn't contain @node
*/
xmlNodeSetPtr
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
xmlXPathNodeSetSort(nodes);
return(xmlXPathNodeLeadingSorted(nodes, node));
}
/**
* xmlXPathLeadingSorted:
* @nodes1: a node-set, sorted by document order
* @nodes2: a node-set, sorted by document order
*
* Implements the EXSLT - Sets leading() function:
* node-set set:leading (node-set, node-set)
*
* Returns the nodes in @nodes1 that precede the first node in @nodes2
* in document order, @nodes1 if @nodes2 is NULL or empty or
* an empty node-set if @nodes1 doesn't contain @nodes2
*/
xmlNodeSetPtr
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
return(xmlXPathNodeLeadingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 1)));
}
/**
* xmlXPathLeading:
* @nodes1: a node-set
* @nodes2: a node-set
*
* Implements the EXSLT - Sets leading() function:
* node-set set:leading (node-set, node-set)
* @nodes1 and @nodes2 are sorted by document order, then
* #exslSetsLeadingSorted is called.
*
* Returns the nodes in @nodes1 that precede the first node in @nodes2
* in document order, @nodes1 if @nodes2 is NULL or empty or
* an empty node-set if @nodes1 doesn't contain @nodes2
*/
xmlNodeSetPtr
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
if (xmlXPathNodeSetIsEmpty(nodes1))
return(xmlXPathNodeSetCreate(NULL));
xmlXPathNodeSetSort(nodes1);
xmlXPathNodeSetSort(nodes2);
return(xmlXPathNodeLeadingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 1)));
}
/**
* xmlXPathNodeTrailingSorted:
* @nodes: a node-set, sorted by document order
* @node: a node
*
* Implements the EXSLT - Sets trailing() function:
* node-set set:trailing (node-set, node-set)
*
* Returns the nodes in @nodes that follow @node in document order,
* @nodes if @node is NULL or an empty node-set if @nodes
* doesn't contain @node
*/
xmlNodeSetPtr
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
int i, l;
xmlNodePtr cur;
xmlNodeSetPtr ret;
if (node == NULL)
return(nodes);
ret = xmlXPathNodeSetCreate(NULL);
if (xmlXPathNodeSetIsEmpty(nodes) ||
(!xmlXPathNodeSetContains(nodes, node)))
return(ret);
l = xmlXPathNodeSetGetLength(nodes);
for (i = 0; i < l; i++) {
cur = xmlXPathNodeSetItem(nodes, i);
if (cur == node)
break;
xmlXPathNodeSetAddUnique(ret, cur);
}
return(ret);
}
/**
* xmlXPathNodeTrailing:
* @nodes: a node-set
* @node: a node
*
* Implements the EXSLT - Sets trailing() function:
* node-set set:trailing (node-set, node-set)
* @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
* is called.
*
* Returns the nodes in @nodes that follow @node in document order,
* @nodes if @node is NULL or an empty node-set if @nodes
* doesn't contain @node
*/
xmlNodeSetPtr
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
xmlXPathNodeSetSort(nodes);
return(xmlXPathNodeTrailingSorted(nodes, node));
}
/**
* xmlXPathTrailingSorted:
* @nodes1: a node-set, sorted by document order
* @nodes2: a node-set, sorted by document order
*
* Implements the EXSLT - Sets trailing() function:
* node-set set:trailing (node-set, node-set)
*
* Returns the nodes in @nodes1 that follow the first node in @nodes2
* in document order, @nodes1 if @nodes2 is NULL or empty or
* an empty node-set if @nodes1 doesn't contain @nodes2
*/
xmlNodeSetPtr
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
return(xmlXPathNodeTrailingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 0)));
}
/**
* xmlXPathTrailing:
* @nodes1: a node-set
* @nodes2: a node-set
*
* Implements the EXSLT - Sets trailing() function:
* node-set set:trailing (node-set, node-set)
* @nodes1 and @nodes2 are sorted by document order, then
* #xmlXPathTrailingSorted is called.
*
* Returns the nodes in @nodes1 that follow the first node in @nodes2
* in document order, @nodes1 if @nodes2 is NULL or empty or
* an empty node-set if @nodes1 doesn't contain @nodes2
*/
xmlNodeSetPtr
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
if (xmlXPathNodeSetIsEmpty(nodes1))
return(xmlXPathNodeSetCreate(NULL));
xmlXPathNodeSetSort(nodes1);
xmlXPathNodeSetSort(nodes2);
return(xmlXPathNodeTrailingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 0)));
}
/************************************************************************
* *
* Routines to handle extra functions *
@ -2191,6 +2698,30 @@ xmlXPathWrapCString (char * val) {
return(xmlXPathWrapString((xmlChar *)(val)));
}
/**
* xmlXPathWrapExternal:
* @val: the user data
*
* Wraps the @val data into an XPath object.
*
* Returns the newly created object.
*/
xmlXPathObjectPtr
xmlXPathWrapExternal (void *val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathWrapString: out of memory\n");
return(NULL);
}
memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
ret->type = XPATH_USERS;
ret->user = val;
return(ret);
}
/**
* xmlXPathObjectCopy:
* @val: the original object