Browse code

xcap_server: ability to insert new nodes in xcap docs

- xpath cannot do it alone when the selected node is missing
- reported by Laura Testi - credits for testing and further patching

Daniel-Constantin Mierla authored on 08/09/2011 14:02:49
Showing 1 changed files
... ...
@@ -433,13 +433,18 @@ int xcaps_xpath_set(str *inbuf, str *xpaths, str *val, str *outbuf)
433 433
 	xmlNodePtr parent = NULL;
434 434
 	int size;
435 435
 	int i;
436
+	char *p;
436 437
 
437 438
 	doc = xmlParseMemory(inbuf->s, inbuf->len);
438 439
 	if(doc == NULL)
439 440
 		return -1;
440 441
 
441 442
 	if(val!=NULL)
443
+	{
442 444
 		newnode = xmlParseMemory(val->s, val->len);
445
+		if(newnode==NULL)
446
+			goto error;
447
+	}
443 448
 
444 449
 	outbuf->s   = NULL;
445 450
 	outbuf->len = 0;
... ...
@@ -459,15 +464,56 @@ int xcaps_xpath_set(str *inbuf, str *xpaths, str *val, str *outbuf)
459 459
 		LM_ERR("unable to evaluate xpath expression [%s]\n", xpaths->s);
460 460
 		goto error;
461 461
 	}
462
-    nodes = xpathObj->nodesetval;
463
-	if(nodes==NULL)
462
+	nodes = xpathObj->nodesetval;
463
+	if(nodes==NULL || nodes->nodeNr==0 || nodes->nodeTab == NULL)
464 464
 	{
465
+		/* no selection for xpath expression */
465 466
 		LM_DBG("no selection for xpath expression [%s]\n", xpaths->s);
466
-		goto done;
467
-	}
468
-	size = nodes->nodeNr;
469
-	if(val!=NULL)
470
-		value = (const xmlChar*)val->s;
467
+		if(val==NULL)
468
+			goto done;
469
+		/* could be an insert - locate the selection of parent node */
470
+		p = strrchr(xpaths->s, '/');
471
+		if(p==NULL)
472
+			goto done;
473
+		/* evaluate xpath expression for parrent node */
474
+		*p = 0;
475
+		xpathObj = xmlXPathEvalExpression(
476
+					(const xmlChar*)xpaths->s, xpathCtx);
477
+		if(xpathObj == NULL)
478
+		{
479
+			LM_DBG("unable to evaluate xpath parent expression [%s]\n",
480
+					xpaths->s);
481
+			*p = '/';
482
+			goto done;
483
+		}
484
+		*p = '/';
485
+		nodes = xpathObj->nodesetval;
486
+		if(nodes==NULL || nodes->nodeNr==0 || nodes->nodeTab == NULL)
487
+		{
488
+			LM_DBG("no selection for xpath parent expression [%s]\n",
489
+					xpaths->s);
490
+			goto done;
491
+		}
492
+		/* add the new content as child to first selected element node */
493
+		if(nodes->nodeTab[0]==NULL)
494
+		{
495
+			LM_DBG("selection for xpath parent expression has first child"
496
+					" NULL [%s]\n", xpaths->s);
497
+			goto done;
498
+		}
499
+		if(nodes->nodeTab[0]->type==XML_ELEMENT_NODE)
500
+		{
501
+			xmlAddChild(nodes->nodeTab[0], xmlCopyNode(newnode->children, 1));
502
+		} else {
503
+			LM_DBG("selection for xpath parent expression is not element"
504
+					" node [%s]\n", xpaths->s);
505
+			goto done;
506
+		}
507
+	} else {
508
+		/* selection for xpath expression */
509
+		size = nodes->nodeNr;
510
+		if(val!=NULL)
511
+			value = (const xmlChar*)val->s;
471 512
     
472 513
 	/*
473 514
 	 * NOTE: the nodes are processed in reverse order, i.e. reverse document
... ...
@@ -477,22 +523,22 @@ int xcaps_xpath_set(str *inbuf, str *xpaths, str *val, str *outbuf)
477 477
 	 *       they get removed. Mixing XPath and modifications on a tree must be
478 478
 	 *       done carefully !
479 479
 	 */
480
-	for(i = size - 1; i >= 0; i--) {
481
-		if(nodes->nodeTab[i]==NULL)
482
-			continue;
483
-	
484
-		if(nodes->nodeTab[i]->type==XML_ELEMENT_NODE)
485
-		{
486
-			parent = nodes->nodeTab[i]->parent;
487
-			xmlUnlinkNode(nodes->nodeTab[i]);
488
-			if(val!=NULL && newnode!=NULL)
489
-				xmlAddChild(parent, xmlCopyNode(newnode->children, 1));
490
-		} else {
491
-			if(val!=NULL)
492
-				xmlNodeSetContent(nodes->nodeTab[i], value);
493
-			else
494
-				xmlNodeSetContent(nodes->nodeTab[i], (const xmlChar*)"");
495
-		}
480
+		for(i = size - 1; i >= 0; i--) {
481
+			if(nodes->nodeTab[i]==NULL)
482
+				continue;
483
+
484
+			if(nodes->nodeTab[i]->type==XML_ELEMENT_NODE)
485
+			{
486
+				parent = nodes->nodeTab[i]->parent;
487
+				xmlUnlinkNode(nodes->nodeTab[i]);
488
+				if(val!=NULL && newnode!=NULL)
489
+					xmlAddChild(parent, xmlCopyNode(newnode->children, 1));
490
+			} else {
491
+				if(val!=NULL)
492
+					xmlNodeSetContent(nodes->nodeTab[i], value);
493
+				else
494
+					xmlNodeSetContent(nodes->nodeTab[i], (const xmlChar*)"");
495
+			}
496 496
 		/*
497 497
 		 * All the elements returned by an XPath query are pointers to
498 498
 		 * elements from the tree *except* namespace nodes where the XPath
... ...
@@ -510,8 +556,9 @@ int xcaps_xpath_set(str *inbuf, str *xpaths, str *val, str *outbuf)
510 510
 		 *   - remove the reference to the modified nodes from the node set
511 511
 		 *     as they are processed, if they are not namespace nodes.
512 512
 		 */
513
-		if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL)
514
-			nodes->nodeTab[i] = NULL;
513
+			if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL)
514
+				nodes->nodeTab[i] = NULL;
515
+		}
515 516
 	}
516 517
 
517 518
 	xmlDocDumpMemory(doc, &xmem, &size);