Пример #1
0
/**
 *  Loop through array of operations and perform them
 */
static void
edProcess(xmlDocPtr doc, const XmlEdAction* ops, int ops_count)
{
    int k;
    xmlXPathContextPtr ctxt = xmlXPathNewContext(doc);
    /* NOTE: later registrations override earlier ones */
    registerXstarNs(ctxt);

    /* variables */
    previous_insertion = xmlXPathNodeSetCreate(NULL);
    registerXstarVariable(ctxt, "prev",
        xmlXPathWrapNodeSet(previous_insertion));
    xmlDeregisterNodeDefault(&removeNodeFromPrev);

#if HAVE_EXSLT_XPATH_REGISTER
    /* register extension functions */
    exsltDateXpathCtxtRegister(ctxt, BAD_CAST "date");
    exsltMathXpathCtxtRegister(ctxt, BAD_CAST "math");
    exsltSetsXpathCtxtRegister(ctxt, BAD_CAST "set");
    exsltStrXpathCtxtRegister(ctxt, BAD_CAST "str");
#endif
    /* namespaces from doc */
    extract_ns_defs(doc, ctxt);
    /* namespaces from command line */
    nsarr_xpath_register(ctxt);

    for (k = 0; k < ops_count; k++)
    {
        xmlXPathObjectPtr res;
        xmlNodeSetPtr nodes;

        /* NOTE: to make relative paths match as if from "/", set context to
           document; setting to root would match as if from "/node()/" */
        ctxt->node = (xmlNodePtr) doc;

        if (ops[k].op == XML_ED_VAR) {
            res = xmlXPathEvalExpression(BAD_CAST ops[k].arg2, ctxt);
            xmlXPathRegisterVariable(ctxt, BAD_CAST ops[k].arg1, res);
            continue;
        }

        res = xmlXPathEvalExpression(BAD_CAST ops[k].arg1, ctxt);
        if (!res || res->type != XPATH_NODESET || !res->nodesetval) continue;
        nodes = res->nodesetval;

        switch (ops[k].op)
        {
            case XML_ED_DELETE:
                edDelete(doc, nodes);
                break;
            case XML_ED_MOVE: {
                xmlXPathObjectPtr res_to;
                ctxt->node = (xmlNodePtr) doc;
                res_to = xmlXPathEvalExpression(BAD_CAST ops[k].arg2, ctxt);
                if (!res_to
                    || res_to->type != XPATH_NODESET
                    || res_to->nodesetval->nodeNr != 1) {
                    fprintf(stderr, "move destination is not a single node\n");
                    continue;
                }
                edMove(doc, nodes, res_to->nodesetval->nodeTab[0]);
                xmlXPathFreeObject(res_to);
                break;
            }
            case XML_ED_UPDATE:
                edUpdate(doc, nodes, ops[k].arg2, ops[k].type, ctxt);
                break;
            case XML_ED_RENAME:
                edRename(doc, nodes, ops[k].arg2, ops[k].type);
                break;
            case XML_ED_INSERT:
                edInsert(doc, nodes, ops[k].arg2, ops[k].arg3, ops[k].type, -1);
                break;
            case XML_ED_APPEND:
                edInsert(doc, nodes, ops[k].arg2, ops[k].arg3, ops[k].type, 1);
                break;
            case XML_ED_SUBNODE:
                edInsert(doc, nodes, ops[k].arg2, ops[k].arg3, ops[k].type, 0);
                break;
            default:
                break;
        }
        xmlXPathFreeObject(res);
    }
    /* NOTE: free()ing ctxt also free()s previous_insertion */
    previous_insertion = NULL;
    xmlDeregisterNodeDefault(NULL);

    xmlXPathFreeContext(ctxt);
}
Пример #2
0
/**
 * xsltKeyFunction:
 * @ctxt:  the XPath Parser context
 * @nargs:  the number of arguments
 *
 * Implement the key() XSLT function
 *   node-set key(string, object)
 */
