/* * call-seq: * context.find("xpath") -> true|false|number|string|XML::XPath::Object * * Executes the provided xpath function. The result depends on the execution * of the xpath statement. It may be true, false, a number, a string or * a node set. */ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr) { xmlXPathContextPtr xctxt; xmlXPathObjectPtr xobject; xmlXPathCompExprPtr xcompexpr; Data_Get_Struct(self, xmlXPathContext, xctxt); if (TYPE(xpath_expr) == T_STRING) { VALUE expression = rb_check_string_type(xpath_expr); xobject = xmlXPathEval((xmlChar*) StringValueCStr(expression), xctxt); } else if (rb_obj_is_kind_of(xpath_expr, cXMLXPathExpression)) { Data_Get_Struct(xpath_expr, xmlXPathCompExpr, xcompexpr); xobject = xmlXPathCompiledEval(xcompexpr, xctxt); } else { rb_raise(rb_eTypeError, "Argument should be an intance of a String or XPath::Expression"); } return rxml_xpath_to_value(xctxt, xobject); }
/** *设置XPATH *@param xpath XPATH的内容 *@return 设置成功返回true,否则返回false; */ bool gpl::xml::setXPath(const char* xpath) { xmlXPathCompExprPtr comp; comp = xmlXPathCompile(BAD_CAST xpath); if (comp == NULL) return false; if (m_xml->resource != NULL) { xmlXPathFreeObject(m_xml->resource); m_xml->resource = NULL; } //XPATH解析树输出 //xmlXPathDebugDumpCompExpr(stdout, comp, 0); m_xml->resource = xmlXPathCompiledEval(comp, m_xml->context); //XPATH返回结果输出 //xmlXPathDebugDumpObject(stdout, m_xml->resource, 0); xmlXPathFreeCompExpr(comp); if (m_xml->resource == NULL) return false; //该XPATH下无节点数则返回失败 if (m_xml->resource->nodesetval == NULL || m_xml->resource->nodesetval->nodeNr == 0) return false; return true; }
XmlXPathObjectHelper XPathExpr::eval(xmlXPathContextPtr context, const Context *ctx) const { try { XmlXPathObjectHelper xpathObj; if (compiled()) { xpathObj = XmlXPathObjectHelper(xmlXPathCompiledEval( compiled_expr_.get(), context)); } else { const std::string expr = expression(ctx); if (stripAllOutput(expr)) { xpathObj = XmlXPathObjectHelper(xmlXPathEvalExpression( (const xmlChar *)STRIP_XPOINTER.c_str(), context)); } else { xpathObj = XmlXPathObjectHelper(xmlXPathEvalExpression( (const xmlChar *)expr.c_str(), context)); } } XmlUtils::throwUnless(NULL != xpathObj.get()); return xpathObj; } catch(const std::exception &e) { std::string message = "XPath error with expression " + expression(ctx) + " : "; message.append(e.what()); throw std::runtime_error(message); } }
/* * Class: org_xmlsoft_XPathContext * Method: evaluateCompiledImpl * Signature: (Lrath/libxml/XPathExpression;)Lrath/libxml/XPathObject; */ JNIEXPORT jobject JNICALL Java_org_xmlsoft_XPathContext_evaluateCompiledImpl (JNIEnv *env, jobject obj, jobject expr) { xmlXPathContext *ctx = findXPathContext(env, obj); xmlXPathCompExpr *compiled = (xmlXPathCompExprPtr)(*env)->GetLongField(env, expr, fieldXPathExprP); xmlXPathObject *result = xmlXPathCompiledEval(compiled, ctx); return buildXPathObject(env, obj, result); }
/* * call-seq: * context.find("xpath") -> true|false|number|string|XML::XPath::Object * * Executes the provided xpath function. The result depends on the execution * of the xpath statement. It may be true, false, a number, a string or * a node set. */ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr) { xmlXPathContextPtr xctxt; xmlXPathObjectPtr xobject; xmlXPathCompExprPtr xcompexpr; VALUE result; Data_Get_Struct(self, xmlXPathContext, xctxt); if (TYPE(xpath_expr) == T_STRING) { VALUE expression = rb_check_string_type(xpath_expr); xobject = xmlXPathEval((xmlChar*) StringValueCStr(expression), xctxt); } else if (rb_obj_is_kind_of(xpath_expr, cXMLXPathExpression)) { Data_Get_Struct(xpath_expr, xmlXPathCompExpr, xcompexpr); xobject = xmlXPathCompiledEval(xcompexpr, xctxt); } else { rb_raise(rb_eTypeError, "Argument should be an intance of a String or XPath::Expression"); } if (xobject == NULL) { /* xmlLastError is different than xctxt->lastError. Use xmlLastError since it has the message set while xctxt->lastError does not. */ xmlErrorPtr xerror = xmlGetLastError(); rxml_raise(xerror); } switch (xobject->type) { case XPATH_NODESET: result = rxml_xpath_object_wrap(xctxt->doc, xobject); break; case XPATH_BOOLEAN: result = (xobject->boolval != 0) ? Qtrue : Qfalse; xmlXPathFreeObject(xobject); break; case XPATH_NUMBER: result = rb_float_new(xobject->floatval); xmlXPathFreeObject(xobject); break; case XPATH_STRING: result = rb_str_new2((const char*)xobject->stringval); xmlXPathFreeObject(xobject); break; default: result = Qnil; xmlXPathFreeObject(xobject); } return result; }
/** * xmlSchematronRunTest: * @ctxt: the schema validation context * @test: the current test * @instance: the document instace tree * @cur: the current node in the instance * * Validate a rule against a tree instance at a given position * * Returns 1 in case of success, 0 if error and -1 in case of internal error */ static int xmlSchematronRunTest(xmlSchematronValidCtxtPtr ctxt, xmlSchematronTestPtr test, xmlDocPtr instance, xmlNodePtr cur, xmlSchematronPatternPtr pattern) { xmlXPathObjectPtr ret; int failed; failed = 0; ctxt->xctxt->doc = instance; ctxt->xctxt->node = cur; ret = xmlXPathCompiledEval(test->comp, ctxt->xctxt); if (ret == NULL) { failed = 1; } else { switch (ret->type) { case XPATH_XSLT_TREE: case XPATH_NODESET: if ((ret->nodesetval == NULL) || (ret->nodesetval->nodeNr == 0)) failed = 1; break; case XPATH_BOOLEAN: failed = !ret->boolval; break; case XPATH_NUMBER: if ((xmlXPathIsNaN(ret->floatval)) || (ret->floatval == 0.0)) failed = 1; break; case XPATH_STRING: if ((ret->stringval == NULL) || (ret->stringval[0] == 0)) failed = 1; break; case XPATH_UNDEFINED: case XPATH_POINT: case XPATH_RANGE: case XPATH_LOCATIONSET: case XPATH_USERS: failed = 1; break; } xmlXPathFreeObject(ret); } if ((failed) && (test->type == XML_SCHEMATRON_ASSERT)) ctxt->nberrors++; else if ((!failed) && (test->type == XML_SCHEMATRON_REPORT)) ctxt->nberrors++; xmlSchematronReportSuccess(ctxt, test, cur, pattern, !failed); return(!failed); }
xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar * xpath) { xmlDocPtr doctree; xmlXPathContextPtr ctxt; xmlXPathObjectPtr res; xmlXPathCompExprPtr comppath; int32 docsize; docsize = VARSIZE(document) - VARHDRSZ; pgxml_parser_init(); doctree = xmlParseMemory((char *) VARDATA(document), docsize); if (doctree == NULL) { /* not well-formed */ return NULL; } ctxt = xmlXPathNewContext(doctree); ctxt->node = xmlDocGetRootElement(doctree); /* compile the path */ comppath = xmlXPathCompile(xpath); if (comppath == NULL) { xmlCleanupParser(); xmlFreeDoc(doctree); elog_error(ERROR, "XPath Syntax Error", 1); return NULL; } /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); if (res == NULL) { xmlXPathFreeContext(ctxt); /* xmlCleanupParser(); */ xmlFreeDoc(doctree); return NULL; } /* xmlFreeDoc(doctree); */ return res; }
static void findXMLTagsCore (xmlXPathContext *ctx, xmlNode *root, const tagXpathTableTable *xpathTableTable, const kindOption* const kinds,void *userData) { unsigned int i; int j; xmlNode * node; Assert (root); Assert (xpathTableTable); for (i = 0; i < xpathTableTable->count; ++i) { xmlXPathObject *object; xmlNodeSet *set; const tagXpathTable *elt = xpathTableTable->table + i; if (! elt->xpathCompiled) continue; #if 0 /* Older version of libxml2 doesn't have xmlXPathSetContextNode. */ if (xmlXPathSetContextNode (root, ctx) != 0) { error (WARNING, "Failed to set node to XpathContext"); return; } #else ctx->node = root; #endif object = xmlXPathCompiledEval (elt->xpathCompiled, ctx); if (!object) continue; set = object->nodesetval; if (set) { for (j = 0; j < set->nodeNr; ++j) { node = set->nodeTab[j]; if (elt->specType == LXPATH_TABLE_DO_MAKE) simpleXpathMakeTag (node, &(elt->makeTagSpec), kinds, userData); else elt->recurSpec.enter (node, &(elt->recurSpec), ctx, userData); } } xmlXPathFreeObject (object); } }
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace) { int32 docsize = VARSIZE(document) - VARHDRSZ; PgXmlErrorContext *xmlerrcxt; xmlXPathCompExprPtr comppath; workspace->doctree = NULL; workspace->ctxt = NULL; workspace->res = NULL; xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); PG_TRY(); { workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize); if (workspace->doctree != NULL) { workspace->ctxt = xmlXPathNewContext(workspace->doctree); workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree); /* compile the path */ comppath = xmlXPathCompile(xpath); if (comppath == NULL) xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, "XPath Syntax Error"); /* Now evaluate the path expression. */ workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt); xmlXPathFreeCompExpr(comppath); } } PG_CATCH(); { cleanup_workspace(workspace); pg_xml_done(xmlerrcxt, true); PG_RE_THROW(); } PG_END_TRY(); if (workspace->res == NULL) cleanup_workspace(workspace); pg_xml_done(xmlerrcxt, false); return workspace->res; }
const XMLXPath *XMLDocument::makeXPathQuery(const char *query, char **namespaces, int length, const XMLElement * e, std::string * error) { errorXPathBuffer.clear(); xmlXPathContext *ctxt = xmlXPathNewContext(document); if (!ctxt) { errorXPathBuffer.append(gettext("Cannot create a parser context")); *error = errorXPathBuffer; return 0; } if (e) { ctxt->node = (xmlNode *) e->getRealXMLPointer(); } if (namespaces) { for (int i = 0; i < length; i++) { xmlXPathRegisterNs(ctxt, (const xmlChar *)namespaces[i], (const xmlChar *)namespaces[i + length]); } } xmlSetStructuredErrorFunc(ctxt, XMLDocument::errorXPathFunction); xmlXPathCompExpr *expr = xmlXPathCtxtCompile(ctxt, (const xmlChar *)query); if (!expr) { xmlSetStructuredErrorFunc(ctxt, 0); xmlXPathFreeContext(ctxt); *error = errorXPathBuffer; return 0; } xmlXPathObject *xpath = xmlXPathCompiledEval(expr, ctxt); xmlSetStructuredErrorFunc(ctxt, 0); xmlXPathFreeContext(ctxt); xmlXPathFreeCompExpr(expr); if (!xpath) { *error = errorXPathBuffer; return 0; } return new XMLXPath(*this, xpath); }
/** * xsltEvalXPathStringNs: * @ctxt: the XSLT transformation context * @comp: the compiled XPath expression * @nsNr: the number of namespaces in the list * @nsList: the list of in-scope namespaces to use * * Process the expression using XPath, allowing to pass a namespace mapping * context and get a string * * Returns the computed string value or NULL, must be deallocated by the * caller. */ xmlChar * xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, int nsNr, xmlNsPtr *nsList) { xmlChar *ret = NULL; xmlXPathObjectPtr res; xmlNodePtr oldInst; xmlNodePtr oldNode; int oldPos, oldSize; int oldNsNr; xmlNsPtr *oldNamespaces; oldInst = ctxt->inst; oldNode = ctxt->node; oldPos = ctxt->xpathCtxt->proximityPosition; oldSize = ctxt->xpathCtxt->contextSize; oldNsNr = ctxt->xpathCtxt->nsNr; oldNamespaces = ctxt->xpathCtxt->namespaces; ctxt->xpathCtxt->node = ctxt->node; /* TODO: do we need to propagate the namespaces here ? */ ctxt->xpathCtxt->namespaces = nsList; ctxt->xpathCtxt->nsNr = nsNr; res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); if (res != NULL) { if (res->type != XPATH_STRING) res = xmlXPathConvertString(res); if (res->type == XPATH_STRING) { ret = res->stringval; res->stringval = NULL; } else { xsltTransformError(ctxt, NULL, NULL, "xpath : string() function didn't return a String\n"); } xmlXPathFreeObject(res); } else { ctxt->state = XSLT_STATE_STOPPED; } #ifdef WITH_XSLT_DEBUG_TEMPLATES XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltEvalXPathString: returns %s\n", ret)); #endif ctxt->inst = oldInst; ctxt->node = oldNode; ctxt->xpathCtxt->contextSize = oldSize; ctxt->xpathCtxt->proximityPosition = oldPos; ctxt->xpathCtxt->nsNr = oldNsNr; ctxt->xpathCtxt->namespaces = oldNamespaces; return(ret); }
/** * xsltEvalXPathPredicate: * @ctxt: the XSLT transformation context * @comp: the XPath compiled expression * @nsList: the namespaces in scope * @nsNr: the number of namespaces in scope * * Process the expression using XPath and evaluate the result as * an XPath predicate * * Returns 1 is the predicate was true, 0 otherwise */ int xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, xmlNsPtr *nsList, int nsNr) { int ret; xmlXPathObjectPtr res; int oldNsNr; xmlNsPtr *oldNamespaces; xmlNodePtr oldInst; int oldProximityPosition, oldContextSize; oldContextSize = ctxt->xpathCtxt->contextSize; oldProximityPosition = ctxt->xpathCtxt->proximityPosition; oldNsNr = ctxt->xpathCtxt->nsNr; oldNamespaces = ctxt->xpathCtxt->namespaces; oldInst = ctxt->inst; ctxt->xpathCtxt->node = ctxt->node; ctxt->xpathCtxt->namespaces = nsList; ctxt->xpathCtxt->nsNr = nsNr; res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); if (res != NULL) { ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res); xmlXPathFreeObject(res); #ifdef WITH_XSLT_DEBUG_TEMPLATES XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltEvalXPathPredicate: returns %d\n", ret)); #endif } else { #ifdef WITH_XSLT_DEBUG_TEMPLATES XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, "xsltEvalXPathPredicate: failed\n")); #endif ctxt->state = XSLT_STATE_STOPPED; ret = 0; } ctxt->xpathCtxt->nsNr = oldNsNr; ctxt->xpathCtxt->namespaces = oldNamespaces; ctxt->inst = oldInst; ctxt->xpathCtxt->contextSize = oldContextSize; ctxt->xpathCtxt->proximityPosition = oldProximityPosition; return(ret); }
static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace) { int32 docsize = VARSIZE(document) - VARHDRSZ; xmlXPathObjectPtr res; xmlXPathCompExprPtr comppath; workspace->doctree = NULL; workspace->ctxt = NULL; workspace->res = NULL; pgxml_parser_init(); workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize); if (workspace->doctree == NULL) return NULL; /* not well-formed */ workspace->ctxt = xmlXPathNewContext(workspace->doctree); workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree); /* compile the path */ comppath = xmlXPathCompile(xpath); if (comppath == NULL) { cleanup_workspace(workspace); xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, "XPath Syntax Error"); } /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, workspace->ctxt); workspace->res = res; xmlXPathFreeCompExpr(comppath); if (res == NULL) cleanup_workspace(workspace); return res; }
/* * call-seq: * context.find("xpath") -> XML::XPath::Object * * Find nodes matching the specified XPath expression */ static VALUE rxml_xpath_context_find(VALUE self, VALUE xpath_expr) { xmlXPathContextPtr xctxt; xmlXPathObjectPtr xobject; xmlXPathCompExprPtr xcompexpr; VALUE result; Data_Get_Struct(self, xmlXPathContext, xctxt); if (TYPE(xpath_expr) == T_STRING) { VALUE expression = rb_check_string_type(xpath_expr); xobject = xmlXPathEval((xmlChar*) StringValueCStr(expression), xctxt); } else if (rb_obj_is_kind_of(xpath_expr, cXMLXPathExpression)) { Data_Get_Struct(xpath_expr, xmlXPathCompExpr, xcompexpr); xobject = xmlXPathCompiledEval(xcompexpr, xctxt); } else { rb_raise(rb_eTypeError, "Argument should be an intance of a String or XPath::Expression"); } if (xobject == NULL) { /* xmlLastError is different than xctxt->lastError. Use xmlLastError since it has the message set while xctxt->lastError does not. */ xmlErrorPtr xerror = xmlGetLastError(); rxml_raise(xerror); } result = rxml_xpath_object_wrap(xobject); rb_iv_set(result, "@context", self); return result; }
static void testXPath(const char *str) { xmlXPathObjectPtr res; xmlXPathContextPtr ctxt; #if defined(LIBXML_XPTR_ENABLED) if (xptr) { ctxt = xmlXPtrNewContext(document, NULL, NULL); res = xmlXPtrEval(BAD_CAST str, ctxt); } else { #endif ctxt = xmlXPathNewContext(document); ctxt->node = xmlDocGetRootElement(document); if (expr) res = xmlXPathEvalExpression(BAD_CAST str, ctxt); else { /* res = xmlXPathEval(BAD_CAST str, ctxt); */ xmlXPathCompExprPtr comp; comp = xmlXPathCompile(BAD_CAST str); if (comp != NULL) { if (tree) xmlXPathDebugDumpCompExpr(stdout, comp, 0); res = xmlXPathCompiledEval(comp, ctxt); xmlXPathFreeCompExpr(comp); } else res = NULL; } #if defined(LIBXML_XPTR_ENABLED) } #endif xmlXPathDebugDumpObject(stdout, res, 0); xmlXPathFreeObject(res); xmlXPathFreeContext(ctxt); }
xmlXPathObjectPtr get_nodes_with_name_xpath( XMLDoc *tree, FeriteString *str ) { char *xpath, *x = "descendant-or-self::node()"; xmlXPathCompExprPtr comp = NULL; int length = strlen( x ) + str->length + 4; xpath = malloc(length); memset(xpath, '\0', length ); sprintf( xpath, "%s/%s", x, str->data ); comp = xmlXPathCompile( BAD_CAST xpath ); free(xpath); if( comp != NULL ) { xmlXPathObjectPtr res = NULL; xmlXPathContextPtr ctxt = xmlXPathNewContext( tree->doc ); ctxt->node = tree->node; res = xmlXPathCompiledEval( comp, ctxt ); xmlXPathFreeContext( ctxt ); xmlXPathFreeCompExpr( comp ); return res; } return NULL; }
/** * 'update' operation */ static void edUpdate(xmlDocPtr doc, xmlNodeSetPtr nodes, const char *val, XmlNodeType type, xmlXPathContextPtr ctxt) { int i; xmlXPathCompExprPtr xpath = NULL; if (type == XML_EXPR) { xpath = xmlXPathCompile((const xmlChar*) val); if (!xpath) return; } for (i = 0; i < nodes->nodeNr; i++) { /* update node */ if (type == XML_EXPR) { xmlXPathObjectPtr res; ctxt->node = nodes->nodeTab[i]; res = xmlXPathCompiledEval(xpath, ctxt); if (res->type == XPATH_NODESET || res->type == XPATH_XSLT_TREE) { int j; xmlNodePtr oldChild; xmlNodeSetPtr oldChildren = xmlXPathNodeSetCreate(NULL); /* NOTE: newChildren can be NULL for empty result set */ xmlNodeSetPtr newChildren = res->nodesetval; /* NOTE: nodes can be both oldChildren and newChildren */ /* unlink the old children */ for (oldChild = nodes->nodeTab[i]->children; oldChild; oldChild = oldChild->next) { xmlUnlinkNode(oldChild); /* we can't free it now because an oldChild can also be newChild! just put it in the list */ xmlXPathNodeSetAdd(oldChildren, oldChild); } /* add the new children */ for (j = 0; newChildren && j < newChildren->nodeNr; j++) { xmlNodePtr node = newChildren->nodeTab[j]; xmlAddChild(nodes->nodeTab[i], /* if node is linked to this doc we need to copy */ (node->doc == doc)? xmlDocCopyNode(node, doc, 1) : node); newChildren->nodeTab[j] = NULL; } newChildren->nodeNr = 0; /* NOTE: if any oldChildren were newChildren, they've been copied so we can free them all now */ for (j = 0; j < oldChildren->nodeNr; j++) { xmlFreeNode(oldChildren->nodeTab[j]); oldChildren->nodeTab[j] = NULL; } oldChildren->nodeNr = 0; xmlXPathFreeNodeSet(oldChildren); } else { res = xmlXPathConvertString(res); update_string(doc, nodes->nodeTab[i], res->stringval); } xmlXPathFreeObject(res); } else { update_string(doc, nodes->nodeTab[i], (const xmlChar*) val); } } xmlXPathFreeCompExpr(xpath); }
/** * xsltInitCtxtKey: * @ctxt: an XSLT transformation context * @idoc: the document information (holds key values) * @keyDef: the key definition * * Computes the key tables this key and for the current input document. * * Returns: 0 on success, -1 on error */ int xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc, xsltKeyDefPtr keyDef) { int i, len, k; xmlNodeSetPtr matchList = NULL, keylist; xmlXPathObjectPtr matchRes = NULL, useRes = NULL; xmlChar *str = NULL; xsltKeyTablePtr table; xmlNodePtr oldInst, cur; xmlNodePtr oldContextNode; xsltDocumentPtr oldDocInfo; int oldXPPos, oldXPSize; xmlDocPtr oldXPDoc; int oldXPNsNr; xmlNsPtr *oldXPNamespaces; xmlXPathContextPtr xpctxt; #ifdef KEY_INIT_DEBUG fprintf(stderr, "xsltInitCtxtKey %s : %d\n", keyDef->name, ctxt->keyInitLevel); #endif if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL)) return(-1); /* * Detect recursive keys */ if (ctxt->keyInitLevel > ctxt->nbKeys) { #ifdef WITH_XSLT_DEBUG_KEYS XSLT_TRACE(ctxt,XSLT_TRACE_KEYS, xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtKey: key definition of %s is recursive\n", keyDef->name)); #endif xsltTransformError(ctxt, NULL, keyDef->inst, "Key definition for %s is recursive\n", keyDef->name); ctxt->state = XSLT_STATE_STOPPED; return(-1); } ctxt->keyInitLevel++; xpctxt = ctxt->xpathCtxt; idoc->nbKeysComputed++; /* * Save context state. */ oldInst = ctxt->inst; oldDocInfo = ctxt->document; oldContextNode = ctxt->node; oldXPDoc = xpctxt->doc; oldXPPos = xpctxt->proximityPosition; oldXPSize = xpctxt->contextSize; oldXPNsNr = xpctxt->nsNr; oldXPNamespaces = xpctxt->namespaces; /* * Set up contexts. */ ctxt->document = idoc; ctxt->node = (xmlNodePtr) idoc->doc; ctxt->inst = keyDef->inst; xpctxt->doc = idoc->doc; xpctxt->node = (xmlNodePtr) idoc->doc; /* TODO : clarify the use of namespaces in keys evaluation */ xpctxt->namespaces = keyDef->nsList; xpctxt->nsNr = keyDef->nsNr; /* * Evaluate the 'match' expression of the xsl:key. * TODO: The 'match' is a *pattern*. */ matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt); if (matchRes == NULL) { #ifdef WITH_XSLT_DEBUG_KEYS XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtKey: %s evaluation failed\n", keyDef->match)); #endif xsltTransformError(ctxt, NULL, keyDef->inst, "Failed to evaluate the 'match' expression.\n"); ctxt->state = XSLT_STATE_STOPPED; goto error; } else { if (matchRes->type == XPATH_NODESET) { matchList = matchRes->nodesetval; #ifdef WITH_XSLT_DEBUG_KEYS if (matchList != NULL) XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtKey: %s evaluates to %d nodes\n", keyDef->match, matchList->nodeNr)); #endif } else { /* * Is not a node set, but must be. */ #ifdef WITH_XSLT_DEBUG_KEYS XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtKey: %s is not a node set\n", keyDef->match)); #endif xsltTransformError(ctxt, NULL, keyDef->inst, "The 'match' expression did not evaluate to a node set.\n"); ctxt->state = XSLT_STATE_STOPPED; goto error; } } if ((matchList == NULL) || (matchList->nodeNr <= 0)) goto exit; /** * Multiple key definitions for the same name are allowed, so * we must check if the key is already present for this doc */ table = (xsltKeyTablePtr) idoc->keys; while (table != NULL) { if (xmlStrEqual(table->name, keyDef->name) && (((keyDef->nameURI == NULL) && (table->nameURI == NULL)) || ((keyDef->nameURI != NULL) && (table->nameURI != NULL) && (xmlStrEqual(table->nameURI, keyDef->nameURI))))) break; table = table->next; } /** * If the key was not previously defined, create it now and * chain it to the list of keys for the doc */ if (table == NULL) { table = xsltNewKeyTable(keyDef->name, keyDef->nameURI); if (table == NULL) goto error; table->next = idoc->keys; idoc->keys = table; } /* * SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!) * "...the use attribute of the xsl:key element is evaluated with x as " the current node and with a node list containing just x as the * current node list" */ xpctxt->contextSize = 1; xpctxt->proximityPosition = 1; for (i = 0; i < matchList->nodeNr; i++) { cur = matchList->nodeTab[i]; if (! IS_XSLT_REAL_NODE(cur)) continue; xpctxt->node = cur; /* * Process the 'use' of the xsl:key. * SPEC XSLT 1.0: * "The use attribute is an expression specifying the values of * the key; the expression is evaluated once for each node that * matches the pattern." */ if (useRes != NULL) xmlXPathFreeObject(useRes); useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt); if (useRes == NULL) { xsltTransformError(ctxt, NULL, keyDef->inst, "Failed to evaluate the 'use' expression.\n"); ctxt->state = XSLT_STATE_STOPPED; break; } if (useRes->type == XPATH_NODESET) { if ((useRes->nodesetval != NULL) && (useRes->nodesetval->nodeNr != 0)) { len = useRes->nodesetval->nodeNr; str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]); } else { continue; } } else { len = 1; if (useRes->type == XPATH_STRING) { /* * Consume the string value. */ str = useRes->stringval; useRes->stringval = NULL; } else { str = xmlXPathCastToString(useRes); } } /* * Process all strings. */ k = 0; while (1) { if (str == NULL) goto next_string; #ifdef WITH_XSLT_DEBUG_KEYS XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str)); #endif keylist = xmlHashLookup(table->keys, str); if (keylist == NULL) { keylist = xmlXPathNodeSetCreate(cur); if (keylist == NULL) goto error; xmlHashAddEntry(table->keys, str, keylist); } else { /* * TODO: How do we know if this function failed? */ xmlXPathNodeSetAdd(keylist, cur); } switch (cur->type) { case XML_ELEMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: cur->psvi = keyDef; break; case XML_ATTRIBUTE_NODE: ((xmlAttrPtr) cur)->psvi = keyDef; break; case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: ((xmlDocPtr) cur)->psvi = keyDef; break; default: break; } xmlFree(str); str = NULL; next_string: k++; if (k >= len) break; str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]); } } exit: error: ctxt->keyInitLevel--; /* * Restore context state. */ xpctxt->doc = oldXPDoc; xpctxt->nsNr = oldXPNsNr; xpctxt->namespaces = oldXPNamespaces; xpctxt->proximityPosition = oldXPPos; xpctxt->contextSize = oldXPSize; ctxt->node = oldContextNode; ctxt->document = oldDocInfo; ctxt->inst = oldInst; if (str) xmlFree(str); if (useRes != NULL) xmlXPathFreeObject(useRes); if (matchRes != NULL) xmlXPathFreeObject(matchRes); return(0); }
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; }
//! Evaluate XPath expression in the specified context. //----------------------------------------------------------------------- static result_type eval(expression_type const expr, evaluator_type const ctx) { return xmlXPathCompiledEval(expr, ctx); }
/** * fastxml_xpath_search provides a common xpath search function for * the libraries bits (node, doc). it handles mangling non-namespaced * xpath queries into something libxml will play nice with */ VALUE fastxml_xpath_search(VALUE self, VALUE raw_xpath, VALUE blk) { VALUE ret, dv, xpath_s; xmlXPathCompExprPtr xpath_xpr; xmlXPathContextPtr xpath_ctx; xmlXPathObjectPtr xpath_obj; fxml_data_t *data; xmlChar *xpath_expr; xmlNodePtr root = NULL; xmlNsPtr *ns_list = NULL; xmlNsPtr *cur_ns = NULL; xmlChar *root_ns = NULL; int ns_cnt = 0; if (NIL_P(raw_xpath)) rb_raise(rb_eArgError, "nil passed as xpath"); dv = rb_iv_get( self, "@lxml_doc" ); Data_Get_Struct( dv, fxml_data_t, data ); xpath_ctx = xmlXPathNewContext( data->doc ); if (xpath_ctx == NULL) rb_raise( rb_eRuntimeError, "unable to create xpath context" ); root = data->node; if (root == NULL) root = xmlDocGetRootElement( data->doc ); xpath_ctx->node = root; cur_ns = ns_list = xmlGetNsList( data->doc, root ); while (cur_ns != NULL && (*cur_ns) != NULL) { xmlXPathRegisterNs( xpath_ctx, (*cur_ns)->prefix, (*cur_ns)->href ); cur_ns++; } if (ns_list != NULL) { xpath_ctx->namespaces = ns_list; xpath_ctx->nsNr = ns_cnt; } xpath_s = rb_obj_as_string( raw_xpath ); if (root->ns != NULL) { // we have a base namespace, this is going to get "interesting" root_ns = (xmlChar*)root->ns->prefix; if (root_ns == NULL) root_ns = (xmlChar*)"__myFunkyLittleRootNsNotToBeUseByAnyoneElseIHope__"; // alternatives? how do other xpath processors handle root/default namespaces? xmlXPathRegisterNs( xpath_ctx, root_ns, root->ns->href ); // need to update the xpath expression xpath_s = munge_xpath_namespace( xpath_s, root_ns ); xpath_ctx->nsNr++; } xpath_expr = (xmlChar*)RSTRING_PTR(xpath_s); xpath_xpr = xmlXPathCompile( xpath_expr ); if (xpath_xpr == NULL) { xmlXPathFreeContext( xpath_ctx ); xmlFree( ns_list ); rb_raise( rb_eRuntimeError, "unable to evaluate xpath expression" ); } xpath_obj = xmlXPathCompiledEval( xpath_xpr, xpath_ctx ); if (xpath_obj == NULL) { rb_raise( rb_eRuntimeError, "unable to evaluate xpath expression" ); xmlXPathFreeCompExpr( xpath_xpr ); xmlXPathFreeContext( xpath_ctx ); xmlFree( ns_list ); return Qnil; } ret = fastxml_nodeset_to_obj( xpath_obj, data ); xmlFree( ns_list ); xmlXPathFreeCompExpr( xpath_xpr ); xmlXPathFreeContext( xpath_ctx ); return ret; }
Datum xpath_table(PG_FUNCTION_ARGS) { /* Function parameters */ char *pkeyfield = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *xmlfield = text_to_cstring(PG_GETARG_TEXT_PP(1)); char *relname = text_to_cstring(PG_GETARG_TEXT_PP(2)); char *xpathset = text_to_cstring(PG_GETARG_TEXT_PP(3)); char *condition = text_to_cstring(PG_GETARG_TEXT_PP(4)); /* SPI (input tuple) support */ SPITupleTable *tuptable; HeapTuple spi_tuple; TupleDesc spi_tupdesc; /* Output tuple (tuplestore) support */ Tuplestorestate *tupstore = NULL; TupleDesc ret_tupdesc; HeapTuple ret_tuple; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; AttInMetadata *attinmeta; MemoryContext per_query_ctx; MemoryContext oldcontext; char **values; xmlChar **xpaths; char *pos; const char *pathsep = "|"; int numpaths; int ret; int proc; int i; int j; int rownr; /* For issuing multiple rows from one original * document */ bool had_values; /* To determine end of nodeset results */ StringInfoData query_buf; PgXmlErrorContext *xmlerrcxt; volatile xmlDocPtr doctree = NULL; /* We only have a valid tuple description in table function mode */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (rsinfo->expectedDesc == NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("xpath_table must be called as a table function"))); /* * We want to materialise because it means that we don't have to carry * libxml2 parser state between invocations of this function */ if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("xpath_table requires Materialize mode, but it is not " "allowed in this context"))); /* * The tuplestore must exist in a higher context than this function call * (per_query_ctx is used) */ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); /* * Create the tuplestore - work_mem is the max in-memory size before a * file is created on disk to hold it. */ tupstore = tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, false, work_mem); MemoryContextSwitchTo(oldcontext); /* get the requested return tuple description */ ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc); /* must have at least one output column (for the pkey) */ if (ret_tupdesc->natts < 1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("xpath_table must have at least one output column"))); /* * At the moment we assume that the returned attributes make sense for the * XPath specififed (i.e. we trust the caller). It's not fatal if they get * it wrong - the input function for the column type will raise an error * if the path result can't be converted into the correct binary * representation. */ attinmeta = TupleDescGetAttInMetadata(ret_tupdesc); /* Set return mode and allocate value space. */ rsinfo->returnMode = SFRM_Materialize; rsinfo->setDesc = ret_tupdesc; values = (char **) palloc(ret_tupdesc->natts * sizeof(char *)); xpaths = (xmlChar **) palloc(ret_tupdesc->natts * sizeof(xmlChar *)); /* * Split XPaths. xpathset is a writable CString. * * Note that we stop splitting once we've done all needed for tupdesc */ numpaths = 0; pos = xpathset; while (numpaths < (ret_tupdesc->natts - 1)) { xpaths[numpaths++] = (xmlChar *) pos; pos = strstr(pos, pathsep); if (pos != NULL) { *pos = '\0'; pos++; } else break; } /* Now build query */ initStringInfo(&query_buf); /* Build initial sql statement */ appendStringInfo(&query_buf, "SELECT %s, %s FROM %s WHERE %s", pkeyfield, xmlfield, relname, condition); if ((ret = SPI_connect()) < 0) elog(ERROR, "xpath_table: SPI_connect returned %d", ret); if ((ret = SPI_exec(query_buf.data, 0)) != SPI_OK_SELECT) elog(ERROR, "xpath_table: SPI execution failed for query %s", query_buf.data); proc = SPI_processed; /* elog(DEBUG1,"xpath_table: SPI returned %d rows",proc); */ tuptable = SPI_tuptable; spi_tupdesc = tuptable->tupdesc; /* Switch out of SPI context */ MemoryContextSwitchTo(oldcontext); /* * Check that SPI returned correct result. If you put a comma into one of * the function parameters, this will catch it when the SPI query returns * e.g. 3 columns. */ if (spi_tupdesc->natts != 2) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("expression returning multiple columns is not valid in parameter list"), errdetail("Expected two columns in SPI result, got %d.", spi_tupdesc->natts))); } /* * Setup the parser. This should happen after we are done evaluating the * query, in case it calls functions that set up libxml differently. */ xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); PG_TRY(); { /* For each row i.e. document returned from SPI */ for (i = 0; i < proc; i++) { char *pkey; char *xmldoc; xmlXPathContextPtr ctxt; xmlXPathObjectPtr res; xmlChar *resstr; xmlXPathCompExprPtr comppath; /* Extract the row data as C Strings */ spi_tuple = tuptable->vals[i]; pkey = SPI_getvalue(spi_tuple, spi_tupdesc, 1); xmldoc = SPI_getvalue(spi_tuple, spi_tupdesc, 2); /* * Clear the values array, so that not-well-formed documents * return NULL in all columns. Note that this also means that * spare columns will be NULL. */ for (j = 0; j < ret_tupdesc->natts; j++) values[j] = NULL; /* Insert primary key */ values[0] = pkey; /* Parse the document */ if (xmldoc) doctree = xmlParseMemory(xmldoc, strlen(xmldoc)); else /* treat NULL as not well-formed */ doctree = NULL; if (doctree == NULL) { /* not well-formed, so output all-NULL tuple */ ret_tuple = BuildTupleFromCStrings(attinmeta, values); tuplestore_puttuple(tupstore, ret_tuple); heap_freetuple(ret_tuple); } else { /* New loop here - we have to deal with nodeset results */ rownr = 0; do { /* Now evaluate the set of xpaths. */ had_values = false; for (j = 0; j < numpaths; j++) { ctxt = xmlXPathNewContext(doctree); ctxt->node = xmlDocGetRootElement(doctree); /* compile the path */ comppath = xmlXPathCompile(xpaths[j]); if (comppath == NULL) xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, "XPath Syntax Error"); /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); xmlXPathFreeCompExpr(comppath); if (res != NULL) { switch (res->type) { case XPATH_NODESET: /* We see if this nodeset has enough nodes */ if (res->nodesetval != NULL && rownr < res->nodesetval->nodeNr) { resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]); had_values = true; } else resstr = NULL; break; case XPATH_STRING: resstr = xmlStrdup(res->stringval); break; default: elog(NOTICE, "unsupported XQuery result: %d", res->type); resstr = xmlStrdup((const xmlChar *) "<unsupported/>"); } /* * Insert this into the appropriate column in the * result tuple. */ values[j + 1] = (char *) resstr; } xmlXPathFreeContext(ctxt); } /* Now add the tuple to the output, if there is one. */ if (had_values) { ret_tuple = BuildTupleFromCStrings(attinmeta, values); tuplestore_puttuple(tupstore, ret_tuple); heap_freetuple(ret_tuple); } rownr++; } while (had_values); } if (doctree != NULL) xmlFreeDoc(doctree); doctree = NULL; if (pkey) pfree(pkey); if (xmldoc) pfree(xmldoc); } } PG_CATCH(); { if (doctree != NULL) xmlFreeDoc(doctree); pg_xml_done(xmlerrcxt, true); PG_RE_THROW(); } PG_END_TRY(); if (doctree != NULL) xmlFreeDoc(doctree); pg_xml_done(xmlerrcxt, false); tuplestore_donestoring(tupstore); SPI_finish(); rsinfo->setResult = tupstore; /* * SFRM_Materialize mode expects us to return a NULL Datum. The actual * tuples are in our tuplestore and passed back through rsinfo->setResult. * rsinfo->setDesc is set to the tuple description that we actually used * to build our tuples with, so the caller can verify we did what it was * expecting. */ return (Datum) 0; }
/** * xsltInitCtxtKey: * @ctxt: an XSLT transformation context * @doc: an XSLT document * @keyd: the key definition * * Computes the key tables this key and for the current input document. */ int xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr doc, xsltKeyDefPtr keyd) { int i; xmlNodeSetPtr nodelist = NULL, keylist; xmlXPathObjectPtr res = NULL; xmlChar *str, **list; xsltKeyTablePtr table; int oldPos, oldSize; xmlNodePtr oldInst; xmlNodePtr oldNode; xsltDocumentPtr oldDoc; xmlDocPtr oldXDoc; int oldNsNr; xmlNsPtr *oldNamespaces; doc->nbKeysComputed++; /* * Evaluate the nodelist */ oldXDoc= ctxt->xpathCtxt->doc; oldPos = ctxt->xpathCtxt->proximityPosition; oldSize = ctxt->xpathCtxt->contextSize; oldNsNr = ctxt->xpathCtxt->nsNr; oldNamespaces = ctxt->xpathCtxt->namespaces; oldInst = ctxt->inst; oldDoc = ctxt->document; oldNode = ctxt->node; if (keyd->comp == NULL) goto error; if (keyd->usecomp == NULL) goto error; ctxt->document = doc; ctxt->xpathCtxt->doc = doc->doc; ctxt->xpathCtxt->node = (xmlNodePtr) doc->doc; ctxt->node = (xmlNodePtr) doc->doc; /* TODO : clarify the use of namespaces in keys evaluation */ ctxt->xpathCtxt->namespaces = keyd->nsList; ctxt->xpathCtxt->nsNr = keyd->nsNr; ctxt->inst = keyd->inst; res = xmlXPathCompiledEval(keyd->comp, ctxt->xpathCtxt); ctxt->xpathCtxt->contextSize = oldSize; ctxt->xpathCtxt->proximityPosition = oldPos; ctxt->inst = oldInst; if (res != NULL) { if (res->type == XPATH_NODESET) { nodelist = res->nodesetval; #ifdef WITH_XSLT_DEBUG_KEYS if (nodelist != NULL) XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtKey: %s evaluates to %d nodes\n", keyd->match, nodelist->nodeNr)); #endif } else { #ifdef WITH_XSLT_DEBUG_KEYS XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtKey: %s is not a node set\n", keyd->match)); #endif goto error; } } else { #ifdef WITH_XSLT_DEBUG_KEYS XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsltInitCtxtKey: %s evaluation failed\n", keyd->match)); #endif ctxt->state = XSLT_STATE_STOPPED; goto error; } /* * for each node in the list evaluate the key and insert the node */ if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) goto error; /** * Multiple key definitions for the same name are allowed, so * we must check if the key is already present for this doc */ table = (xsltKeyTablePtr) doc->keys; while (table != NULL) { if (xmlStrEqual(table->name, keyd->name) && (((keyd->nameURI == NULL) && (table->nameURI == NULL)) || ((keyd->nameURI != NULL) && (table->nameURI != NULL) && (xmlStrEqual(table->nameURI, keyd->nameURI))))) break; table = table->next; } /** * If the key was not previously defined, create it now and * chain it to the list of keys for the doc */ if (table == NULL) { table = xsltNewKeyTable(keyd->name, keyd->nameURI); if (table == NULL) goto error; table->next = doc->keys; doc->keys = table; } for (i = 0;i < nodelist->nodeNr;i++) { if (IS_XSLT_REAL_NODE(nodelist->nodeTab[i])) { ctxt->node = nodelist->nodeTab[i]; list = xsltEvalXPathKeys(ctxt, keyd->usecomp, keyd); if (list != NULL) { int ix = 0; str = list[ix++]; while (str != NULL) { #ifdef WITH_XSLT_DEBUG_KEYS XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsl:key : node associated to(%s,%s)\n", keyd->name, str)); #endif keylist = xmlHashLookup(table->keys, str); if (keylist == NULL) { keylist = xmlXPathNodeSetCreate(nodelist->nodeTab[i]); xmlHashAddEntry(table->keys, str, keylist); } else { xmlXPathNodeSetAdd(keylist, nodelist->nodeTab[i]); } switch (nodelist->nodeTab[i]->type) { case XML_ELEMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: nodelist->nodeTab[i]->psvi = keyd; break; case XML_ATTRIBUTE_NODE: { xmlAttrPtr attr = (xmlAttrPtr) nodelist->nodeTab[i]; attr->psvi = keyd; break; } case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: { xmlDocPtr kdoc = (xmlDocPtr) nodelist->nodeTab[i]; kdoc->psvi = keyd; break; } default: break; } xmlFree(str); str = list[ix++]; } xmlFree(list); #ifdef WITH_XSLT_DEBUG_KEYS } else { XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "xsl:key : use %s failed to return strings\n", keyd->use)); #endif } } } error: ctxt->document = oldDoc; ctxt->xpathCtxt->doc = oldXDoc; ctxt->xpathCtxt->nsNr = oldNsNr; ctxt->xpathCtxt->namespaces = oldNamespaces; ctxt->node = oldNode; if (res != NULL) xmlXPathFreeObject(res); return(0); }