/** * exsltMathLowest: * @ns: a node-set * * Implements the EXSLT - Math lowest() function * node-set math:lowest (node-set) * * Returns the nodes in the node-set whose value is the minimum value * for the node-set. */ static xmlNodeSetPtr exsltMathLowest (xmlNodeSetPtr ns) { xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); double min, cur; int i; if ((ns == NULL) || (ns->nodeNr == 0)) return(ret); min = xmlXPathCastNodeToNumber(ns->nodeTab[0]); if (xmlXPathIsNaN(min)) return(ret); else xmlXPathNodeSetAddUnique(ret, ns->nodeTab[0]); for (i = 1; i < ns->nodeNr; i++) { cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); if (xmlXPathIsNaN(cur)) { xmlXPathEmptyNodeSet(ret); return(ret); } if (cur > min) continue; if (cur < min) { min = cur; xmlXPathEmptyNodeSet(ret); xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); continue; } xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); } return(ret); }
/* * call-seq: * element_children * * Get the list of children for this node as a NodeSet. All nodes will be * element nodes. * * Example: * * @doc.root.element_children.all? { |x| x.element? } # => true */ static VALUE element_children(VALUE self) { xmlNodePtr node; xmlNodePtr child; xmlNodeSetPtr set; VALUE document; VALUE node_set; Data_Get_Struct(self, xmlNode, node); child = xmlFirstElementChild(node); set = xmlXPathNodeSetCreate(child); document = DOC_RUBY_OBJECT(node->doc); if(!child) return Nokogiri_wrap_xml_node_set(set, document); child = xmlNextElementSibling(child); while(NULL != child) { xmlXPathNodeSetAddUnique(set, child); child = xmlNextElementSibling(child); } node_set = Nokogiri_wrap_xml_node_set(set, document); return node_set; }
/* * call-seq: * children * * Get the list of children for this node as a NodeSet */ static VALUE children(VALUE self) { xmlNodePtr node; xmlNodePtr child; xmlNodeSetPtr set; VALUE document; VALUE node_set; Data_Get_Struct(self, xmlNode, node); child = node->children; set = xmlXPathNodeSetCreate(child); document = DOC_RUBY_OBJECT(node->doc); if(!child) { return Nokogiri_wrap_xml_node_set(set, document); } child = child->next; while(NULL != child) { xmlXPathNodeSetAddUnique(set, child); child = child->next; } node_set = Nokogiri_wrap_xml_node_set(set, document); return node_set; }
/** * exsltStrTokenizeFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on the characters of the delimiter string and returns a * node set of token elements, each containing one token from the string. */ static void exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiters, *cur; const xmlChar *token, *delimiter; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; int clen; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiters = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); } if (delimiters == NULL) return; str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiters); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterLocalRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { for (cur = str, token = str; *cur != 0; cur += clen) { clen = xmlUTF8Size(cur); if (*delimiters == 0) { /* empty string case */ xmlChar ctmp; ctmp = *(cur+clen); *(cur+clen) = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", cur); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *(cur+clen) = ctmp; /* restore the changed byte */ token = cur + clen; } else for (delimiter = delimiters; *delimiter != 0; delimiter += xmlUTF8Size(delimiter)) { if (!xmlUTF8Charcmp(cur, delimiter)) { if (cur == token) { /* discard empty tokens */ token = cur + clen; break; } *cur = 0; /* terminate the token */ node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; /* restore the changed byte */ token = cur + clen; break; } } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, ret); } } fail: if (str != NULL) xmlFree(str); if (delimiters != NULL) xmlFree(delimiters); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }
/** * exsltStrSplitFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on a delimiting string and returns a node set of token * elements, each containing one token from the string. */ static void exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiter, *cur; const xmlChar *token; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; int delimiterLength; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiter = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiter = xmlStrdup((const xmlChar *) " "); } if (delimiter == NULL) return; delimiterLength = xmlStrlen (delimiter); str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiter); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } /* * OPTIMIZE TODO: We are creating an xmlDoc for every split! */ container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterLocalRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { for (cur = str, token = str; *cur != 0; cur++) { if (delimiterLength == 0) { if (cur != token) { xmlChar tmp = *cur; *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = tmp; token++; } } else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) { if (cur == token) { /* discard empty tokens */ cur = cur + delimiterLength - 1; token = cur + 1; continue; } *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; cur = cur + delimiterLength - 1; token = cur + 1; } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } /* * Mark it as a function result in order to avoid garbage * collecting of tree fragments */ xsltExtensionInstructionResultRegister(tctxt, ret); } } fail: if (str != NULL) xmlFree(str); if (delimiter != NULL) xmlFree(delimiter); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }
/** * exsltStrTokenizeFunction: * @ctxt: an XPath parser context * @nargs: the number of arguments * * Splits up a string on the characters of the delimiter string and returns a * node set of token elements, each containing one token from the string. */ static void exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlChar *str, *delimiters, *cur; const xmlChar *token, *delimiter; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; if ((nargs < 1) || (nargs > 2)) { xmlXPathSetArityError(ctxt); return; } if (nargs == 2) { delimiters = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) return; } else { delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); } if (delimiters == NULL) return; str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (str == NULL)) { xmlFree(delimiters); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:tokenize : internal error tctxt == NULL\n"); goto fail; } container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterTmpRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { ret->boolval = 0; /* Freeing is not handled there anymore */ for (cur = str, token = str; *cur != 0; cur++) { for (delimiter = delimiters; *delimiter != 0; delimiter++) { if (*cur == *delimiter) { if (cur == token) { /* discard empty tokens */ token = cur + 1; break; } *cur = 0; node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); *cur = *delimiter; token = cur + 1; break; } } } if (token != cur) { node = xmlNewDocRawNode(container, NULL, (const xmlChar *) "token", token); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } } } fail: if (str != NULL) xmlFree(str); if (delimiters != NULL) xmlFree(delimiters); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }
static void exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlChar *str = NULL; xmlNodeSetPtr nodeset = NULL; xsltTransformContextPtr tctxt; xmlXPathCompExprPtr comp = NULL; xmlXPathObjectPtr ret = NULL; xmlDocPtr oldDoc, container = NULL; xmlNodePtr oldNode; int oldContextSize; int oldProximityPosition; int i, j; if (nargs != 2) { xmlXPathSetArityError(ctxt); return; } str = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } nodeset = xmlXPathPopNodeSet(ctxt); if (xmlXPathCheckError(ctxt)) { xmlXPathSetTypeError(ctxt); return; } if (str == NULL || !xmlStrlen(str) || !(comp = xmlXPathCompile(str))) { if (nodeset != NULL) xmlXPathFreeNodeSet(nodeset); if (str != NULL) xmlFree(str); valuePush(ctxt, xmlXPathNewNodeSet(NULL)); return; } ret = xmlXPathNewNodeSet(NULL); if (ret == NULL) { xsltGenericError(xsltGenericErrorContext, "exsltDynMapFunction: ret == NULL\n"); goto cleanup; } oldDoc = ctxt->context->doc; oldNode = ctxt->context->node; oldContextSize = ctxt->context->contextSize; oldProximityPosition = ctxt->context->proximityPosition; tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "dyn:map : internal error tctxt == NULL\n"); goto cleanup; } container = xsltCreateRVT(tctxt); if (container == NULL) { xsltTransformError(tctxt, NULL, NULL, "dyn:map : internal error container == NULL\n"); goto cleanup; } xsltRegisterLocalRVT(tctxt, container); if (nodeset && nodeset->nodeNr > 0) { xmlXPathNodeSetSort(nodeset); ctxt->context->contextSize = nodeset->nodeNr; ctxt->context->proximityPosition = 0; for (i = 0; i < nodeset->nodeNr; i++) { xmlXPathObjectPtr subResult = NULL; ctxt->context->proximityPosition++; ctxt->context->node = nodeset->nodeTab[i]; ctxt->context->doc = nodeset->nodeTab[i]->doc; subResult = xmlXPathCompiledEval(comp, ctxt->context); if (subResult != NULL) { switch (subResult->type) { case XPATH_NODESET: if (subResult->nodesetval != NULL) for (j = 0; j < subResult->nodesetval->nodeNr; j++) xmlXPathNodeSetAdd(ret->nodesetval, subResult->nodesetval-> nodeTab[j]); break; case XPATH_BOOLEAN: if (container != NULL) { xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "boolean", BAD_CAST (subResult-> boolval ? "true" : "")); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_NUMBER: if (container != NULL) { xmlChar *val = xmlXPathCastNumberToString(subResult-> floatval); xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "number", val); if (val != NULL) xmlFree(val); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; case XPATH_STRING: if (container != NULL) { xmlNodePtr cur = xmlNewChild((xmlNodePtr) container, NULL, BAD_CAST "string", subResult->stringval); if (cur != NULL) { cur->ns = xmlNewNs(cur, BAD_CAST "http://exslt.org/common", BAD_CAST "exsl"); xmlXPathNodeSetAddUnique(ret->nodesetval, cur); } xsltExtensionInstructionResultRegister(tctxt, ret); } break; default: break; } xmlXPathFreeObject(subResult); } } } ctxt->context->doc = oldDoc; ctxt->context->node = oldNode; ctxt->context->contextSize = oldContextSize; ctxt->context->proximityPosition = oldProximityPosition; cleanup: if (comp != NULL) xmlXPathFreeCompExpr(comp); if (nodeset != NULL) xmlXPathFreeNodeSet(nodeset); if (str != NULL) xmlFree(str); valuePush(ctxt, ret); return; }
static void exsltRegexpMatchFunction (xmlXPathParserContextPtr ctxt, int nargs) { xsltTransformContextPtr tctxt; xmlNodePtr node; xmlDocPtr container; xmlXPathObjectPtr ret = NULL; xmlChar *haystack, *regexp, *flagstr, *working, *match; int rc, x, flags, global, ovector[30]; if ((nargs < 1) || (nargs > 3)) { xmlXPathSetArityError(ctxt); return; } if (nargs > 2) { flagstr = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (flagstr == NULL)) { return; } } else { flagstr = xmlStrdup(""); } regexp = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (regexp == NULL)) { xmlFree(flagstr); return; } haystack = xmlXPathPopString(ctxt); if (xmlXPathCheckError(ctxt) || (haystack == NULL)) { xmlFree(regexp); xmlFree(flagstr); return; } /* Return a result tree fragment */ tctxt = xsltXPathGetTransformContext(ctxt); if (tctxt == NULL) { xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, "exslt:regexp : internal error tctxt == NULL\n"); goto fail; } container = xsltCreateRVT(tctxt); if (container != NULL) { xsltRegisterTmpRVT(tctxt, container); ret = xmlXPathNewNodeSet(NULL); if (ret != NULL) { ret->boolval = 0; exsltRegexpFlagsFromString(flagstr, &global, &flags); working = haystack; rc = exsltRegexpExecute(ctxt, working, regexp, flags, ovector, sizeof(ovector)/sizeof(int)); while (rc > 0) { for(int group = 0; group < rc; group++) { match = xmlStrsub(working, ovector[group*2], ovector[group*2+1]-ovector[group*2]); if (NULL == match) goto fail; node = xmlNewDocRawNode(container, NULL, "match", match); xmlFree(match); xmlAddChild((xmlNodePtr) container, node); xmlXPathNodeSetAddUnique(ret->nodesetval, node); } if (!global) break; working = working + ovector[1]; rc = exsltRegexpExecute(ctxt, working, regexp, flags, ovector, sizeof(ovector)/sizeof(int)); } } } fail: if (flagstr != NULL) xmlFree(flagstr); if (regexp != NULL) xmlFree(regexp); if (haystack != NULL) xmlFree(haystack); if (ret != NULL) valuePush(ctxt, ret); else valuePush(ctxt, xmlXPathNewNodeSet(NULL)); }