void
xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
    xmlXPathObjectPtr obj1, obj2;

    if (nargs != 2) {
	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
		"key() : expects two arguments\n");
	ctxt->error = XPATH_INVALID_ARITY;
	return;
    }

    /*
    * Get the key's value.
    */
    obj2 = valuePop(ctxt);
    xmlXPathStringFunction(ctxt, 1);
    if ((obj2 == NULL) ||
	(ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
	xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
	    "key() : invalid arg expecting a string\n");
	ctxt->error = XPATH_INVALID_TYPE;
	xmlXPathFreeObject(obj2);

	return;
    }
    /*
    * Get the key's name.
    */
    obj1 = valuePop(ctxt);

    if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) {
	int i;
	xmlXPathObjectPtr newobj, ret;

	ret = xmlXPathNewNodeSet(NULL);

	if (obj2->nodesetval != NULL) {
	    for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
		valuePush(ctxt, xmlXPathObjectCopy(obj1));
		valuePush(ctxt,
			  xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
		xmlXPathStringFunction(ctxt, 1);
		xsltKeyFunction(ctxt, 2);
		newobj = valuePop(ctxt);
		ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
						       newobj->nodesetval);
		xmlXPathFreeObject(newobj);
	    }
	}
	valuePush(ctxt, ret);
    } else {
	xmlNodeSetPtr nodelist = NULL;
	xmlChar *key = NULL, *value;
	const xmlChar *keyURI;
	xsltTransformContextPtr tctxt;
	xmlChar *qname, *prefix;
	xmlXPathContextPtr xpctxt = ctxt->context;
	xmlNodePtr tmpNode = NULL;
	xsltDocumentPtr oldDocInfo;

	tctxt = xsltXPathGetTransformContext(ctxt);

	oldDocInfo = tctxt->document;

	if (xpctxt->node == NULL) {
	    xsltTransformError(tctxt, NULL, tctxt->inst,
		"Internal error in xsltKeyFunction(): "
		"The context node is not set on the XPath context.\n");
	    tctxt->state = XSLT_STATE_STOPPED;
	    goto error;
	}
	/*
	 * Get the associated namespace URI if qualified name
	 */
	qname = obj1->stringval;
	key = xmlSplitQName2(qname, &prefix);
	if (key == NULL) {
	    key = xmlStrdup(obj1->stringval);
	    keyURI = NULL;
	    if (prefix != NULL)
		xmlFree(prefix);
	} else {
	    if (prefix != NULL) {
		keyURI = xmlXPathNsLookup(xpctxt, prefix);
		if (keyURI == NULL) {
		    xsltTransformError(tctxt, NULL, tctxt->inst,
			"key() : prefix %s is not bound\n", prefix);
		    /*
		    * TODO: Shouldn't we stop here?
		    */
		}
		xmlFree(prefix);
	    } else {
		keyURI = NULL;
	    }
	}

	/*
	 * Force conversion of first arg to string
	 */
	valuePush(ctxt, obj2);
	xmlXPathStringFunction(ctxt, 1);
	if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
	    xsltTransformError(tctxt, NULL, tctxt->inst,
		"key() : invalid arg expecting a string\n");
	    ctxt->error = XPATH_INVALID_TYPE;
	    goto error;
	}
	obj2 = valuePop(ctxt);
	value = obj2->stringval;

	/*
	* We need to ensure that ctxt->document is available for
	* xsltGetKey().
	* First find the relevant doc, which is the context node's
	* owner doc; using context->doc is not safe, since
	* the doc could have been acquired via the document() function,
	* or the doc might be a Result Tree Fragment.
	* FUTURE INFO: In XSLT 2.0 the key() function takes an additional
	* argument indicating the doc to use.
	*/
	if (xpctxt->node->type == XML_NAMESPACE_DECL) {
	    /*
	    * REVISIT: This is a libxml hack! Check xpath.c for details.
	    * The XPath module sets the owner element of a ns-node on
	    * the ns->next field.
	    */
	    if ((((xmlNsPtr) xpctxt->node)->next != NULL) &&
		(((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE))
	    {
		tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next;
	    }
	} else
	    tmpNode = xpctxt->node;

	if ((tmpNode == NULL) || (tmpNode->doc == NULL)) {
	    xsltTransformError(tctxt, NULL, tctxt->inst,
		"Internal error in xsltKeyFunction(): "
		"Couldn't get the doc of the XPath context node.\n");
	    goto error;
	}

	if ((tctxt->document == NULL) ||
	    (tctxt->document->doc != tmpNode->doc))
	{
	    if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) {
		/*
		* This is a Result Tree Fragment.
		*/
		if (tmpNode->doc->_private == NULL) {
		    tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc);
		    if (tmpNode->doc->_private == NULL)
			goto error;
		}
		tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private;
	    } else {
		/*
		* May be the initial source doc or a doc acquired via the
		* document() function.
		*/
		tctxt->document = xsltFindDocument(tctxt, tmpNode->doc);
	    }
	    if (tctxt->document == NULL) {
		xsltTransformError(tctxt, NULL, tctxt->inst,
		    "Internal error in xsltKeyFunction(): "
		    "Could not get the document info of a context doc.\n");
		tctxt->state = XSLT_STATE_STOPPED;
		goto error;
	    }
	}
	/*
	* Get/compute the key value.
	*/
	nodelist = xsltGetKey(tctxt, key, keyURI, value);

error:
	tctxt->document = oldDocInfo;
	valuePush(ctxt, xmlXPathWrapNodeSet(
	    xmlXPathNodeSetMerge(NULL, nodelist)));
	if (key != NULL)
	    xmlFree(key);
    }

    if (obj1 != NULL)
	xmlXPathFreeObject(obj1);
    if (obj2 != NULL)
	xmlXPathFreeObject(obj2);
}
Пример #3
0
/**
 * xsltKeyFunction:
 * @ctxt:  the XPath Parser context
 * @nargs:  the number of arguments
 *
 * Implement the key() XSLT function
 *   node-set key(string, object)
 */
void
xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){
    xmlNodeSetPtr nodelist;
    xmlXPathObjectPtr obj1, obj2;
    xmlChar *key = NULL, *value;
    const xmlChar *keyURI;
    xsltTransformContextPtr tctxt;

    if (nargs != 2) {
	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
        xsltGenericError(xsltGenericErrorContext,
		"key() : expects two arguments\n");
	ctxt->error = XPATH_INVALID_ARITY;
	return;
    }

    obj2 = valuePop(ctxt);
    if ((obj2 == NULL) ||
	(ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
	xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL);
	xsltGenericError(xsltGenericErrorContext,
	    "key() : invalid arg expecting a string\n");
	ctxt->error = XPATH_INVALID_TYPE;
	xmlXPathFreeObject(obj2);

	return;
    }
    obj1 = valuePop(ctxt);

    if (obj2->type == XPATH_NODESET) {
	int i;
	xmlXPathObjectPtr newobj, ret;

	ret = xmlXPathNewNodeSet(NULL);

	if (obj2->nodesetval != NULL) {
	    for (i = 0; i < obj2->nodesetval->nodeNr; i++) {
		valuePush(ctxt, xmlXPathObjectCopy(obj1));
		valuePush(ctxt,
			  xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i]));
		xmlXPathStringFunction(ctxt, 1);
		xsltKeyFunction(ctxt, 2);
		newobj = valuePop(ctxt);
		ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
						       newobj->nodesetval);
		xmlXPathFreeObject(newobj);
	    }
	}
	valuePush(ctxt, ret);
    } else {
	xmlChar *qname, *prefix;

	/*
	 * Get the associated namespace URI if qualified name
	 */
	qname = obj1->stringval;
	key = xmlSplitQName2(qname, &prefix);
	if (key == NULL) {
	    key = xmlStrdup(obj1->stringval);
	    keyURI = NULL;
	    if (prefix != NULL)
		xmlFree(prefix);
	} else {
	    if (prefix != NULL) {
		keyURI = xmlXPathNsLookup(ctxt->context, prefix);
		if (keyURI == NULL) {
		    xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
					  NULL, NULL);
		    xsltGenericError(xsltGenericErrorContext,
			"key() : prefix %s is not bound\n", prefix);
		}
		xmlFree(prefix);
	    } else {
		keyURI = NULL;
	    }
	}

	/*
	 * Force conversion of first arg to string
	 */
	valuePush(ctxt, obj2);
	xmlXPathStringFunction(ctxt, 1);
	if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
	    xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt),
				  NULL, NULL);
	    xsltGenericError(xsltGenericErrorContext,
		"key() : invalid arg expecting a string\n");
	    ctxt->error = XPATH_INVALID_TYPE;
	    xmlXPathFreeObject(obj1);

	    return;
	}
	obj2 = valuePop(ctxt);
	value = obj2->stringval;

	tctxt = xsltXPathGetTransformContext(ctxt);

	nodelist = xsltGetKey(tctxt, key, keyURI, value);
	valuePush(ctxt, xmlXPathWrapNodeSet(
		        xmlXPathNodeSetMerge(NULL, nodelist)));
    }


    if (obj1 != NULL)
	xmlXPathFreeObject(obj1);
    if (obj2 != NULL)
	xmlXPathFreeObject(obj2);
    if (key != NULL)
	xmlFree(key);
}