OLD | NEW |
1 /* | 1 /* |
2 * templates.c: Implementation of the template processing | 2 * templates.c: Implementation of the template processing |
3 * | 3 * |
4 * Reference: | 4 * Reference: |
5 * http://www.w3.org/TR/1999/REC-xslt-19991116 | 5 * http://www.w3.org/TR/1999/REC-xslt-19991116 |
6 * | 6 * |
7 * See Copyright for the status of this software. | 7 * See Copyright for the status of this software. |
8 * | 8 * |
9 * daniel@veillard.com | 9 * daniel@veillard.com |
10 */ | 10 */ |
(...skipping 22 matching lines...) Expand all Loading... |
33 | 33 |
34 #ifdef WITH_XSLT_DEBUG | 34 #ifdef WITH_XSLT_DEBUG |
35 #define WITH_XSLT_DEBUG_TEMPLATES | 35 #define WITH_XSLT_DEBUG_TEMPLATES |
36 #endif | 36 #endif |
37 | 37 |
38 /************************************************************************ | 38 /************************************************************************ |
39 * * | 39 * * |
40 * Module interfaces * | 40 * Module interfaces * |
41 * * | 41 * * |
42 ************************************************************************/ | 42 ************************************************************************/ |
43 | 43 |
44 /** | 44 /** |
45 * xsltEvalXPathPredicate: | 45 * xsltEvalXPathPredicate: |
46 * @ctxt: the XSLT transformation context | 46 * @ctxt: the XSLT transformation context |
47 * @comp: the XPath compiled expression | 47 * @comp: the XPath compiled expression |
48 * @nsList: the namespaces in scope | 48 * @nsList: the namespaces in scope |
49 * @nsNr: the number of namespaces in scope | 49 * @nsNr: the number of namespaces in scope |
50 * | 50 * |
51 * Process the expression using XPath and evaluate the result as | 51 * Process the expression using XPath and evaluate the result as |
52 * an XPath predicate | 52 * an XPath predicate |
53 * | 53 * |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 * free the result. | 192 * free the result. |
193 */ | 193 */ |
194 xmlChar * | 194 xmlChar * |
195 xsltEvalTemplateString(xsltTransformContextPtr ctxt, | 195 xsltEvalTemplateString(xsltTransformContextPtr ctxt, |
196 xmlNodePtr contextNode, | 196 xmlNodePtr contextNode, |
197 xmlNodePtr inst) | 197 xmlNodePtr inst) |
198 { | 198 { |
199 xmlNodePtr oldInsert, insert = NULL; | 199 xmlNodePtr oldInsert, insert = NULL; |
200 xmlChar *ret; | 200 xmlChar *ret; |
201 | 201 |
202 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) | 202 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) || |
| 203 (inst->type != XML_ELEMENT_NODE)) |
203 return(NULL); | 204 return(NULL); |
204 | 205 |
205 if (inst->children == NULL) | 206 if (inst->children == NULL) |
206 return(NULL); | 207 return(NULL); |
207 | 208 |
208 /* | 209 /* |
209 * This creates a temporary element-node to add the resulting | 210 * This creates a temporary element-node to add the resulting |
210 * text content to. | 211 * text content to. |
211 * OPTIMIZE TODO: Keep such an element-node in the transformation | 212 * OPTIMIZE TODO: Keep such an element-node in the transformation |
212 * context to avoid creating it every time. | 213 * context to avoid creating it every time. |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 if (*(cur+1) == '{') { /* escaped '{' */ | 274 if (*(cur+1) == '{') { /* escaped '{' */ |
274 cur++; | 275 cur++; |
275 ret = xmlStrncat(ret, str, cur - str); | 276 ret = xmlStrncat(ret, str, cur - str); |
276 cur++; | 277 cur++; |
277 str = cur; | 278 str = cur; |
278 continue; | 279 continue; |
279 } | 280 } |
280 ret = xmlStrncat(ret, str, cur - str); | 281 ret = xmlStrncat(ret, str, cur - str); |
281 str = cur; | 282 str = cur; |
282 cur++; | 283 cur++; |
283 » while ((*cur != 0) && (*cur != '}')) cur++; | 284 » while ((*cur != 0) && (*cur != '}')) { |
| 285 » » /* Need to check for literal (bug539741) */ |
| 286 » » if ((*cur == '\'') || (*cur == '"')) { |
| 287 » » char delim = *(cur++); |
| 288 » » while ((*cur != 0) && (*cur != delim)) |
| 289 » » » cur++; |
| 290 » » if (*cur != 0) |
| 291 » » » cur++;» /* skip the ending delimiter */ |
| 292 » » } else |
| 293 » » cur++; |
| 294 } |
284 if (*cur == 0) { | 295 if (*cur == 0) { |
285 xsltTransformError(ctxt, NULL, inst, | 296 xsltTransformError(ctxt, NULL, inst, |
286 "xsltAttrTemplateValueProcessNode: unmatched '{'\n"); | 297 "xsltAttrTemplateValueProcessNode: unmatched '{'\n"); |
287 ret = xmlStrncat(ret, str, cur - str); | 298 ret = xmlStrncat(ret, str, cur - str); |
288 return(ret); | 299 return(ret); |
289 } | 300 } |
290 str++; | 301 str++; |
291 expr = xmlStrndup(str, cur - str); | 302 expr = xmlStrndup(str, cur - str); |
292 if (expr == NULL) | 303 if (expr == NULL) |
293 return(ret); | 304 return(ret); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 * Returns the computed string value or NULL, must be deallocated by the | 385 * Returns the computed string value or NULL, must be deallocated by the |
375 * caller. | 386 * caller. |
376 */ | 387 */ |
377 xmlChar * | 388 xmlChar * |
378 xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst, | 389 xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst, |
379 const xmlChar *name, const xmlChar *ns) | 390 const xmlChar *name, const xmlChar *ns) |
380 { | 391 { |
381 xmlChar *ret; | 392 xmlChar *ret; |
382 xmlChar *expr; | 393 xmlChar *expr; |
383 | 394 |
384 if ((ctxt == NULL) || (inst == NULL) || (name == NULL)) | 395 if ((ctxt == NULL) || (inst == NULL) || (name == NULL) || |
| 396 (inst->type != XML_ELEMENT_NODE)) |
385 return(NULL); | 397 return(NULL); |
386 | 398 |
387 expr = xsltGetNsProp(inst, name, ns); | 399 expr = xsltGetNsProp(inst, name, ns); |
388 if (expr == NULL) | 400 if (expr == NULL) |
389 return(NULL); | 401 return(NULL); |
390 | 402 |
391 /* | 403 /* |
392 * TODO: though now {} is detected ahead, it would still be good to | 404 * TODO: though now {} is detected ahead, it would still be good to |
393 * optimize both functions to keep the splitted value if the | 405 * optimize both functions to keep the splitted value if the |
394 * attribute content and the XPath precompiled expressions around | 406 * attribute content and the XPath precompiled expressions around |
(...skipping 23 matching lines...) Expand all Loading... |
418 * | 430 * |
419 * Returns the static string value or NULL, must be deallocated by the | 431 * Returns the static string value or NULL, must be deallocated by the |
420 * caller. | 432 * caller. |
421 */ | 433 */ |
422 const xmlChar * | 434 const xmlChar * |
423 xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst, | 435 xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst, |
424 const xmlChar *name, const xmlChar *ns, int *found) { | 436 const xmlChar *name, const xmlChar *ns, int *found) { |
425 const xmlChar *ret; | 437 const xmlChar *ret; |
426 xmlChar *expr; | 438 xmlChar *expr; |
427 | 439 |
428 if ((style == NULL) || (inst == NULL) || (name == NULL)) | 440 if ((style == NULL) || (inst == NULL) || (name == NULL) || |
| 441 (inst->type != XML_ELEMENT_NODE)) |
429 return(NULL); | 442 return(NULL); |
430 | 443 |
431 expr = xsltGetNsProp(inst, name, ns); | 444 expr = xsltGetNsProp(inst, name, ns); |
432 if (expr == NULL) { | 445 if (expr == NULL) { |
433 *found = 0; | 446 *found = 0; |
434 return(NULL); | 447 return(NULL); |
435 } | 448 } |
436 *found = 1; | 449 *found = 1; |
437 | 450 |
438 ret = xmlStrchr(expr, '{'); | 451 ret = xmlStrchr(expr, '{'); |
439 if (ret != NULL) { | 452 if (ret != NULL) { |
440 xmlFree(expr); | 453 xmlFree(expr); |
441 return(NULL); | 454 return(NULL); |
442 } | 455 } |
443 ret = xmlDictLookup(style->dict, expr, -1); | 456 ret = xmlDictLookup(style->dict, expr, -1); |
444 xmlFree(expr); | 457 xmlFree(expr); |
445 return(ret); | 458 return(ret); |
446 } | 459 } |
447 | 460 |
448 /** | 461 /** |
449 * xsltAttrTemplateProcess: | 462 * xsltAttrTemplateProcess: |
450 * @ctxt: the XSLT transformation context | 463 * @ctxt: the XSLT transformation context |
451 * @target: the element where the attribute will be grafted | 464 * @target: the element where the attribute will be grafted |
452 * @attr: the attribute node of a literal result element | 465 * @attr: the attribute node of a literal result element |
453 * | 466 * |
454 * Process one attribute of a Literal Result Element (in the stylesheet). | 467 * Process one attribute of a Literal Result Element (in the stylesheet). |
455 * Evaluates Attribute Value Templates and copies the attribute over to | 468 * Evaluates Attribute Value Templates and copies the attribute over to |
456 * the result element. | 469 * the result element. |
457 * This does *not* process attribute sets (xsl:use-attribute-set). | 470 * This does *not* process attribute sets (xsl:use-attribute-set). |
458 * | 471 * |
459 * | 472 * |
460 * Returns the generated attribute node. | 473 * Returns the generated attribute node. |
461 */ | 474 */ |
462 xmlAttrPtr | 475 xmlAttrPtr |
463 xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, | 476 xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, |
464 xmlAttrPtr attr) | 477 xmlAttrPtr attr) |
465 { | 478 { |
466 const xmlChar *value; | 479 const xmlChar *value; |
467 xmlAttrPtr ret; | 480 xmlAttrPtr ret; |
468 | 481 |
469 if ((ctxt == NULL) || (attr == NULL) || (target == NULL)) | 482 if ((ctxt == NULL) || (attr == NULL) || (target == NULL) || |
| 483 (target->type != XML_ELEMENT_NODE)) |
470 return(NULL); | 484 return(NULL); |
471 | 485 |
472 if (attr->type != XML_ATTRIBUTE_NODE) | 486 if (attr->type != XML_ATTRIBUTE_NODE) |
473 return(NULL); | 487 return(NULL); |
474 | 488 |
475 /* | 489 /* |
476 * Skip all XSLT attributes. | 490 * Skip all XSLT attributes. |
477 */ | 491 */ |
478 #ifdef XSLT_REFACTORED | 492 #ifdef XSLT_REFACTORED |
479 if (attr->psvi == xsltXSLTAttrMarker) | 493 if (attr->psvi == xsltXSLTAttrMarker) |
480 return(NULL); | 494 return(NULL); |
481 #else | 495 #else |
482 if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) | 496 if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) |
483 return(NULL); | 497 return(NULL); |
484 #endif | 498 #endif |
485 /* | 499 /* |
486 * Get the value. | 500 * Get the value. |
487 */ | 501 */ |
488 if (attr->children != NULL) { | 502 if (attr->children != NULL) { |
(...skipping 16 matching lines...) Expand all Loading... |
505 ret = target->properties; | 519 ret = target->properties; |
506 while (ret != NULL) { | 520 while (ret != NULL) { |
507 if (((attr->ns != NULL) == (ret->ns != NULL)) && | 521 if (((attr->ns != NULL) == (ret->ns != NULL)) && |
508 xmlStrEqual(ret->name, attr->name) && | 522 xmlStrEqual(ret->name, attr->name) && |
509 ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href))) | 523 ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href))) |
510 { | 524 { |
511 break; | 525 break; |
512 } | 526 } |
513 ret = ret->next; | 527 ret = ret->next; |
514 } | 528 } |
515 if (ret != NULL) {» | 529 if (ret != NULL) { |
516 /* free the existing value */ | 530 /* free the existing value */ |
517 xmlFreeNodeList(ret->children); | 531 xmlFreeNodeList(ret->children); |
518 ret->children = ret->last = NULL; | 532 ret->children = ret->last = NULL; |
519 /* | 533 /* |
520 * Adjust ns-prefix if needed. | 534 * Adjust ns-prefix if needed. |
521 */ | 535 */ |
522 if ((ret->ns != NULL) && | 536 if ((ret->ns != NULL) && |
523 (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix))) | 537 (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix))) |
524 { | 538 { |
525 ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target); | 539 ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target); |
526 } | 540 } |
527 } else { | 541 } else { |
528 /* create a new attribute */ | 542 /* create a new attribute */ |
529 if (attr->ns != NULL) | 543 if (attr->ns != NULL) |
530 ret = xmlNewNsProp(target, | 544 ret = xmlNewNsProp(target, |
531 xsltGetNamespace(ctxt, attr->parent, attr->ns, target), | 545 xsltGetNamespace(ctxt, attr->parent, attr->ns, target), |
532 attr->name, NULL); | 546 attr->name, NULL); |
533 else | 547 else |
534 » ret = xmlNewNsProp(target, NULL, attr->name, NULL);» | 548 » ret = xmlNewNsProp(target, NULL, attr->name, NULL); |
535 } | 549 } |
536 /* | 550 /* |
537 * Set the value. | 551 * Set the value. |
538 */ | 552 */ |
539 if (ret != NULL) { | 553 if (ret != NULL) { |
540 xmlNodePtr text; | 554 xmlNodePtr text; |
541 | 555 |
542 text = xmlNewText(NULL); | 556 text = xmlNewText(NULL); |
543 if (text != NULL) { | 557 if (text != NULL) { |
544 ret->last = ret->children = text; | 558 ret->last = ret->children = text; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
576 (target->doc->dict == ctxt->dict) && | 590 (target->doc->dict == ctxt->dict) && |
577 xmlDictOwns(ctxt->dict, value)) { | 591 xmlDictOwns(ctxt->dict, value)) { |
578 text->content = (xmlChar *) value; | 592 text->content = (xmlChar *) value; |
579 } else { | 593 } else { |
580 text->content = xmlStrdup(value); | 594 text->content = xmlStrdup(value); |
581 } | 595 } |
582 } | 596 } |
583 } else { | 597 } else { |
584 if (attr->ns) { | 598 if (attr->ns) { |
585 xsltTransformError(ctxt, NULL, attr->parent, | 599 xsltTransformError(ctxt, NULL, attr->parent, |
586 » » "Internal error: Failed to create attribute '{%s}%s'.\n", | 600 » » "Internal error: Failed to create attribute '{%s}%s'.\n", |
587 attr->ns->href, attr->name); | 601 attr->ns->href, attr->name); |
588 } else { | 602 } else { |
589 xsltTransformError(ctxt, NULL, attr->parent, | 603 xsltTransformError(ctxt, NULL, attr->parent, |
590 » » "Internal error: Failed to create attribute '%s'.\n", | 604 » » "Internal error: Failed to create attribute '%s'.\n", |
591 attr->name); | 605 attr->name); |
592 } | 606 } |
593 } | 607 } |
594 return(ret); | 608 return(ret); |
595 } | 609 } |
596 | 610 |
597 | 611 |
598 /** | 612 /** |
599 * xsltAttrListTemplateProcess: | 613 * xsltAttrListTemplateProcess: |
600 * @ctxt: the XSLT transformation context | 614 * @ctxt: the XSLT transformation context |
601 * @target: the element where the attributes will be grafted | 615 * @target: the element where the attributes will be grafted |
602 * @attrs: the first attribute | 616 * @attrs: the first attribute |
603 * | 617 * |
604 * Processes all attributes of a Literal Result Element. | 618 * Processes all attributes of a Literal Result Element. |
605 * Attribute references are applied via xsl:use-attribute-set | 619 * Attribute references are applied via xsl:use-attribute-set |
606 * attributes. | 620 * attributes. |
607 * Copies all non XSLT-attributes over to the @target element | 621 * Copies all non XSLT-attributes over to the @target element |
608 * and evaluates Attribute Value Templates. | 622 * and evaluates Attribute Value Templates. |
609 * | 623 * |
610 * Called by xsltApplySequenceConstructor() (transform.c). | 624 * Called by xsltApplySequenceConstructor() (transform.c). |
611 * | 625 * |
612 * Returns a new list of attribute nodes, or NULL in case of error. | 626 * Returns a new list of attribute nodes, or NULL in case of error. |
613 * (Don't assign the result to @target->properties; if | 627 * (Don't assign the result to @target->properties; if |
614 * the result is NULL, you'll get memory leaks, since the | 628 * the result is NULL, you'll get memory leaks, since the |
615 * attributes will be disattached.) | 629 * attributes will be disattached.) |
616 */ | 630 */ |
617 xmlAttrPtr | 631 xmlAttrPtr |
618 xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, | 632 xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, |
619 xmlNodePtr target, xmlAttrPtr attrs) | 633 xmlNodePtr target, xmlAttrPtr attrs) |
620 { | 634 { |
621 xmlAttrPtr attr, copy, last; | 635 xmlAttrPtr attr, copy, last; |
622 xmlNodePtr oldInsert, text; | 636 xmlNodePtr oldInsert, text; |
623 xmlNsPtr origNs = NULL, copyNs = NULL; | 637 xmlNsPtr origNs = NULL, copyNs = NULL; |
624 const xmlChar *value; | 638 const xmlChar *value; |
625 xmlChar *valueAVT; | 639 xmlChar *valueAVT; |
626 | 640 |
627 if ((ctxt == NULL) || (target == NULL) || (attrs == NULL)) | 641 if ((ctxt == NULL) || (target == NULL) || (attrs == NULL) || |
| 642 (target->type != XML_ELEMENT_NODE)) |
628 return(NULL); | 643 return(NULL); |
629 | 644 |
630 oldInsert = ctxt->insert; | 645 oldInsert = ctxt->insert; |
631 ctxt->insert = target; | 646 ctxt->insert = target; |
632 | 647 |
633 /* | 648 /* |
634 * Instantiate LRE-attributes. | 649 * Instantiate LRE-attributes. |
635 */ | 650 */ |
636 if (target->properties) { | 651 if (target->properties) { |
637 last = target->properties; | 652 last = target->properties; |
638 while (last->next != NULL) | 653 while (last->next != NULL) |
639 last = last->next; | 654 last = last->next; |
640 } else { | 655 } else { |
641 last = NULL; | 656 last = NULL; |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
814 * @node: the attribute template node | 829 * @node: the attribute template node |
815 * | 830 * |
816 * Obsolete. Don't use it. | 831 * Obsolete. Don't use it. |
817 * | 832 * |
818 * Returns NULL. | 833 * Returns NULL. |
819 */ | 834 */ |
820 xmlNodePtr * | 835 xmlNodePtr * |
821 xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr no
de) { | 836 xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr no
de) { |
822 if (node == NULL) | 837 if (node == NULL) |
823 return(NULL); | 838 return(NULL); |
824 | 839 |
825 return(0); | 840 return(0); |
826 } | 841 } |
827 | 842 |
828 | 843 |
OLD | NEW |