📄 xpointer.c
字号:
if (node == (xmlNodePtr) ctxt->context->doc) {
return(xmlXPtrNewRange(node, 0, node,
xmlXPtrGetArity(node)));
} else {
switch (node->type) {
case XML_ATTRIBUTE_NODE:
/* !!! our model is slightly different than XPath */
return(xmlXPtrNewRange(node, 0, node,
xmlXPtrGetArity(node)));
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_DOCUMENT_NODE:
case XML_NOTATION_NODE:
case XML_HTML_DOCUMENT_NODE: {
int indx = xmlXPtrGetIndex(node);
node = node->parent;
return(xmlXPtrNewRange(node, indx - 1,
node, indx + 1));
}
default:
return(NULL);
}
}
}
default:
TODO /* missed one case ??? */
}
return(NULL);
}
/**
* xmlXPtrRangeFunction:
* @ctxt: the XPointer Parser context
* @nargs: the number of args
*
* Function implementing the range() function 5.4.3
* location-set range(location-set )
*
* The range function returns ranges covering the locations in
* the argument location-set. For each location x in the argument
* location-set, a range location representing the covering range of
* x is added to the result location-set.
*/
void
xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
int i;
xmlXPathObjectPtr set;
xmlLocationSetPtr oldset;
xmlLocationSetPtr newset;
CHECK_ARITY(1);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_LOCATIONSET) &&
(ctxt->value->type != XPATH_NODESET)))
XP_ERROR(XPATH_INVALID_TYPE)
set = valuePop(ctxt);
if (set->type == XPATH_NODESET) {
xmlXPathObjectPtr tmp;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
xmlXPathFreeObject(set);
set = tmp;
}
oldset = (xmlLocationSetPtr) set->user;
/*
* The loop is to compute the covering range for each item and add it
*/
newset = xmlXPtrLocationSetCreate(NULL);
for (i = 0;i < oldset->locNr;i++) {
xmlXPtrLocationSetAdd(newset,
xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
}
/*
* Save the new value and cleanup
*/
valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
xmlXPathFreeObject(set);
}
/**
* xmlXPtrInsideRange:
* @ctxt: the XPointer Parser context
* @loc: the location for which the inside range must be computed
*
* A inside range is a range described in the range-inside() description
*
* Returns a new location or NULL in case of error
*/
static xmlXPathObjectPtr
xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
if (loc == NULL)
return(NULL);
if ((ctxt == NULL) || (ctxt->context == NULL) ||
(ctxt->context->doc == NULL))
return(NULL);
switch (loc->type) {
case XPATH_POINT: {
xmlNodePtr node = (xmlNodePtr) loc->user;
switch (node->type) {
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE: {
if (node->content == NULL) {
return(xmlXPtrNewRange(node, 0, node, 0));
} else {
return(xmlXPtrNewRange(node, 0, node,
xmlStrlen(node->content)));
}
}
case XML_ATTRIBUTE_NODE:
case XML_ELEMENT_NODE:
case XML_ENTITY_REF_NODE:
case XML_DOCUMENT_NODE:
case XML_NOTATION_NODE:
case XML_HTML_DOCUMENT_NODE: {
return(xmlXPtrNewRange(node, 0, node,
xmlXPtrGetArity(node)));
}
default:
break;
}
return(NULL);
}
case XPATH_RANGE: {
xmlNodePtr node = (xmlNodePtr) loc->user;
if (loc->user2 != NULL) {
return(xmlXPtrNewRange(node, loc->index,
loc->user2, loc->index2));
} else {
switch (node->type) {
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE: {
if (node->content == NULL) {
return(xmlXPtrNewRange(node, 0, node, 0));
} else {
return(xmlXPtrNewRange(node, 0, node,
xmlStrlen(node->content)));
}
}
case XML_ATTRIBUTE_NODE:
case XML_ELEMENT_NODE:
case XML_ENTITY_REF_NODE:
case XML_DOCUMENT_NODE:
case XML_NOTATION_NODE:
case XML_HTML_DOCUMENT_NODE: {
return(xmlXPtrNewRange(node, 0, node,
xmlXPtrGetArity(node)));
}
default:
break;
}
return(NULL);
}
}
default:
TODO /* missed one case ??? */
}
return(NULL);
}
/**
* xmlXPtrRangeInsideFunction:
* @ctxt: the XPointer Parser context
* @nargs: the number of args
*
* Function implementing the range-inside() function 5.4.3
* location-set range-inside(location-set )
*
* The range-inside function returns ranges covering the contents of
* the locations in the argument location-set. For each location x in
* the argument location-set, a range location is added to the result
* location-set. If x is a range location, then x is added to the
* result location-set. If x is not a range location, then x is used
* as the container location of the start and end points of the range
* location to be added; the index of the start point of the range is
* zero; if the end point is a character point then its index is the
* length of the string-value of x, and otherwise is the number of
* location children of x.
*
*/
void
xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
int i;
xmlXPathObjectPtr set;
xmlLocationSetPtr oldset;
xmlLocationSetPtr newset;
CHECK_ARITY(1);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_LOCATIONSET) &&
(ctxt->value->type != XPATH_NODESET)))
XP_ERROR(XPATH_INVALID_TYPE)
set = valuePop(ctxt);
if (set->type == XPATH_NODESET) {
xmlXPathObjectPtr tmp;
/*
* First convert to a location set
*/
tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
xmlXPathFreeObject(set);
set = tmp;
}
oldset = (xmlLocationSetPtr) set->user;
/*
* The loop is to compute the covering range for each item and add it
*/
newset = xmlXPtrLocationSetCreate(NULL);
for (i = 0;i < oldset->locNr;i++) {
xmlXPtrLocationSetAdd(newset,
xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
}
/*
* Save the new value and cleanup
*/
valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
xmlXPathFreeObject(set);
}
/**
* xmlXPtrRangeToFunction:
* @ctxt: the XPointer Parser context
* @nargs: the number of args
*
* Implement the range-to() XPointer function
*/
void
xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr range;
const xmlChar *cur;
xmlXPathObjectPtr res, obj;
xmlXPathObjectPtr tmp;
xmlLocationSetPtr newset = NULL;
xmlNodeSetPtr oldset;
int i;
if (ctxt == NULL) return;
CHECK_ARITY(1);
/*
* Save the expression pointer since we will have to evaluate
* it multiple times. Initialize the new set.
*/
CHECK_TYPE(XPATH_NODESET);
obj = valuePop(ctxt);
oldset = obj->nodesetval;
ctxt->context->node = NULL;
cur = ctxt->cur;
newset = xmlXPtrLocationSetCreate(NULL);
for (i = 0; i < oldset->nodeNr; i++) {
ctxt->cur = cur;
/*
* Run the evaluation with a node list made of a single item
* in the nodeset.
*/
ctxt->context->node = oldset->nodeTab[i];
tmp = xmlXPathNewNodeSet(ctxt->context->node);
valuePush(ctxt, tmp);
xmlXPathEvalExpr(ctxt);
CHECK_ERROR;
/*
* The result of the evaluation need to be tested to
* decided whether the filter succeeded or not
*/
res = valuePop(ctxt);
range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
if (range != NULL) {
xmlXPtrLocationSetAdd(newset, range);
}
/*
* Cleanup
*/
if (res != NULL)
xmlXPathFreeObject(res);
if (ctxt->value == tmp) {
res = valuePop(ctxt);
xmlXPathFreeObject(res);
}
ctxt->context->node = NULL;
}
/*
* The result is used as the new evaluation set.
*/
xmlXPathFreeObject(obj);
ctxt->context->node = NULL;
ctxt->context->contextSize = -1;
ctxt->context->proximityPosition = -1;
valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
}
/**
* xmlXPtrAdvanceNode:
* @cur: the node
* @level: incremented/decremented to show level in tree
*
* Advance to the next element or text node in document order
* TODO: add a stack for entering/exiting entities
*
* Returns -1 in case of failure, 0 otherwise
*/
xmlNodePtr
xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
next:
if (cur == NULL)
return(NULL);
if (cur->children != NULL) {
cur = cur->children ;
if (level != NULL)
(*level)++;
goto found;
}
skip: /* This label should only be needed if something is wrong! */
if (cur->next != NULL) {
cur = cur->next;
goto found;
}
do {
cur = cur->parent;
if (level != NULL)
(*level)--;
if (cur == NULL) return(NULL);
if (cur->next != NULL) {
cur = cur->next;
goto found;
}
} while (cur != NULL);
found:
if ((cur->type != XML_ELEMENT_NODE) &&
(cur->type != XML_TEXT_NODE) &&
(cur->type != XML_DOCUMENT_NODE) &&
(cur->type != XML_HTML_DOCUMENT_NODE) &&
(cur->type != XML_CDATA_SECTION_NODE)) {
if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */
TODO
goto skip;
}
goto next;
}
return(cur);
}
/**
* xmlXPtrAdvanceChar:
* @node: the node
* @indx: the indx
* @bytes: the number of bytes
*
* Advance a point of the associated number of bytes (not UTF8 chars)
*
* Returns -1 in case of failure, 0 otherwise
*/
static int
xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) {
xmlNodePtr cur;
int pos;
int len;
if ((node == NULL) || (indx == NULL))
return(-1);
cur = *node;
if (cur == NULL)
return(-1);
pos = *indx;
while (bytes >= 0) {
/*
* First position to the beginning of the first text node
* corresponding to this point
*/
while ((cur != NULL) &&
((cur->type == XML_ELEMENT_NODE) ||
(cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE))) {
if (pos > 0) {
cur = xmlXPtrGetNthChild(cur, pos);
pos = 0;
} else {
cur = xmlXPtrAdvanceNode(cur, NULL);
pos = 0;
}
}
if (cur == NULL) {
*node = NULL;
*indx = 0;
return(-1);
}
/*
* if there is no move needed return the current value.
*/
if (pos == 0) pos = 1;
if (bytes == 0) {
*node = cur;
*indx = pos;
return(0);
}
/*
* We should have a text (or cdata) node ...
*/
len = 0;
if ((cur->type != XML_ELEMENT_NODE) &&
(cur->content != NULL)) {
len = xmlStrlen(cur->content);
}
if (pos > len) {
/* Strange, the indx in the text node is greater than it's len */
STRANGE
pos = len;
}
if (pos + bytes >= len) {
bytes -= (len - pos);
cur = xmlXPtrAdvanceNode(cur, NULL);
cur = 0;
} else if (pos + bytes < len) {
pos += bytes;
*node = cur;
*indx = pos;
return(0);
}
}
return(-1);
}
/**
* xmlXPtrMatchString:
* @string: the string to search
* @start: the start textnode
* @startindex: the start index
* @end: the end textnode IN/OUT
* @endindex: the end index IN/OUT
*
* Check whether the document contains @string at the position
* (@start, @startindex) and limited by the (@end, @endindex) point
*
* Returns -1 in case of failure, 0 if not found, 1 if found in which case
* (@start, @startindex) will indicate the position of the beginning
* of the range and (@end, @endindex) will indicate the end
* of the range
*/
static int
xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
xmlNodePtr *end, int *endindex) {
xmlNodePtr cur;
int pos; /* 0 based */
int len; /* in bytes */
int stringlen; /* in bytes */
int match;
if (string == NULL)
return(-1);
if (start == NULL)
return(-1);
if ((end == NULL) || (endindex == NULL))
return(-1);
cur = start;
if (cur == NULL)
return(-1);
pos = startindex - 1;
stringlen = xmlStrlen(string);
while (stringlen > 0) {
if ((cur == *end) && (pos + stringlen > *endindex))
return(0);
if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
len = xmlStrlen(cur->content)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -