1/*---------------------------------------------------------------------------- 2| Copyright (c) 2000 Jochen Loewer (loewerj@hotmail.com) 3|----------------------------------------------------------------------------- 4| 5| $Id: domxslt.c,v 1.119 2008/03/04 21:03:09 rolf Exp $ 6| 7| 8| A XSLT implementation for tDOM, according to the W3C 9| recommendation (16 Nov 1999). 10| See http://www.w3.org/TR/1999/REC-xslt-19991116 for details. 11| 12| 13| The contents of this file are subject to the Mozilla Public License 14| Version 1.1 (the "License"); you may not use this file except in 15| compliance with the License. You may obtain a copy of the License at 16| http://www.mozilla.org/MPL/ 17| 18| Software distributed under the License is distributed on an "AS IS" 19| basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 20| License for the specific language governing rights and limitations 21| under the License. 22| 23| The Original Code is tDOM. 24| 25| The Initial Developer of the Original Code is Jochen Loewer 26| Portions created by Jochen Loewer are Copyright (C) 1999, 2000 27| Jochen Loewer. All Rights Reserved. 28| 29| Contributor(s): 30| Aug01 Rolf Ade xsl:include, xsl:import, xsl:apply-imports, 31| document() plus several bug fixes 32| 33| Fall/Winter 01 Rolf Ade rewrite of xsl:number, xsl:key/key(), 34| handling of toplevel var/parameter, 35| plenty of fixes and enhancements all 36| over the place. 37| 38| 2001-2007 Rolf Ade All changes and enhancements. 39| 40| written by Jochen Loewer 41| June, 2000 42| 43\---------------------------------------------------------------------------*/ 44 45 46 47/*---------------------------------------------------------------------------- 48| Includes 49| 50\---------------------------------------------------------------------------*/ 51#include <stdio.h> 52#include <stdlib.h> 53#include <string.h> 54#include <math.h> 55#include <limits.h> 56#include <ctype.h> 57#include <locale.h> 58#include <dom.h> 59#include <domxpath.h> 60#include <domxslt.h> 61#include <tcl.h> /* for hash tables */ 62 63/*---------------------------------------------------------------------------- 64| Defines 65| 66\---------------------------------------------------------------------------*/ 67#define XSLT_NAMESPACE "http://www.w3.org/1999/XSL/Transform" 68#define INITIAL_SIZE_FOR_KEYSETS 10 69 70 71/*---------------------------------------------------------------------------- 72| Macros 73| 74\---------------------------------------------------------------------------*/ 75#define DBG(x) 76#define TRACE(x) DBG(fprintf(stderr,(x))) 77#define TRACE1(x,a) DBG(fprintf(stderr,(x),(a))) 78#define TRACE2(x,a,b) DBG(fprintf(stderr,(x),(a),(b))) 79#define TRACE3(x,a,b,c) DBG(fprintf(stderr,(x),(a),(b),(c))) 80#define TRACE4(x,a,b,c,d) DBG(fprintf(stderr,(x),(a),(b),(c),(d))) 81#define TRACE5(x,a,b,c,d,e) DBG(fprintf(stderr,(x),(a),(b),(c),(d),(e))) 82 83#define CHECK_RC if (rc < 0) return rc 84#define CHECK_RC1(x) if (rc < 0) {FREE((char*)(x)); return rc;} 85#define SET_TAG(t,n,s,v) if (strcmp(n,s)==0) { t->info = v; return v; } 86#define SETSCOPESTART xs->varFramesStack[xs->varFramesStackPtr].stop=1 87#define SETPARAMDEF xs->varFramesStack[xs->varFramesStackPtr].stop=2 88 89#if defined(_MSC_VER) 90# define STRCASECMP(a,b) stricmp (a,b) 91#else 92# define STRCASECMP(a,b) strcasecmp (a,b) 93#endif 94 95extern void printAst (int depth, ast t); 96 97/*-------------------------------------------------------------------------- 98| xsltTag 99| 100\-------------------------------------------------------------------------*/ 101typedef enum { 102 103 unknown = 1, 104 applyImports, applyTemplates, attribute, attributeSet, callTemplate, 105 choose, comment, copy, copyOf, decimalFormat, element, fallback, forEach, 106 xsltIf, import, 107 include, key, message, namespaceAlias, number, output, otherwise, 108 param, procinstr, 109 preserveSpace, sort, stylesheet, stripSpace, text, template, 110 transform, valueOf, variable, when, withParam 111 112} xsltTag; 113 114 115/*-------------------------------------------------------------------------- 116| xsltAttr 117| 118\-------------------------------------------------------------------------*/ 119typedef enum { 120 121 a_caseorder = 1, 122 a_count, a_dataType, a_disableOutputEscaping, 123 a_doctypePublic, a_doctypeSystem, a_elements, a_encoding, 124 a_format, a_from, a_href, a_lang, a_level, a_match, a_mediaType, a_method, 125 a_mode, a_name, a_namespace, a_order, a_prio, a_select, a_space, 126 a_terminate, a_test, a_use, a_useAttributeSets, a_value, 127 a_groupingSeparator, a_groupingSize, 128 a_decimalSeparator, a_infinity, a_minusSign, a_nan, a_percent, 129 a_perMille, a_zeroDigit, a_digit, a_patternSeparator, a_version, 130 a_excludeResultPrefixes, a_extensionElementPrefixes, 131 a_stylesheetPrefix, a_resultPrefix, a_indent, a_omitXMLDeclaration, 132 a_standalone, a_cdataSectionElements 133 134} xsltAttr; 135 136 137/*-------------------------------------------------------------------------- 138| xsltExclExtNS 139| 140\-------------------------------------------------------------------------*/ 141typedef struct xsltExclExtNS 142{ 143 char * uri; 144 145 struct xsltExclExtNS * next; 146 147} xsltExclExtNS; 148 149/*-------------------------------------------------------------------------- 150| xsltSubDocs 151| 152\-------------------------------------------------------------------------*/ 153typedef struct xsltSubDoc 154{ 155 domDocument * doc; 156 char * baseURI; 157 Tcl_HashTable keyData; 158 xsltExclExtNS * excludeNS; 159 xsltExclExtNS * extensionNS; 160 int fwCmpProcessing; 161 int isStylesheet; 162 int fixedXMLSource; 163 int mustFree; 164 165 struct xsltSubDoc * next; 166 167} xsltSubDoc; 168 169/*-------------------------------------------------------------------------- 170| xsltTemplate 171| 172\-------------------------------------------------------------------------*/ 173typedef struct xsltTemplate { 174 175 char * match; 176 const char * name; 177 const char * nameURI; 178 ast ast; 179 const char * mode; 180 const char * modeURI; 181 double prio; 182 domNode * content; 183 double precedence; 184 ast freeAst; 185 xsltSubDoc * sDoc; 186 187 struct xsltTemplate *next; 188 189} xsltTemplate; 190 191 192/*-------------------------------------------------------------------------- 193| xsltAttrSet 194| 195\-------------------------------------------------------------------------*/ 196typedef struct xsltAttrSet { 197 198 const char * name; 199 const char * uri; 200 domNode * content; 201 202 struct xsltAttrSet *next; 203 204} xsltAttrSet; 205 206/*-------------------------------------------------------------------------- 207| xsltNodeSet 208| 209\-------------------------------------------------------------------------*/ 210typedef struct xsltNodeSet { 211 212 domNode **nodes; 213 int nr_nodes; 214 int allocated; 215 216} xsltNodeSet; 217 218/*-------------------------------------------------------------------------- 219| xsltKeyInfo 220| 221\-------------------------------------------------------------------------*/ 222typedef struct xsltKeyInfo { 223 224 domNode * node; 225 char * match; 226 ast matchAst; 227 char * use; 228 ast useAst; 229 230 struct xsltKeyInfo * next; 231 232} xsltKeyInfo; 233 234/*-------------------------------------------------------------------------- 235| xsltVariable 236| 237\-------------------------------------------------------------------------*/ 238typedef struct xsltVariable { 239 240 const char * name; 241 const char * uri; 242 domNode * node; 243 xpathResultSet rs; 244 int active; 245 246} xsltVariable; 247 248/*-------------------------------------------------------------------------- 249| xsltVarFrame 250| 251\-------------------------------------------------------------------------*/ 252typedef struct xsltVarFrame { 253 254 xsltVariable * vars; 255 int polluted; 256 int nrOfVars; 257 int varStartIndex; 258 int stop; 259 260} xsltVarFrame; 261 262/*-------------------------------------------------------------------------- 263| xsltTopLevelVar 264| 265\-------------------------------------------------------------------------*/ 266typedef struct xsltTopLevelVar 267{ 268 269 domNode * node; 270 char * name; 271 int isParameter; 272 double precedence; 273 274} xsltTopLevelVar; 275 276/*-------------------------------------------------------------------------- 277| xsltVarInProcess 278| 279\-------------------------------------------------------------------------*/ 280typedef struct xsltVarInProcess 281 282{ 283 char *name; 284 285 struct xsltVarInProcess *next; 286 287} xsltVarInProcess; 288 289 290/*-------------------------------------------------------------------------- 291| xsltDecimalFormat 292| 293\-------------------------------------------------------------------------*/ 294typedef struct xsltDecimalFormat 295{ 296#if TclOnly8Bits 297 char * name; 298 char * uri; 299 char decimalSeparator; 300 char groupingSeparator; 301 char * infinity; 302 char minusSign; 303 char * NaN; 304 char percent; 305 char zeroDigit; 306 char digit; 307 char patternSeparator; 308#else 309 char * name; 310 char * uri; 311 Tcl_UniChar decimalSeparator; 312 Tcl_UniChar groupingSeparator; 313 char * infinity; 314 Tcl_UniChar minusSign; 315 char * NaN; 316 Tcl_UniChar percent; 317 Tcl_UniChar perMille; 318 Tcl_UniChar zeroDigit; 319 Tcl_UniChar digit; 320 Tcl_UniChar patternSeparator; 321#endif /* TclOnly8Bits */ 322 323 struct xsltDecimalFormat * next; 324 325} xsltDecimalFormat; 326 327 328/*-------------------------------------------------------------------------- 329| xsltWSInfo 330| 331\-------------------------------------------------------------------------*/ 332typedef struct xsltWSInfo 333{ 334 335 int hasData; 336 int stripAll; 337 double wildcardPrec; 338 Tcl_HashTable stripTokens; 339 Tcl_HashTable preserveTokens; 340 341} xsltWSInfo; 342 343 344typedef struct xsltNSAlias 345{ 346 347 char *fromUri; 348 char *toUri; 349 double precedence; 350 351 struct xsltNSAlias *next; 352 353} xsltNSAlias; 354 355 356/*-------------------------------------------------------------------------- 357| xsltState 358| 359\-------------------------------------------------------------------------*/ 360typedef struct { 361 362 xsltTemplate * templates; 363 Tcl_HashTable namedTemplates; 364 Tcl_HashTable isElementTpls; 365 xsltWSInfo wsInfo; 366 domNode * xmlRootNode; 367 domDocInfo doctype; 368 int indentOutput; 369 domDocument * resultDoc; 370 domNode * lastNode; 371 xsltVarFrame * varFramesStack; 372 int varFramesStackPtr; 373 int varFramesStackLen; 374 xsltVariable * varStack; 375 int varStackPtr; 376 int varStackLen; 377 xsltAttrSet * attrSets; 378 Tcl_HashTable xpaths; 379 Tcl_HashTable pattern; 380 Tcl_HashTable formats; 381 Tcl_HashTable topLevelVars; 382 Tcl_HashTable keyInfos; 383 xsltNSAlias * nsAliases; 384 int nsUniqeNr; 385 xsltVarInProcess * varsInProcess; 386 xpathCBs cbs; 387 xpathFuncCallback orig_funcCB; 388 void * orig_funcClientData; 389 xsltMsgCB xsltMsgCB; 390 void * xsltMsgClientData; 391 xsltDecimalFormat * decimalFormats; 392 domNode * current; 393 xsltSubDoc * subDocs; 394 xsltSubDoc * currentSubDoc; 395 xsltTemplate * currentTplRule; 396 domNode * currentXSLTNode; 397 domDocument * xsltDoc; 398 399} xsltState; 400 401 402typedef enum { 403 latin_number, latin_upper, latin_lower, 404 roman_upper, roman_lower 405} xsltNumberingType; 406 407 408/*-------------------------------------------------------------------------- 409| xsltNumberFormatToken 410| 411\-------------------------------------------------------------------------*/ 412typedef struct { 413 414 xsltNumberingType type; 415 int minlength; 416 char *sepStart; 417 int sepLen; 418 419} xsltNumberFormatToken; 420 421 422/*-------------------------------------------------------------------------- 423| xsltNumberFormat 424| 425\-------------------------------------------------------------------------*/ 426typedef struct { 427 428 char *formatStr; 429 int prologLen; 430 xsltNumberFormatToken *tokens; 431 int maxtokens; 432 char *epilogStart; 433 int epilogLen; 434 435} xsltNumberFormat; 436 437 438/*-------------------------------------------------------------------------- 439| Prototypes 440| 441\-------------------------------------------------------------------------*/ 442static int ApplyTemplates ( xsltState *xs, xpathResultSet *context, 443 domNode *currentNode, int currentPos, 444 domNode *actionNode, xpathResultSet *nodeList, 445 const char *mode, const char *modeURI, 446 char **errMsg); 447 448static int ApplyTemplate ( xsltState *xs, xpathResultSet *context, 449 domNode *currentNode, domNode *exprContext, 450 int currentPos, const char *mode, 451 const char *modeURI, char **errMsg); 452 453static int ExecActions (xsltState *xs, xpathResultSet *context, 454 domNode *currentNode, int currentPos, 455 domNode *actionNode, char **errMsg); 456 457static domDocument * getExternalDocument (Tcl_Interp *interp, xsltState *xs, 458 domDocument *xsltDoc, 459 const char *baseURI, 460 const char *href, int isStylesheet, 461 int fixedXMLSource, char **errMsg); 462 463 464/*---------------------------------------------------------------------------- 465| printXML 466| 467\---------------------------------------------------------------------------*/ 468static void printXML (domNode *node, int level, int maxlevel) { 469 470 domTextNode *tnode; 471 domProcessingInstructionNode *pi; 472 char tmp[80]; 473 int i, l, n; 474 475 n = 0; 476 while (node) { 477 478 for (i=0;i<level;i++) fprintf(stderr, " "); 479 if (node->nodeType == ELEMENT_NODE) { 480 if (node->firstChild && node->firstChild->nodeType == TEXT_NODE) { 481 tnode = (domTextNode*)node->firstChild; 482 l = tnode->valueLength; 483 if (l > 30) l = 30; 484 memmove(tmp, tnode->nodeValue, l); 485 tmp[l] = '\0'; 486 fprintf(stderr, "<%s/domNode0x%p> '%s'\n", node->nodeName, 487 node, tmp); 488 } else { 489 tmp[0] = '\0'; 490 if ((level>=maxlevel) && (node->firstChild)) { 491 strcpy( tmp, "..."); 492 } 493 fprintf(stderr, "<%s/domNode0x%p> %s\n", node->nodeName, 494 node, tmp); 495 } 496 if (level<maxlevel) { 497 if (node->firstChild) printXML(node->firstChild, level+1, 498 maxlevel); 499 } 500 } 501 if (node->nodeType == TEXT_NODE) { 502 tnode = (domTextNode*)node; 503 l = tnode->valueLength; 504 if (l > 70) l = 70; 505 memmove(tmp, tnode->nodeValue, l); 506 tmp[l] = '\0'; 507 fprintf(stderr, "'%s'\n", tmp); 508 } 509 if (node->nodeType == COMMENT_NODE) { 510 tnode = (domTextNode*)node; 511 l = tnode->valueLength; 512 memmove (tmp, "<!--", 4); 513 if (l >70) l = 70; 514 memmove (&tmp[4], tnode->nodeValue, l); 515 memmove (&tmp[4+l], "-->", 3); 516 tmp[7+l] = '\0'; 517 fprintf(stderr, "'%s'\n", tmp); 518 } 519 if (node->nodeType == PROCESSING_INSTRUCTION_NODE) { 520 pi = (domProcessingInstructionNode*)node; 521 l = pi->targetLength; 522 if (l > 70) l = 70; 523 memmove(tmp, pi->targetValue, l); 524 tmp[l] = '\0'; 525 fprintf(stderr, "<?%s ", tmp); 526 l = pi->dataLength; 527 if (l > 70) l = 70; 528 memmove(tmp, pi->dataValue, l); 529 tmp[l] = '\0'; 530 fprintf(stderr, "%s?>\n", tmp); 531 } 532 node = node->nextSibling; 533 n++; 534 if (n>8) { fprintf(stderr, "...\n"); return; } 535 } 536} 537 538/*---------------------------------------------------------------------------- 539| reportError 540| 541\---------------------------------------------------------------------------*/ 542static void 543reportError ( 544 domNode * node, 545 char * str, 546 char ** errMsg) 547{ 548 Tcl_DString dStr; 549 char buffer[1024]; 550 const char *baseURI; 551 int line, column; 552 553 Tcl_DStringInit (&dStr); 554 baseURI = findBaseURI (node); 555 if (baseURI) { 556 Tcl_DStringAppend (&dStr, "In entity ", 10); 557 Tcl_DStringAppend (&dStr, baseURI, -1); 558 } 559 if (node->nodeFlags & HAS_LINE_COLUMN) { 560 domGetLineColumn (node, &line, &column); 561 sprintf (buffer, " at line %d, column %d:\n", line, column); 562 Tcl_DStringAppend (&dStr, buffer, -1); 563 Tcl_DStringAppend (&dStr, str, -1); 564 } else { 565 if (baseURI) Tcl_DStringAppend (&dStr, ": ", 2); 566 Tcl_DStringAppend (&dStr, str, -1); 567 } 568 if (*errMsg) FREE (*errMsg); 569 *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); 570 Tcl_DStringFree (&dStr); 571} 572 573/*---------------------------------------------------------------------------- 574| getAttr 575| 576\---------------------------------------------------------------------------*/ 577static char * getAttr ( 578 domNode *node, 579 char *name, 580 xsltAttr attrTypeNo 581) 582{ 583 domAttrNode *attr; 584 585 attr = node->firstAttr; 586 while (attr) { 587 588 if (attr->info == (unsigned int)attrTypeNo) { 589 return attr->nodeValue; 590 } else if (attr->info == 0) { 591 if (strcmp ((char*)attr->nodeName, name)==0) { 592 attr->info = (unsigned int)attrTypeNo; 593 return attr->nodeValue; 594 } 595 } 596 attr = attr->nextSibling; 597 } 598 return NULL; 599} 600 601 602/*---------------------------------------------------------------------------- 603| getTag 604| 605\---------------------------------------------------------------------------*/ 606static xsltTag getTag ( 607 domNode *node 608) 609{ 610 const char *name; 611 612 if (node->nodeType != ELEMENT_NODE) { 613 node->info = (int)unknown; 614 return unknown; 615 } 616 if (node->info != 0) { 617 return (xsltTag)node->info; 618 } 619 name = domNamespaceURI(node); 620 if ((name == NULL) || (strcmp(name, XSLT_NAMESPACE)!=0)) { 621 node->info = (int)unknown; 622 return unknown; 623 } 624 name = domGetLocalName(node->nodeName); 625 626 switch (*name) { 627 case 'a': SET_TAG(node,name,"apply-imports", applyImports); 628 SET_TAG(node,name,"apply-templates",applyTemplates); 629 SET_TAG(node,name,"attribute", attribute); 630 SET_TAG(node,name,"attribute-set", attributeSet); 631 break; 632 case 'c': SET_TAG(node,name,"call-template", callTemplate); 633 SET_TAG(node,name,"choose", choose); 634 SET_TAG(node,name,"comment", comment); 635 SET_TAG(node,name,"copy", copy); 636 SET_TAG(node,name,"copy-of", copyOf); 637 break; 638 case 'd': SET_TAG(node,name,"decimal-format", decimalFormat); 639 break; 640 case 'e': SET_TAG(node,name,"element", element); 641 break; 642 case 'f': SET_TAG(node,name,"fallback", fallback); 643 SET_TAG(node,name,"for-each", forEach); 644 break; 645 case 'i': SET_TAG(node,name,"if", xsltIf); 646 SET_TAG(node,name,"import", import); 647 SET_TAG(node,name,"include", include); 648 break; 649 case 'k': SET_TAG(node,name,"key", key); 650 break; 651 case 'm': SET_TAG(node,name,"message", message); 652 break; 653 case 'n': SET_TAG(node,name,"namespace-alias",namespaceAlias); 654 SET_TAG(node,name,"number", number); 655 break; 656 case 'o': SET_TAG(node,name,"output", output); 657 SET_TAG(node,name,"otherwise", otherwise); 658 break; 659 case 'p': SET_TAG(node,name,"param", param); 660 SET_TAG(node,name,"preserve-space", preserveSpace); 661 SET_TAG(node,name,"processing-instruction", procinstr); 662 break; 663 case 's': SET_TAG(node,name,"sort", sort); 664 SET_TAG(node,name,"stylesheet", stylesheet); 665 SET_TAG(node,name,"strip-space", stripSpace); 666 break; 667 case 't': SET_TAG(node,name,"template", template); 668 SET_TAG(node,name,"text", text); 669 SET_TAG(node,name,"transform", transform); 670 break; 671 case 'v': SET_TAG(node,name,"value-of", valueOf); 672 SET_TAG(node,name,"variable", variable); 673 break; 674 case 'w': SET_TAG(node,name,"when", when); 675 SET_TAG(node,name,"with-param", withParam); 676 break; 677 } 678 node->info = (int)unknown; 679 return unknown; 680} 681 682 683/*---------------------------------------------------------------------------- 684| xsltPopVarFrame 685| 686\---------------------------------------------------------------------------*/ 687static void xsltPopVarFrame ( 688 xsltState * xs 689) 690{ 691 int i; 692 xsltVarFrame *frame; 693 694 if (xs->varFramesStackPtr >= 0) { 695 frame = &xs->varFramesStack[xs->varFramesStackPtr]; 696 if (frame->nrOfVars) { 697 for (i = frame->varStartIndex; 698 i < frame->varStartIndex + frame->nrOfVars; 699 i++) { 700 xpathRSFree (&(&xs->varStack[i])->rs); 701 } 702 } 703 xs->varStackPtr -= frame->nrOfVars; 704 xs->varFramesStackPtr--; 705 } 706} 707 708 709/*---------------------------------------------------------------------------- 710| xsltPushVarFrame 711| 712\---------------------------------------------------------------------------*/ 713static void xsltPushVarFrame ( 714 xsltState * xs 715) 716{ 717 xsltVarFrame * frame; 718 719 xs->varFramesStackPtr++; 720 if (xs->varFramesStackPtr >= xs->varFramesStackLen) { 721 xs->varFramesStack = (xsltVarFrame *) REALLOC ((char*)xs->varFramesStack, 722 sizeof (xsltVarFrame) 723 * 2 * xs->varFramesStackLen); 724 xs->varFramesStackLen *= 2; 725 } 726 frame = &(xs->varFramesStack[xs->varFramesStackPtr]); 727 frame->polluted = 0; 728 frame->nrOfVars = 0; 729 frame->varStartIndex = -1; 730 frame->stop = 0; 731} 732 733 734/*---------------------------------------------------------------------------- 735| xsltAddExternalDocument 736| 737\---------------------------------------------------------------------------*/ 738static int xsltAddExternalDocument ( 739 xsltState * xs, 740 const char * baseURI, 741 const char * str, 742 int fixedXMLSource, 743 xpathResultSet * result, 744 char ** errMsg 745) 746{ 747 xsltSubDoc * sdoc; 748 domDocument * extDocument; 749 int found; 750 751 DBG( 752 fprintf (stderr, "xsltAddExternalDocument: baseURI '%s'\n", baseURI); 753 fprintf (stderr, "xsltAddExternalDocument: systemID '%s'\n", str); 754 ) 755 756 found = 0; 757 sdoc = xs->subDocs; 758 if (str) { 759 while (sdoc) { 760 if (!sdoc->isStylesheet 761 && sdoc->baseURI 762 && strcmp (sdoc->baseURI, str)==0) { 763 rsAddNode (result, sdoc->doc->rootNode); 764 found = 1; 765 break; 766 } 767 sdoc = sdoc->next; 768 } 769 } 770 if (!found) { 771 if (!xs->xsltDoc->extResolver) { 772 *errMsg = tdomstrdup("need resolver Script to include Stylesheet! " 773 "(use \"-externalentitycommand\")"); 774 return -1; 775 } 776 extDocument = getExternalDocument ( 777 (Tcl_Interp*)xs->orig_funcClientData, 778 xs, xs->xsltDoc, baseURI, str, 0, fixedXMLSource, 779 errMsg); 780 if (extDocument) { 781 rsAddNode (result, extDocument->rootNode); 782 } else { 783 return -1; 784 } 785 } 786 return found; 787} 788 789 790/*---------------------------------------------------------------------------- 791| xsltNumberFormatTokenizer 792| 793\---------------------------------------------------------------------------*/ 794static xsltNumberFormat* xsltNumberFormatTokenizer ( 795 xsltState *xs, 796 char *formatStr, 797 char **errMsg 798) 799{ 800 char *p; 801 int hnew, clen, nrOfTokens = 0; 802 Tcl_HashEntry *h; 803 xsltNumberFormat *format; 804 805 /* TODO: make it l18n aware. */ 806 807 h = Tcl_CreateHashEntry (&xs->formats, formatStr, &hnew); 808 if (!hnew) { 809 return (xsltNumberFormat *) Tcl_GetHashValue (h); 810 } else { 811 format = (xsltNumberFormat *)MALLOC(sizeof (xsltNumberFormat)); 812 memset (format, 0 , sizeof (xsltNumberFormat)); 813 format->tokens = (xsltNumberFormatToken *) 814 MALLOC(sizeof (xsltNumberFormatToken) * 20); 815 memset (format->tokens, 0, sizeof (xsltNumberFormatToken) * 20); 816 format->maxtokens = 20; 817 Tcl_SetHashValue (h, format); 818 format->formatStr = p = Tcl_GetHashKey (&(xs->formats), h); 819 } 820 while (*p) { 821 clen = UTF8_CHAR_LEN(*p); 822 if (!clen) { 823 reportError (xs->currentXSLTNode, "xsl:number: UTF-8 form of" 824 " character longer than 3 Byte", errMsg); 825 return NULL; 826 } 827 if (clen > 1) { 828 /* hack: skip over multibyte chars - this may be wrong */ 829 format->prologLen += clen; 830 p += clen; 831 continue; 832 } 833 if (isalnum((unsigned char)*p)) break; 834 format->prologLen++; 835 p++; 836 } 837 838 format->tokens[0].minlength = 1; 839 if (!*p) { 840 format->tokens[0].type = latin_number; 841 return format; 842 } 843 844#define addSeperator \ 845 p++; \ 846 if (*p) { \ 847 format->tokens[nrOfTokens].sepStart = p; \ 848 } \ 849 while (*p) { \ 850 clen = UTF8_CHAR_LEN(*p); \ 851 if (!clen) { \ 852 reportError (xs->currentXSLTNode, "xsl:number: UTF-8 form of character longer than 3 Byte", errMsg); \ 853 return NULL; \ 854 } \ 855 if (clen > 1) { \ 856 /* hack: skip over multibyte chars - this may be wrong */ \ 857 format->tokens[nrOfTokens].sepLen += clen; \ 858 p += clen; \ 859 continue; \ 860 } \ 861 if (isalnum((unsigned char)*p)) break; \ 862 format->tokens[nrOfTokens].sepLen++; \ 863 p++; \ 864 } \ 865 if (*p) { \ 866 if (format->tokens[nrOfTokens].sepLen == 0) goto wrongSyntax; \ 867 } \ 868 nrOfTokens++; \ 869 if (nrOfTokens == format->maxtokens) { \ 870 format->tokens = (xsltNumberFormatToken *) REALLOC ((char *)format->tokens, sizeof (xsltNumberFormatToken) * format->maxtokens * 2); \ 871 format->maxtokens *= 2; \ 872 } \ 873 format->tokens[nrOfTokens].minlength = 1; \ 874 continue; 875 876 while (*p) { 877 if (*p == '0') { 878 format->tokens[nrOfTokens].minlength++; 879 p++; 880 continue; 881 } 882 if (*p == '1') { 883 format->tokens[nrOfTokens].type = latin_number; 884 addSeperator; 885 } 886 if (*p == 'A') { 887 if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; 888 format->tokens[nrOfTokens].type = latin_upper; 889 addSeperator; 890 } 891 if (*p == 'a') { 892 if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; 893 format->tokens[nrOfTokens].type = latin_lower; 894 addSeperator; 895 } 896 if (*p == 'I') { 897 if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; 898 format->tokens[nrOfTokens].type = roman_upper; 899 addSeperator; 900 } 901 if (*p == 'i') { 902 if (isalnum((unsigned char)*(p+1))) goto wrongSyntax; 903 format->tokens[nrOfTokens].type = roman_lower; 904 addSeperator; 905 } 906 format->tokens[nrOfTokens].type = latin_number; 907 while (isalnum((unsigned char)*(p+1))) { 908 p++; 909 } 910 addSeperator; 911 } 912 format->epilogStart = format->tokens[nrOfTokens-1].sepStart; 913 format->tokens[nrOfTokens-1].sepStart = NULL; 914 format->epilogLen = format->tokens[nrOfTokens-1].sepLen; 915 format->tokens[nrOfTokens-1].sepLen = 0; 916 return format; 917 918 wrongSyntax: 919 reportError (xs->currentXSLTNode, "xsl:number: Wrong syntax in" 920 " format attribute", errMsg); 921 return NULL; 922} 923 924/*---------------------------------------------------------------------------- 925| formatValue 926| 927\---------------------------------------------------------------------------*/ 928static void formatValue ( 929 xsltNumberFormat *f, 930 int *useFormatToken, 931 int value, 932 Tcl_DString *str, 933 char *groupingSeparator, 934 long groupingSize, 935 int addSeperater 936) 937{ 938 int len, fulllen, gslen, upper = 0, e, m, b, i, z, v; 939 char tmp[80], *pt; 940 Tcl_DString tmp1; 941 static struct { char *digit; char *ldigit; int value; } RomanDigit[] = { 942 { "M" , "m" , 1000, }, 943 { "CM", "cm", 900, }, 944 { "D" , "d" , 500, }, 945 { "CD", "cd", 400, }, 946 { "C" , "c" , 100, }, 947 { "XC", "xc", 90, }, 948 { "L" , "l" , 50, }, 949 { "XL", "xl", 40, }, 950 { "X" , "x" , 10, }, 951 { "IX", "ix", 9, }, 952 { "V" , "v" , 5, }, 953 { "IV", "iv", 4, }, 954 { "I" , "i" , 1 } 955 }; 956 957 switch (f->tokens[*useFormatToken].type) { 958 case latin_number: 959 sprintf (tmp, "%d", value); 960 fulllen = len = strlen (tmp); 961 if (f->tokens[*useFormatToken].minlength > fulllen) { 962 fulllen = f->tokens[*useFormatToken].minlength; 963 } 964 if (groupingSeparator) { 965 gslen = strlen (groupingSeparator); 966 Tcl_DStringInit (&tmp1); 967 if (len < f->tokens[*useFormatToken].minlength) { 968 for (i = 0; i < f->tokens[*useFormatToken].minlength - len; i++) { 969 Tcl_DStringAppend (&tmp1, "0", 1); 970 } 971 } 972 Tcl_DStringAppend (&tmp1, tmp, len); 973 pt = Tcl_DStringValue (&tmp1); 974 len = Tcl_DStringLength (&tmp1); 975 m = len % groupingSize; 976 if (m) { 977 Tcl_DStringAppend (str, pt, m); 978 pt += m; 979 } 980 i = len - m; 981 while (i) { 982 if (i != len) { 983 Tcl_DStringAppend (str, groupingSeparator, gslen); 984 } 985 Tcl_DStringAppend (str, pt, groupingSize); 986 pt += groupingSize; 987 i -= groupingSize; 988 } 989 Tcl_DStringFree (&tmp1); 990 } else { 991 for (i = 0; i < fulllen - len; i++) { 992 Tcl_DStringAppend (str, "0", 1); 993 } 994 Tcl_DStringAppend (str, tmp, len); 995 } 996 goto appendSeperator; 997 break; 998 999 case latin_upper: 1000 upper = 1; 1001 /* fall thru */ 1002 case latin_lower: 1003 /* Home grown algorithm. (And I'm really not happy with it.) 1004 Please let rolf@pointsman.de know how to do this better / 1005 faster / more clever. */ 1006 1007 if (value <= 0) { 1008 /* Hm, zero can't be expressed with letter sequences... 1009 What to do? One of the several cases, not mentioned 1010 by the spec. */ 1011 /* fall back to latin numbers */ 1012 sprintf (tmp, "%d", value); 1013 break; 1014 } 1015 e = 1; 1016 m = b = 26; 1017 while (value > m) { 1018 b *= 26; 1019 m += b; 1020 e++; 1021 } 1022 m -= b; 1023 value -= m; 1024 for (i = 0; i < e; i++) { 1025 b /= 26; 1026 z = value / b; 1027 value = value - z*b; 1028 if (i < e -1) { 1029 if (value == 0) { 1030 value += b; 1031 } else { 1032 z++; 1033 } 1034 } 1035 if (upper) { 1036 tmp[i] = 64+z; 1037 } else { 1038 tmp[i] = 96+z; 1039 } 1040 } 1041 tmp[i] = '\0'; 1042 break; 1043 1044 case roman_upper: 1045 upper = 1; 1046 /* fall thru */ 1047 case roman_lower: 1048 /* Algorithm follows the idear of the converter 1049 at http://mini.net/cgi-bin/wikit/1749.html */ 1050 1051 /* Side note: There exists a rarely used roman notation 1052 to express figures up to a few millions. Does somebody 1053 really need this? */ 1054 1055 if (value > 3999 || value <= 0) { 1056 /* fall back to latin numbers */ 1057 sprintf (tmp, "%d", value); 1058 break; 1059 } 1060 if (value == 0) { 1061 /* what to do with zero??? */ 1062 sprintf (tmp, "%d", 0); 1063 break; 1064 } 1065 v = 0; tmp[0] = '\0'; 1066 while (value > 0) { 1067 while (value >= RomanDigit[v].value) { 1068 if (upper) { strcat(tmp, RomanDigit[v].digit); } 1069 else { strcat(tmp, RomanDigit[v].ldigit); } 1070 value -= RomanDigit[v].value; 1071 } 1072 v++; 1073 } 1074 break; 1075 1076 default: 1077 sprintf (tmp, "%d", value); 1078 break; 1079 } 1080 len = strlen (tmp); 1081 Tcl_DStringAppend (str, tmp, len); 1082 appendSeperator: 1083 if (addSeperater) { 1084 if (f->tokens[*useFormatToken].sepStart) { 1085 Tcl_DStringAppend (str, f->tokens[*useFormatToken].sepStart, 1086 f->tokens[*useFormatToken].sepLen); 1087 *useFormatToken += 1; 1088 } else { 1089 if (*useFormatToken > 0) { 1090 Tcl_DStringAppend (str, f->tokens[*useFormatToken-1].sepStart, 1091 f->tokens[*useFormatToken-1].sepLen); 1092 } else { 1093 /* insert default seperator '.' */ 1094 Tcl_DStringAppend (str, ".", 1); 1095 } 1096 } 1097 } 1098 1099 return; 1100} 1101 1102/*---------------------------------------------------------------------------- 1103| xsltFormatNumber 1104| 1105\---------------------------------------------------------------------------*/ 1106#if TclOnly8Bits 1107static int xsltFormatNumber ( 1108 double number, 1109 char * formatStr, 1110 xsltDecimalFormat * df, 1111 char ** resultStr, 1112 int * resultLen, 1113 char ** errMsg 1114) 1115{ 1116 char *p, prefix[800], suffix[800], s[2400], n[800], f[800]; 1117 char *negformat = NULL, save = '\0', save1; 1118 int i, l, zl, g, nHash, nZero, fHash, fZero, gLen, isNeg; 1119/* struct lconv *lc = NULL; */ 1120 char wrongFormat[] = "Unable to interpret format pattern."; 1121 1122 DBG(fprintf(stderr, "\nformatStr='%s' \n", formatStr);) 1123 if (number < 0.0) { 1124 isNeg = 1; 1125 number *= -1.0; 1126 } else { 1127 isNeg = 0; 1128 } 1129 p = formatStr; 1130 while (*p) { 1131 if (*p == df->patternSeparator) { 1132 *p = '\0'; 1133 negformat = ++p; 1134 break; 1135 } 1136 p++; 1137 } 1138 /* Check for more than one patternSeparator in the formatStr */ 1139 while (*p) { 1140 if (*p == df->patternSeparator) { 1141 *errMsg = tdomstrdup(wrongFormat); 1142 return -1; 1143 } 1144 p++; 1145 } 1146 p = formatStr; 1147 1148 i = 0; 1149 while (*p 1150 && (*p!=df->zeroDigit) 1151 && (*p!=df->digit) 1152 && (*p!=df->groupingSeparator) 1153 && (*p!=df->decimalSeparator)) { 1154 if (i<79) { prefix[i++] = *p; } 1155 p++; 1156 } 1157 prefix[i] = '\0'; 1158 nHash = nZero = fHash = fZero = 0; 1159 gLen = -2222; 1160 while (*p) { 1161 if (*p==df->digit) { 1162 if (nZero) {*errMsg = tdomstrdup(wrongFormat); return -1;} 1163 nHash++;} 1164 else if (*p==df->zeroDigit) { nZero++; } 1165 else if (*p==df->groupingSeparator) { gLen=-1; } 1166 else break; 1167 p++; gLen++; 1168 } 1169 if (*p && (*p==df->decimalSeparator)) { 1170 p++; 1171 while (*p && (*p==df->zeroDigit)) { p++; fZero++; } 1172 while (*p && (*p==df->digit)) { p++; fHash++; } 1173 } 1174 i = 0; 1175 while (*p) { 1176 if (i<79) { suffix[i++] = *p; } 1177 p++; 1178 } 1179 suffix[i] = '\0'; 1180 if (save) *p = save; 1181 1182 if (isNeg && negformat) { 1183 /* Only prefix and suffix are taken from the second format string */ 1184 p++; 1185 i = 0; 1186 while (*p 1187 && *p!=df->zeroDigit 1188 && *p!=df->digit 1189 && *p!=df->groupingSeparator 1190 && *p!=df->decimalSeparator) { 1191 if (i<79) { prefix[i++] = *p; } 1192 p++; 1193 } 1194 prefix[i] = '\0'; 1195 while (*p 1196 && ((*p==df->zeroDigit) 1197 || (*p==df->digit) 1198 || (*p==df->groupingSeparator) 1199 || (*p==df->decimalSeparator))) p++; 1200 i = 0; 1201 while (*p) { 1202 if (i<79) { suffix[i++] = *p; } 1203 p++; 1204 } 1205 suffix[i] = '\0'; 1206 } 1207 1208 if (isNeg) { 1209 if (negformat) { 1210 if (prefix[0]=='\0' && suffix[0]=='\0') { 1211 prefix[0] = df->minusSign; 1212 prefix[1] = '\0'; 1213 } 1214 } else { 1215 i = 0; 1216 save = prefix[0]; 1217 prefix[0] = df->minusSign; 1218 while (i < 79) { 1219 i++; 1220 if (save == '\0') { 1221 prefix[i] = save; 1222 break; 1223 } 1224 save1 = prefix[i]; 1225 prefix[i] = save; 1226 save = save1; 1227 } 1228 if (i == 79) prefix[79] = '\0'; 1229 } 1230 } 1231 if (prefix[0]=='\xc2' && prefix[1]=='\xa4') { 1232/* lc = localeconv(); */ 1233/* if (strlen (lc->currency_symbol) > 79 */ 1234/* || lc->currency_symbol[0] == '\0') { */ 1235 prefix[0] = '$'; 1236 prefix[1] = '\0'; 1237/* } else { */ 1238/* strcpy (prefix, lc->currency_symbol); */ 1239/* } */ 1240 } 1241 1242 if (suffix[0] == df->percent) { 1243 number *= 100.0; 1244 } else 1245 if (suffix[0]=='\xe2' && suffix[1]=='\x80' && suffix[2]=='\xb0') { 1246 number *= 1000.0; 1247 } 1248 1249 if (fHash + fZero == 0) { 1250 i = (int) (number+0.5); 1251 } else { 1252 i = (int) number; 1253 } 1254 DBG(fprintf(stderr,"normal part nZero=%d i=%d glen=%d\n", nZero, i, gLen);) 1255 /* fill in grouping char */ 1256 if (gLen > 0) { 1257 if (i < 0.0) {isNeg = 1; i *= -1;} 1258 else isNeg = 0; 1259 sprintf(s,"%0*d", nZero, i); 1260 l = strlen(s); 1261 /* if (l > (nHash+nZero)) { l = nHash+nZero; } */ 1262 DBG(fprintf(stderr,"s='%s isNeg=%d'\n", s, isNeg);) 1263 zl = l + ((l-1) / gLen); 1264 DBG(fprintf(stderr, "l=%d zl=%d \n", l, zl);) 1265 n[zl--] = '\0'; 1266 p = s + strlen(s) -1; 1267 g = 0; 1268 while (zl>=0) { 1269 g++; 1270 n[zl--] = *p--; 1271 if ((g == gLen) && (zl>=1)) { 1272 n[zl--] = df->groupingSeparator; 1273 g = 0; 1274 } 1275 } 1276 DBG(fprintf(stderr,"s='%s' --> n='%s'\n", s, n);) 1277 1278 } else { 1279 sprintf(n,"%0*d", nZero, i); 1280 DBG(fprintf(stderr,"n='%s'\n", n);) 1281 } 1282 1283 DBG(fprintf(stderr, "number=%f Hash=%d fZero=%d \n", number, fHash, fZero);) 1284 if ((fHash+fZero) > 0) { 1285 i = (int) number; 1286 /* format fraction part */ 1287 if (number >= 0.0) { 1288 sprintf(f,"%0.*f", fZero+fHash, number -i); 1289 } else { 1290 sprintf(f,"%0.*f", fZero+fHash, -1.0 * (number -i) ); 1291 } 1292 l = strlen(f); 1293 while (l>0 && fHash>0) { /* strip not need 0's */ 1294 if (f[l-1] == '0') { 1295 f[l-1]='\0'; l--; fHash--; 1296 } else { 1297 break; 1298 } 1299 } 1300 DBG(fprintf(stderr, "f='%s'\n", f);) 1301 sprintf(s,"%s%s%c%s%s", prefix, n, df->decimalSeparator, &(f[2]), suffix); 1302 } else { 1303 sprintf(s,"%s%s%s", prefix, n, suffix); 1304 } 1305 DBG(fprintf(stderr, "returning s='%s' \n\n", s);) 1306 *resultStr = tdomstrdup(s); 1307 *resultLen = strlen(s); 1308 return 0; 1309} 1310 1311#else 1312 1313static int addCurrencySymbol ( 1314 Tcl_UniChar *p, 1315 Tcl_UniChar *result, 1316 int *i 1317) 1318{ 1319 Tcl_DString dStr; 1320 Tcl_UniChar *p1, *currencySymbol; 1321 int move = 0; 1322 struct lconv *lc; 1323 1324 setlocale (LC_MONETARY, ""); 1325 lc = localeconv(); 1326 Tcl_DStringInit (&dStr); 1327 if (*(p+1) == 0xa4) { 1328 if (lc->int_curr_symbol[0] == '\0') { 1329 currencySymbol = Tcl_UtfToUniCharDString ("$", -1, &dStr); 1330 } else { 1331 currencySymbol = 1332 Tcl_UtfToUniCharDString (lc->int_curr_symbol, -1, &dStr); 1333 } 1334 move = 1; 1335 } else { 1336 if (lc->currency_symbol[0] == '\0') { 1337 currencySymbol = Tcl_UtfToUniCharDString ("$", -1, &dStr); 1338 } else { 1339 currencySymbol = 1340 Tcl_UtfToUniCharDString (lc->currency_symbol, -1, &dStr); 1341 } 1342 } 1343 p1 = currencySymbol; 1344 while (*p1 && (*i < 79)) { 1345 result[(*i)++] = *p1; 1346 p1++; 1347 } 1348 Tcl_DStringFree (&dStr); 1349 return move; 1350} 1351 1352static int xsltFormatNumber ( 1353 double number, 1354 char * formatStr, 1355 xsltDecimalFormat * df, 1356 char ** resultStr, 1357 int * resultLen, 1358 char ** errMsg 1359) 1360{ 1361 Tcl_UniChar prefix1[800], prefix2[800], suffix1[800], suffix2[800]; 1362 Tcl_UniChar save = '\0', save1, t, *prefix, *suffix, n[800], f[800]; 1363 Tcl_UniChar uniCharNull = '\0'; 1364 char stmp[240], ftmp[80]; 1365 char wrongFormat[] = "Unable to interpret format pattern."; 1366 int i, j, k, l, zl, g, nHash, nZero, fHash, fZero, gLen, isNeg; 1367 int prefixMinux, percentMul = 0, perMilleMul = 0; 1368 Tcl_DString dStr, s; 1369 Tcl_UniChar *format, *negformat = NULL, *p, *p1; 1370 DBG(Tcl_DString dbStr;) 1371 1372 DBG(fprintf(stderr, "number: '%f'\nformatStr='%s' \n", number, formatStr);) 1373 prefix1[0] = '\0'; 1374 prefix2[0] = '\0'; 1375 suffix1[0] = '\0'; 1376 suffix2[0] = '\0'; 1377 n[0] = '\0'; 1378 f[0] = '\n'; 1379 prefix = NULL; 1380 suffix = NULL; 1381 Tcl_DStringInit (&s); 1382 Tcl_DStringInit (&dStr); 1383 if (number < 0.0) { 1384 isNeg = 1; 1385 number *= -1.0; 1386 } else if (number == 0.0) { 1387 sprintf (stmp, "%f", number); 1388 if (stmp[0] == '-') isNeg = 1; 1389 else isNeg = 0; 1390 } else { 1391 isNeg = 0; 1392 } 1393 format = Tcl_UtfToUniCharDString (formatStr, -1, &dStr); 1394 p = format; 1395 while (*p) { 1396 if (*p == df->patternSeparator) { 1397 save = *p; 1398 *p = '\0'; 1399 negformat = ++p; 1400 break; 1401 } 1402 p++; 1403 } 1404 /* Check for more than one patternSeparator in the formatStr */ 1405 while (*p) { 1406 if (*p == df->patternSeparator) { 1407 *errMsg = 1408 tdomstrdup("More than one patternSeparator in the pattern"); 1409 goto xsltFormatNumberError; 1410 } 1411 p++; 1412 } 1413 p = format; 1414 1415 i = 0; 1416 while (*p 1417 && (*p!=df->zeroDigit) 1418 && (*p!=df->digit) 1419 && (*p!=df->groupingSeparator) 1420 && (*p!=df->decimalSeparator)) { 1421 if (*p == df->percent) (percentMul = 1); 1422 else if (*p == df->perMille) (perMilleMul = 1); 1423 if (i<79) { 1424 if (*p == 0xa4) { 1425 p += addCurrencySymbol (p, prefix1, &i); 1426 } else { 1427 prefix1[i++] = *p; 1428 } 1429 } 1430 p++; 1431 } 1432 prefix1[i] = '\0'; 1433 nHash = nZero = fHash = fZero = 0; 1434 gLen = -2222; 1435 while (*p) { 1436 if (*p==df->digit) { 1437 if (nZero) { 1438 *errMsg = tdomstrdup(wrongFormat); 1439 goto xsltFormatNumberError; 1440 } 1441 nHash++; 1442 } 1443 else if (*p==df->zeroDigit) { nZero++; } 1444 else if (*p==df->groupingSeparator) { gLen=-1; } 1445 else break; 1446 p++; gLen++; 1447 } 1448 if (*p && (*p==df->decimalSeparator)) { 1449 p++; 1450 while (*p && (*p==df->zeroDigit)) { p++; fZero++; } 1451 while (*p && (*p==df->digit)) { p++; fHash++; } 1452 } 1453 i = 0; 1454 while (*p) { 1455 /* Check for more than one decimalSeparator */ 1456 if (*p == df->decimalSeparator) { 1457 *errMsg = 1458 tdomstrdup("More than one decimalSeparator in subpattern"); 1459 goto xsltFormatNumberError; 1460 } 1461 /* Check for groupingSeparator after decimalSeparator */ 1462 if (*p == df->groupingSeparator) { 1463 *errMsg = tdomstrdup("GroupingSeparator after decimalSeparator"); 1464 goto xsltFormatNumberError; 1465 } 1466 if (*p == df->percent) (percentMul = 1); 1467 else if (*p == df->perMille) (perMilleMul = 1); 1468 if (i<79) { 1469 if (*p == 0xa4) { 1470 p += addCurrencySymbol (p, suffix1, &i); 1471 } else { 1472 suffix1[i++] = *p; 1473 } 1474 } 1475 p++; 1476 } 1477 suffix1[i] = '\0'; 1478 if (save) *p = save; 1479 1480 if (isNeg && negformat) { 1481 /* Only prefix and suffix are taken from the second format string */ 1482 percentMul = 0; perMilleMul = 0; 1483 p++; 1484 i = 0; 1485 while (*p 1486 && *p!=df->zeroDigit 1487 && *p!=df->digit 1488 && *p!=df->groupingSeparator 1489 && *p!=df->decimalSeparator) { 1490 if (*p == df->percent) (percentMul = 1); 1491 else if (*p == df->perMille) (perMilleMul = 1); 1492 if (i<79) { 1493 if (*p == 0xa4) { 1494 p += addCurrencySymbol (p, prefix2, &i); 1495 } else { 1496 prefix2[i++] = *p; 1497 } 1498 } 1499 p++; 1500 } 1501 prefix2[i] = '\0'; 1502 while (*p 1503 && ((*p==df->zeroDigit) 1504 || (*p==df->digit) 1505 || (*p==df->groupingSeparator) 1506 || (*p==df->decimalSeparator))) p++; 1507 i = 0; 1508 while (*p) { 1509 if (*p == df->percent) (percentMul = 1); 1510 else if (*p == df->perMille) (perMilleMul = 1); 1511 if (i<79) { 1512 if (*p == 0xa4) { 1513 p += addCurrencySymbol (p, suffix2, &i); 1514 } else { 1515 suffix2[i++] = *p; 1516 } 1517 } 1518 p++; 1519 } 1520 suffix2[i] = '\0'; 1521 } 1522 1523 if (isNeg) { 1524 if (negformat) { 1525 prefixMinux = 1; 1526 p = prefix1; 1527 p1 = prefix2; 1528 while (prefixMinux) { 1529 if (*p != *p1) { 1530 prefixMinux = 0; 1531 break; 1532 } 1533 if (*p == 0) break; 1534 p++; p1++; 1535 } 1536 if (prefixMinux) { 1537 p = suffix1; 1538 p1 = suffix2; 1539 while (prefixMinux) { 1540 if (*p != *p1) { 1541 prefixMinux = 0; 1542 break; 1543 } 1544 if (*p == 0) break; 1545 p++; p1++; 1546 } 1547 } 1548 prefix = prefix2; 1549 suffix = suffix2; 1550 } else { 1551 prefixMinux = 1; 1552 prefix = prefix1; 1553 suffix = suffix1; 1554 } 1555 if (prefixMinux) { 1556 i = 0; 1557 save = prefix[0]; 1558 prefix[0] = df->minusSign; 1559 while (i < 79) { 1560 i++; 1561 save1 = prefix[i]; 1562 prefix[i] = save; 1563 if (save == 0) break; 1564 save = save1; 1565 } 1566 if (i == 79) prefix[79] = '\0'; 1567 } 1568 } else { 1569 prefix = prefix1; 1570 suffix = suffix1; 1571 } 1572 1573 DBG( 1574 Tcl_DStringInit (&dbStr); 1575 fprintf (stderr, "prefix: '%s' ", Tcl_UniCharToUtfDString(prefix, Tcl_UniCharLen (prefix), &dbStr)); 1576 Tcl_DStringFree (&dbStr); 1577 Tcl_DStringInit (&dbStr); 1578 fprintf (stderr, "suffix: '%s'\n", Tcl_UniCharToUtfDString(suffix, Tcl_UniCharLen (suffix), &dbStr)); 1579 Tcl_DStringFree (&dbStr); 1580 ) 1581 1582 if (percentMul) { 1583 number *= 100.0; 1584 } else if (perMilleMul) { 1585 number *= 1000.0; 1586 } 1587 1588 if (fHash + fZero == 0) { 1589 i = (int) (number+0.5); 1590 } else { 1591 i = (int) number; 1592 /* format fraction part */ 1593 DBG(fprintf(stderr, "formating fraction part: '%f', fZero+fHash: '%d'\n", 1594 number - i, fZero+fHash);) 1595 sprintf(ftmp,"%.*f", fZero+fHash, number -i); 1596 DBG(fprintf(stderr, "raw formated fraction part: '%s'\n", ftmp);) 1597 if (ftmp[0] == '1') { 1598 i++; 1599 } 1600 } 1601 1602 DBG(fprintf(stderr,"normal part nZero=%d i=%d glen=%d\n", nZero, i, gLen);) 1603 /* fill in grouping char */ 1604 if (gLen > 0) { 1605 sprintf(stmp,"%0*d", nZero, i); 1606 l = strlen (stmp); 1607 for (j = 0; j < l; j++) { 1608 t = df->zeroDigit + stmp[j] - 48; 1609 Tcl_DStringAppend (&s, (char*)&t, sizeof (Tcl_UniChar)); 1610 } 1611 DBG( 1612 Tcl_DStringInit(&dbStr); 1613 fprintf (stderr, "'%s' ---> ..\n", stmp); 1614 fprintf(stderr,"s='%s' isNeg=%d'\n", 1615 Tcl_UniCharToUtfDString ( 1616 (Tcl_UniChar*)Tcl_DStringValue (&s), 1617 Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), &dStr 1618 ), 1619 isNeg); 1620 Tcl_DStringFree (&dbStr); 1621 ) 1622 zl = l + ((l-1) / gLen); 1623 DBG(fprintf(stderr, "l=%d zl=%d \n", l, zl);) 1624 n[zl--] = '\0'; 1625 p = (Tcl_UniChar*)Tcl_DStringValue (&s) + l - 1; 1626 g = 0; 1627 while (zl>=0) { 1628 g++; 1629 n[zl--] = *p--; 1630 if ((g == gLen) && (zl>=1)) { 1631 n[zl--] = df->groupingSeparator; 1632 g = 0; 1633 } 1634 } 1635 Tcl_DStringSetLength (&s, 0); 1636 DBG( 1637 Tcl_DStringInit (&dbStr); 1638 fprintf(stderr,"s='%s' --> ", 1639 Tcl_UniCharToUtfDString ( 1640 (Tcl_UniChar*)Tcl_DStringValue (&s), 1641 Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), 1642 &dStr)); 1643 Tcl_DStringFree (&dbStr); 1644 Tcl_DStringInit (&dbStr); 1645 fprintf(stderr,"n='%s'\n", 1646 Tcl_UniCharToUtfDString (n, Tcl_UniCharLen (n), &dbStr)); 1647 Tcl_DStringFree (&dbStr); 1648 ) 1649 } else { 1650 sprintf(stmp,"%0*d", nZero, i); 1651 l = strlen (stmp); 1652 for (j = 0; j < l; j++) { 1653 n[j] = df->zeroDigit + (int) stmp[j] - 48; 1654 } 1655 n[l] = '\0'; 1656 DBG( 1657 Tcl_DStringInit (&dbStr); 1658 fprintf(stderr,"n='%s'\n", 1659 Tcl_UniCharToUtfDString(n, Tcl_UniCharLen (n), &dbStr)); 1660 Tcl_DStringFree (&dbStr); 1661 ) 1662 } 1663 DBG(fprintf(stderr, "number=%f fHash=%d fZero=%d \n", number, fHash, 1664 fZero);) 1665 if ((fHash+fZero) > 0) { 1666 l = strlen(ftmp); 1667 while (l>0 && fHash>0) { /* strip not need 0's */ 1668 if (ftmp[l-1] == '0') { 1669 ftmp[l-1]='\0'; l--; fHash--; 1670 } else { 1671 break; 1672 } 1673 } 1674 k = 0; 1675 if ((number - i != 0.0) || (fZero > 0)) { 1676 while (ftmp[k] != '.') k++; 1677 k++; 1678 for (j = k ; j < l; j++) { 1679 f[j] = df->zeroDigit + (int) ftmp[j] - 48; 1680 } 1681 f[l] = '\0'; 1682 } 1683 DBG(fprintf(stderr, "f='%s'\n", f);) 1684 1685 if (prefix) { 1686 Tcl_DStringAppend (&s, (char*) prefix, 1687 Tcl_UniCharLen (prefix) * sizeof(Tcl_UniChar)); 1688 } 1689 Tcl_DStringAppend (&s, (char*) n, 1690 Tcl_UniCharLen (n) * sizeof(Tcl_UniChar)); 1691 if (k) { 1692 Tcl_DStringAppend (&s, (char*)&df->decimalSeparator, 1693 sizeof (Tcl_UniChar)); 1694 Tcl_DStringAppend (&s, (char*)&(f[k]), 1695 Tcl_UniCharLen (&(f[k])) * sizeof(Tcl_UniChar)); 1696 } 1697 if (suffix) { 1698 Tcl_DStringAppend (&s, (char *) suffix, 1699 Tcl_UniCharLen (suffix) * sizeof(Tcl_UniChar)); 1700 } 1701 Tcl_DStringAppend (&s, (char *)&uniCharNull, sizeof (Tcl_UniChar)); 1702 } else { 1703 if (prefix) { 1704 Tcl_DStringAppend (&s, (char*) prefix, 1705 Tcl_UniCharLen (prefix) * sizeof(Tcl_UniChar)); 1706 } 1707 Tcl_DStringAppend (&s, (char*) n, 1708 Tcl_UniCharLen (n) * sizeof(Tcl_UniChar)); 1709 if (suffix) { 1710 Tcl_DStringAppend (&s, (char *) suffix, 1711 Tcl_UniCharLen (suffix) * sizeof(Tcl_UniChar)); 1712 } 1713 Tcl_DStringAppend (&s, (char *)&uniCharNull, sizeof (Tcl_UniChar)); 1714 } 1715 DBG( 1716 Tcl_DStringInit (&dbStr); 1717 fprintf(stderr, "returning s='%s' \n\n", 1718 Tcl_UniCharToUtfDString( 1719 (Tcl_UniChar*)Tcl_DStringValue (&s), 1720 Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), &dStr 1721 )); 1722 Tcl_DStringFree (&dbStr); 1723 ) 1724 Tcl_DStringSetLength (&dStr, 0); 1725 *resultStr = tdomstrdup( 1726 Tcl_UniCharToUtfDString( 1727 (Tcl_UniChar*)Tcl_DStringValue (&s), 1728 Tcl_UniCharLen((Tcl_UniChar*)Tcl_DStringValue(&s)), &dStr 1729 ) 1730 ); 1731 Tcl_DStringFree (&dStr); 1732 Tcl_DStringFree (&s); 1733 *resultLen = strlen(*resultStr); 1734 return 0; 1735 1736 xsltFormatNumberError: 1737 Tcl_DStringFree (&dStr); 1738 Tcl_DStringFree (&s); 1739 return -1; 1740} 1741 1742#endif /* TclOnly8Bits */ 1743 1744 1745static xsltNodeSet * 1746createXsltNodeSet () 1747{ 1748 xsltNodeSet * ns; 1749 1750 ns = (xsltNodeSet *) MALLOC (sizeof(xsltNodeSet)); 1751 ns->nodes = (domNode**)MALLOC(INITIAL_SIZE_FOR_KEYSETS * sizeof(domNode*)); 1752 ns->allocated = INITIAL_SIZE_FOR_KEYSETS; 1753 ns->nr_nodes = 0; 1754 return ns; 1755} 1756 1757 1758 1759/* Helper proc for buildKeyInfoForDoc. Adds node to the node set ns at 1760 the right position (in document order), if not already 1761 present. This is the same as the core of rsAddNode does. The used 1762 method to add may look a bit simpleminded, but experience shows, 1763 that in the vast majority of the cases node simply has to be 1764 appended to the array. */ 1765 1766static void nsAddNode ( 1767 xsltNodeSet *ns, 1768 domNode *node 1769 ) 1770{ 1771 int insertIndex, i; 1772 1773 insertIndex = ns->nr_nodes; 1774 for (i = ns->nr_nodes - 1; i >= 0; i--) { 1775 if (node == ns->nodes[i]) return; 1776 if (!domPrecedes (node, ns->nodes[i])) { 1777 break; 1778 } 1779 insertIndex--; 1780 } 1781 if (ns->nr_nodes + 1 >= ns->allocated) { 1782 ns->nodes = (domNode**)REALLOC((void*)ns->nodes, 1783 2 * ns->allocated * sizeof(domNode*)); 1784 ns->allocated *= 2; 1785 } 1786 if (insertIndex == ns->nr_nodes) { 1787 ns->nodes[ns->nr_nodes++] = node; 1788 } else { 1789 for (i = ns->nr_nodes - 1; i >= insertIndex; i--) { 1790 ns->nodes[i+1] = ns->nodes[i]; 1791 } 1792 ns->nodes[insertIndex] = node; 1793 ns->nr_nodes++; 1794 } 1795} 1796 1797static int buildKeyInfoForDoc ( 1798 xsltSubDoc *sd, 1799 char *keyId, 1800 Tcl_HashTable *keyInfos, 1801 xsltState *xs, 1802 char **errMsg 1803) 1804{ 1805 int hnew, rc, docOrder, i; 1806 char *useValue; 1807 domNode *node, *savedCurrent; 1808 xpathResultSet rs, context; 1809 Tcl_HashTable *valueTable; 1810 Tcl_HashEntry *h; 1811 xsltKeyInfo *kinfo, *kinfoStart; 1812 xsltNodeSet *keyValues; 1813 1814 h = Tcl_FindHashEntry (keyInfos, keyId); 1815 /* key must exist, this is already checked */ 1816 kinfoStart = (xsltKeyInfo *) Tcl_GetHashValue (h); 1817 1818 /* this must be a new entry, no check for hnew==1 needed */ 1819 h = Tcl_CreateHashEntry (&(sd->keyData), keyId, &hnew); 1820 valueTable = (Tcl_HashTable *)MALLOC(sizeof (Tcl_HashTable)); 1821 Tcl_InitHashTable (valueTable, TCL_STRING_KEYS); 1822 Tcl_SetHashValue (h, valueTable); 1823 1824 savedCurrent = xs->current; 1825 node = sd->doc->rootNode; 1826 while (node) { 1827 kinfo = kinfoStart; 1828 while (kinfo) { 1829 rc = xpathMatches (kinfo->matchAst, kinfo->node, node, &(xs->cbs), 1830 errMsg); 1831 if (rc < 0) { 1832 TRACE1("xpathMatches had errors '%s' \n", *errMsg); 1833 return rc; 1834 } 1835 if (rc > 0) { 1836 TRACE("found match for key !\n"); 1837 xpathRSInit (&rs); 1838 xpathRSInit (&context); 1839 rsAddNode (&context, node); 1840 DBG(printXML(node, 0, 2);) 1841 docOrder = 1; 1842 xs->current = node; 1843 rc = xpathEvalSteps (kinfo->useAst, &context, node, 1844 kinfo->node, 0, &docOrder, &(xs->cbs), 1845 &rs, errMsg); 1846 if (rc != XPATH_OK) { 1847 xpathRSFree (&rs); 1848 xpathRSFree (&context); 1849 return rc; 1850 } 1851 DBG(rsPrint(&rs)); 1852 if (rs.type == xNodeSetResult) { 1853 for (i = 0; i < rs.nr_nodes; i++) { 1854 useValue = xpathFuncStringForNode (rs.nodes[i]); 1855 TRACE1("use value = '%s'\n", useValue); 1856 h = Tcl_CreateHashEntry (valueTable, useValue, &hnew); 1857 if (hnew) { 1858 keyValues = createXsltNodeSet(); 1859 } else { 1860 keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); 1861 } 1862 nsAddNode (keyValues, node); 1863 if (hnew) Tcl_SetHashValue (h, keyValues); 1864 FREE(useValue); 1865 } 1866 } 1867 else if (rs.type != EmptyResult) { 1868 useValue = xpathFuncString (&rs); 1869 TRACE1("use value = '%s'\n", useValue); 1870 h = Tcl_CreateHashEntry (valueTable, useValue, &hnew); 1871 if (hnew) { 1872 keyValues = createXsltNodeSet(); 1873 } else { 1874 keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); 1875 } 1876 nsAddNode (keyValues, node); 1877 if (hnew) Tcl_SetHashValue (h, keyValues); 1878 FREE(useValue); 1879 } 1880 xpathRSFree( &context ); 1881 xpathRSFree( &rs ); 1882 } 1883 kinfo = kinfo->next; 1884 } 1885 if ((node->nodeType == ELEMENT_NODE) && (node->firstAttr)) { 1886 node = (domNode*) node->firstAttr; 1887 continue; 1888 } 1889 if ((node->nodeType == ATTRIBUTE_NODE)) { 1890 if (((domAttrNode*)node)->nextSibling) { 1891 node = (domNode*) ((domAttrNode*)node)->nextSibling; 1892 continue; 1893 } 1894 node = ((domAttrNode*)node)->parentNode; 1895 } 1896 if ((node->nodeType == ELEMENT_NODE) && (node->firstChild)) { 1897 node = node->firstChild; 1898 continue; 1899 } 1900 if (node->nextSibling) { 1901 node = node->nextSibling; 1902 continue; 1903 } 1904 while ( node->parentNode && 1905 (node->parentNode->nextSibling == NULL) ) { 1906 node = node->parentNode; 1907 } 1908 if (node->parentNode) { 1909 node = node->parentNode->nextSibling; 1910 } else { 1911 break; 1912 } 1913 } 1914 xs->current = savedCurrent; 1915 return 0; 1916} 1917 1918 1919/*---------------------------------------------------------------------------- 1920| sortNodeSetByNodeNumber 1921| 1922\---------------------------------------------------------------------------*/ 1923static void sortNodeSetByNodeNumber( 1924 domNode *nodes[], 1925 int n 1926) 1927{ 1928 int i, j, ln, rn; 1929 domNode *tmp; 1930 1931 while (n > 1) { 1932 tmp = nodes[0]; nodes[0] = nodes[n/2]; nodes[n/2] = tmp; 1933 for (i = 0, j = n; ; ) { 1934 do { 1935 --j; 1936 } while (domPrecedes (nodes[0], nodes[j])); 1937 do { 1938 ++i; 1939 } while (i < j && domPrecedes (nodes[i], nodes[0])); 1940 if (i >= j) break; 1941 tmp = nodes[i]; nodes[i] = nodes[j]; nodes[j] = tmp; 1942 } 1943 tmp = nodes[j]; nodes[j] = nodes[0]; nodes[0] = tmp; 1944 ln = j; 1945 rn = n - ++j; 1946 if (ln < rn) { 1947 sortNodeSetByNodeNumber(nodes, ln); 1948 nodes += j; 1949 n = rn; 1950 } else { 1951 sortNodeSetByNodeNumber(&(nodes[j]), rn); 1952 n = ln; 1953 } 1954 } 1955} 1956 1957/*---------------------------------------------------------------------------- 1958| sortByDocOrder 1959| 1960\---------------------------------------------------------------------------*/ 1961void sortByDocOrder ( 1962 xpathResultSet * rs 1963) 1964{ 1965 if (rs->type != xNodeSetResult) return; 1966 sortNodeSetByNodeNumber(rs->nodes, rs->nr_nodes); 1967} 1968 1969/*---------------------------------------------------------------------------- 1970| StripXMLSpace 1971| 1972\---------------------------------------------------------------------------*/ 1973static void StripXMLSpace ( 1974 xsltState * xs, 1975 domNode * node 1976) 1977{ 1978 domNode *child, *newChild, *parent; 1979 int i, len, onlySpace, found, strip; 1980 char *p, prefix[MAX_PREFIX_LEN]; 1981 const char *localName; 1982 double *f; 1983 domNS *ns; 1984 Tcl_HashEntry *h; 1985 Tcl_DString dStr; 1986 1987 1988 if (node->nodeType == TEXT_NODE) { 1989 p = ((domTextNode*)node)->nodeValue; 1990 len = ((domTextNode*)node)->valueLength; 1991 onlySpace = 1; 1992 for (i=0; i<len; i++) { 1993 if (!IS_XML_WHITESPACE(*p)) { 1994 onlySpace = 0; 1995 break; 1996 } 1997 p++; 1998 } 1999 if (onlySpace) { 2000 parent = node->parentNode; 2001 while (parent) { 2002 p = getAttr(parent,"xml:space", a_space); 2003 if (p!=NULL) { 2004 if (strcmp(p,"preserve")==0) return; 2005 if (strcmp(p,"default")==0) break; 2006 } 2007 parent = parent->parentNode; 2008 } 2009 DBG(fprintf(stderr, "removing domNode0x%x(len %d) under '%s' \n", 2010 node, len, node->parentNode->nodeName);) 2011 domDeleteNode (node, NULL, NULL); 2012 } 2013 } else 2014 if (node->nodeType == ELEMENT_NODE) { 2015 if (node->firstChild == NULL) return; 2016 strip = xs->wsInfo.stripAll; 2017 found = 0; 2018 if (node->namespace) { 2019 domSplitQName (node->nodeName, prefix, &localName); 2020 } else { 2021 prefix[0] = '\0'; 2022 localName = node->nodeName; 2023 } 2024 ns = NULL; 2025 Tcl_DStringInit (&dStr); 2026 if (prefix[0] != '\0') { 2027 ns = domLookupPrefix (node, prefix); 2028 if (ns) { 2029 Tcl_DStringAppend (&dStr, ns->uri, -1); 2030 Tcl_DStringAppend (&dStr, ":*", 2); 2031 if (xs->wsInfo.stripAll) { 2032 h = Tcl_FindHashEntry (&xs->wsInfo.preserveTokens, 2033 Tcl_DStringValue (&dStr)); 2034 } else { 2035 h = Tcl_FindHashEntry (&xs->wsInfo.stripTokens, 2036 Tcl_DStringValue (&dStr)); 2037 } 2038 if (h) { 2039 f = Tcl_GetHashValue (h); 2040 if (*f >= xs->wsInfo.wildcardPrec) { 2041 strip = !xs->wsInfo.stripAll; 2042 found = 1; 2043 } 2044 } 2045 if (!found) { 2046 Tcl_DStringFree (&dStr); 2047 Tcl_DStringInit (&dStr); 2048 Tcl_DStringAppend (&dStr, ns->uri, -1); 2049 Tcl_DStringAppend (&dStr, ":", 1); 2050 } 2051 } 2052 } 2053 if (!found) { 2054 Tcl_DStringAppend (&dStr, localName, -1); 2055 if (xs->wsInfo.stripAll) { 2056 h = Tcl_FindHashEntry (&xs->wsInfo.preserveTokens, 2057 Tcl_DStringValue (&dStr)); 2058 } else { 2059 h = Tcl_FindHashEntry (&xs->wsInfo.stripTokens, 2060 Tcl_DStringValue (&dStr)); 2061 } 2062 if (h) { 2063 f = Tcl_GetHashValue (h); 2064 if (*f >= xs->wsInfo.wildcardPrec) { 2065 strip = !xs->wsInfo.stripAll; 2066 } 2067 } 2068 } 2069 Tcl_DStringFree (&dStr); 2070 if (strip) { 2071 child = node->firstChild; 2072 while (child) { 2073 newChild = child->nextSibling; 2074 StripXMLSpace (xs, child); 2075 child = newChild; 2076 } 2077 } else { 2078 child = node->firstChild; 2079 while (child) { 2080 if (child->nodeType == ELEMENT_NODE) { 2081 StripXMLSpace (xs, child); 2082 } 2083 child = child->nextSibling; 2084 } 2085 } 2086 } 2087} 2088 2089/*---------------------------------------------------------------------------- 2090| xsltXPathFuncs 2091| 2092\---------------------------------------------------------------------------*/ 2093static int xsltXPathFuncs ( 2094 void * clientData, 2095 char * funcName, 2096 domNode * ctxNode, 2097 int ctxPos, 2098 xpathResultSet * ctx, 2099 domNode * exprContext, 2100 int argc, 2101 xpathResultSets * argv, 2102 xpathResultSet * result, 2103 char ** errMsg 2104) 2105{ 2106 xsltState * xs = clientData; 2107 char * keyId, *filterValue, *str = NULL; 2108 char prefix[MAX_PREFIX_LEN]; 2109 const char * localName, *baseURI, *nsStr; 2110 int rc, i, len, NaN, freeStr, x; 2111 double n; 2112 xsltNodeSet * keyValues; 2113 Tcl_HashEntry * h; 2114 Tcl_HashTable * docKeyData; 2115 xsltSubDoc * sdoc; 2116 domDocument * ownerDoc; 2117 Tcl_DString dStr; 2118 domNS * ns; 2119 xsltDecimalFormat * df; 2120 2121 DBG ( fprintf(stderr,"xsltXPathFuncs funcName='%s'\n",funcName); ) 2122 2123 if (strcmp(funcName, "key")==0) { 2124 /*-------------------------------------------------------------------- 2125 | 'key' function 2126 \-------------------------------------------------------------------*/ 2127 DBG(fprintf(stderr,"xslt key function called!\n");) 2128 if (argc != 2) { 2129 reportError (exprContext, "key() needs two arguments!", errMsg); 2130 return -1; 2131 } 2132 /* check, if there is a key definition with the given name */ 2133 keyId = xpathFuncString(argv[0]); 2134 TRACE1("keyId='%s' \n", keyId); 2135 domSplitQName (keyId, prefix, &localName); 2136 Tcl_DStringInit (&dStr); 2137 if (prefix[0] != '\0') { 2138 ns = domLookupPrefix (exprContext, prefix); 2139 if (!ns) { 2140 reportError (exprContext, "There isn't a namespace bound to" 2141 " the prefix.", errMsg); 2142 FREE(keyId); 2143 return -1; 2144 } 2145 Tcl_DStringAppend (&dStr, ns->uri, -1); 2146 } 2147 Tcl_DStringAppend (&dStr, localName, -1); 2148 FREE(keyId); 2149 h = Tcl_FindHashEntry (&xs->keyInfos, Tcl_DStringValue (&dStr)); 2150 if (!h) { 2151 reportError (exprContext, "Unknown key in key() function call!", 2152 errMsg); 2153 Tcl_DStringFree (&dStr); 2154 return -1; 2155 } 2156 2157 /* Short cut for empty result sets. */ 2158 if (argv[1]->type == EmptyResult) { 2159 Tcl_DStringFree (&dStr); 2160 return 0; 2161 } 2162 2163 /* find the doc, the context node belongs to */ 2164 sdoc = xs->subDocs; 2165 if (ctxNode->nodeType == ATTRIBUTE_NODE) { 2166 ownerDoc = ((domAttrNode *)ctxNode)->parentNode->ownerDocument; 2167 } else { 2168 ownerDoc = ctxNode->ownerDocument; 2169 } 2170 while (sdoc) { 2171 if (sdoc->doc == ownerDoc) break; 2172 sdoc = sdoc->next; 2173 } 2174 DBG(if (!sdoc) fprintf (stderr, "key() function: ctxNode doesn't belong to a doc out of subDocs!!! This could not happen!. ERROR\n"); 2175 else (fprintf (stderr, "key() function: ctxNode belongs to doc %s\n", sdoc->baseURI));) 2176 2177 h = Tcl_FindHashEntry (&(sdoc->keyData), Tcl_DStringValue (&dStr)); 2178 if (!h) { 2179 if (buildKeyInfoForDoc(sdoc, Tcl_DStringValue (&dStr), 2180 &(xs->keyInfos),xs,errMsg)<0) { 2181 Tcl_DStringFree (&dStr); 2182 return -1; 2183 } 2184 h = Tcl_FindHashEntry (&(sdoc->keyData), Tcl_DStringValue (&dStr)); 2185 } 2186 Tcl_DStringFree (&dStr); 2187 2188 docKeyData = (Tcl_HashTable *) Tcl_GetHashValue (h); 2189 2190 if (argv[1]->type == xNodeSetResult) { 2191 for (i = 0; i < argv[1]->nr_nodes; i++) { 2192 filterValue = xpathFuncStringForNode (argv[1]->nodes[i]); 2193 TRACE1("filterValue='%s' \n", filterValue); 2194 h = Tcl_FindHashEntry (docKeyData, filterValue); 2195 if (h) { 2196 keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); 2197 if (result->type == EmptyResult) { 2198 result->type = xNodeSetResult; 2199 result->nodes = keyValues->nodes; 2200 result->intvalue = 1; 2201 result->nr_nodes = keyValues->nr_nodes; 2202 result->allocated = keyValues->allocated; 2203 } else { 2204 for (x = 0; x < keyValues->nr_nodes; x++) { 2205 rsAddNode(result, keyValues->nodes[x]); 2206 } 2207 } 2208 } 2209 FREE(filterValue); 2210 } 2211 } else { 2212 filterValue = xpathFuncString(argv[1]); 2213 TRACE1("filterValue='%s' \n", filterValue); 2214 h = Tcl_FindHashEntry (docKeyData, filterValue); 2215 if (h) { 2216 keyValues = (xsltNodeSet *) Tcl_GetHashValue (h); 2217 if (result->type == EmptyResult) { 2218 result->type = xNodeSetResult; 2219 result->nodes = keyValues->nodes; 2220 result->intvalue = 1; 2221 result->nr_nodes = keyValues->nr_nodes; 2222 result->allocated = keyValues->allocated; 2223 } else { 2224 for (x = 0; x < keyValues->nr_nodes; x++) { 2225 rsAddNode(result, keyValues->nodes[x]); 2226 } 2227 } 2228 } 2229 FREE(filterValue); 2230 } 2231 return 0; 2232 } else 2233 if (strcmp(funcName, "current")==0) { 2234 /*-------------------------------------------------------------------- 2235 | 'current' function 2236 \-------------------------------------------------------------------*/ 2237 DBG(fprintf(stderr, "xsltXPathFuncs 'current' = 'domNode0x%x' \n", 2238 xs->current);) 2239 if (argc != 0) { 2240 reportError (exprContext, "current() must not have any arguments", 2241 errMsg); 2242 return -1; 2243 } 2244 rsAddNode(result, xs->current); 2245 return 0; 2246 } else 2247 if (strcmp (funcName, "format-number")==0) { 2248 /*-------------------------------------------------------------------- 2249 | 'format-number' function 2250 \-------------------------------------------------------------------*/ 2251 DBG(fprintf(stderr, "before format-number argc=%d \n", argc);) 2252 if (argc == 3) { 2253 str = xpathFuncString (argv[2]); 2254 domSplitQName (str, prefix, &localName); 2255 ns = NULL; 2256 if (prefix[0] != '\0') { 2257 ns = domLookupPrefix (exprContext, prefix); 2258 if (!ns) { 2259 reportError (exprContext, "There isn't a namespace bound" 2260 " to the prefix.", errMsg); 2261 FREE(str); 2262 return -1; 2263 } 2264 } 2265 df = xs->decimalFormats->next; 2266 while (df) { 2267 if (strcmp(df->name, str)==0 2268 && ((df->uri == NULL && ns == NULL) 2269 || (df->uri != NULL 2270 && ns != NULL 2271 && (strcmp (df->uri, ns->uri)==0)))) { 2272 break; 2273 } 2274 df = df->next; 2275 } 2276 FREE(str); 2277 if (df == NULL) { 2278 reportError (exprContext, "There isn't a decimal format with" 2279 " this name.", errMsg); 2280 return -1; 2281 } 2282 } else 2283 if (argc == 2) { 2284 df = xs->decimalFormats; 2285 } else { 2286 reportError (exprContext, "format-number: wrong # parameters:" 2287 " format-number(number, string, ?string?)!", errMsg); 2288 return -1; 2289 } 2290 NaN = 0; 2291 n = xpathFuncNumber (argv[0], &NaN); 2292 if (NaN) { 2293 if (NaN == 2) rsSetString (result, df->NaN); 2294 else if (NaN == 1) rsSetString (result, df->infinity); 2295 else { 2296 Tcl_DStringInit (&dStr); 2297 Tcl_DStringAppend (&dStr, "-", 1); 2298 Tcl_DStringAppend (&dStr, df->infinity, -1); 2299 rsSetString (result, Tcl_DStringValue (&dStr)); 2300 } 2301 return 0; 2302 } 2303 str = xpathFuncString (argv[1]); 2304 DBG(fprintf(stderr, "1 str='%s' \n", str);) 2305 result->type = StringResult; 2306 rc = xsltFormatNumber(n, str, df, &(result->string), 2307 &(result->string_len), errMsg); 2308 FREE(str); 2309 if (rc < 0) { 2310 result->type = EmptyResult; 2311 return rc; 2312 } 2313 DBG(fprintf(stderr, "after format-number \n");) 2314 return 0; 2315 } else 2316 if (strcmp (funcName, "document")==0) { 2317 /*-------------------------------------------------------------------- 2318 | 'document' function 2319 \-------------------------------------------------------------------*/ 2320 DBG(fprintf(stderr, "xsltXPathFuncs 'document' \n");) 2321 if (argc == 1) { 2322 if (argv[0]->type == xNodeSetResult) { 2323 for (i = 0; i < argv[0]->nr_nodes; i++) { 2324 freeStr = 0; 2325 if (argv[0]->nodes[i]->nodeType == ATTRIBUTE_NODE) { 2326 nsStr = ((domAttrNode*)argv[0]->nodes[i])->nodeValue; 2327 baseURI = findBaseURI (((domAttrNode*)argv[0]->nodes[i])->parentNode); 2328 } else { 2329 str = xpathGetStringValue (argv[0]->nodes[i], &len); 2330 nsStr = str; 2331 freeStr = 1; 2332 baseURI = findBaseURI (argv[0]->nodes[i]); 2333 } 2334 /* the case document('') */ 2335 if (*nsStr == '\0') { 2336 if (freeStr) { 2337 FREE(str); 2338 freeStr = 0; 2339 } 2340 nsStr = baseURI; 2341 } 2342 if (xsltAddExternalDocument(xs, baseURI, nsStr, 0, 2343 result, errMsg) < 0) { 2344 if (freeStr) FREE(str); 2345 return -1; 2346 } 2347 if (xs->wsInfo.hasData) { 2348 StripXMLSpace (xs, xs->subDocs->doc->documentElement); 2349 } 2350 if (freeStr) FREE(str); 2351 } 2352 } else { 2353 str = xpathFuncString (argv[0]); 2354 nsStr = str; 2355 if (xs->currentXSLTNode) { 2356 baseURI = findBaseURI (xs->currentXSLTNode); 2357 } else 2358 if (xs->currentTplRule) { 2359 baseURI = findBaseURI (xs->currentTplRule->content); 2360 } else { 2361 baseURI = findBaseURI (xs->xsltDoc->rootNode); 2362 } 2363 if (*nsStr == '\0') { 2364 nsStr = baseURI; 2365 } 2366 DBG (fprintf (stderr, "document() call, with 1 string arg = '%s'\n", str);) 2367 if (xsltAddExternalDocument(xs, baseURI, nsStr, 1, 2368 result, errMsg) < 0) { 2369 FREE(str); 2370 return -1; 2371 } 2372 if (xs->wsInfo.hasData) { 2373 StripXMLSpace (xs, xs->subDocs->doc->documentElement); 2374 } 2375 FREE(str); 2376 } 2377 } else 2378 if (argc == 2) { 2379 if (argv[1]->type != xNodeSetResult) { 2380 reportError (exprContext, "second arg of document() has to be" 2381 " a nodeset!", errMsg); 2382 return -1; 2383 } 2384 if (argv[1]->nodes[0]->nodeType == ATTRIBUTE_NODE) { 2385 baseURI = findBaseURI (((domAttrNode*)argv[1]->nodes[0])->parentNode); 2386 } else { 2387 baseURI = findBaseURI (argv[1]->nodes[0]); 2388 } 2389 if (argv[0]->type == xNodeSetResult) { 2390 for (i = 0; i < argv[0]->nr_nodes; i++) { 2391 freeStr = 0; 2392 if (argv[0]->nodes[i]->nodeType == ATTRIBUTE_NODE) { 2393 nsStr = ((domAttrNode*)argv[0]->nodes[i])->nodeValue; 2394 } else { 2395 str = xpathGetStringValue (argv[0]->nodes[i], &len); 2396 freeStr = 1; 2397 nsStr = str; 2398 } 2399 if (*nsStr == '\0') { 2400 FREE(str); 2401 freeStr = 0; 2402 nsStr = baseURI; 2403 } 2404 if (xsltAddExternalDocument(xs, baseURI, nsStr, 0, 2405 result, errMsg) < 0) { 2406 if (freeStr) FREE(str); 2407 return -1; 2408 } 2409 if (xs->wsInfo.hasData) { 2410 StripXMLSpace (xs, xs->subDocs->doc->documentElement); 2411 } 2412 if (freeStr) FREE(str); 2413 } 2414 } else { 2415 str = xpathFuncString (argv[0]); 2416 nsStr = str; 2417 if (*str == '\0') { 2418 nsStr = baseURI; 2419 } 2420 if (xsltAddExternalDocument(xs, baseURI, nsStr, 0, 2421 result, errMsg) < 0) { 2422 FREE(str); 2423 return -1; 2424 } 2425 if (xs->wsInfo.hasData) { 2426 StripXMLSpace (xs, xs->subDocs->doc->documentElement); 2427 } 2428 FREE(str); 2429 } 2430 } else { 2431 reportError (exprContext, "wrong # of args in document() call!", 2432 errMsg); 2433 return -1; 2434 } 2435 return 0; 2436 } else { 2437 /* chain back to original callback */ 2438 if (xs->orig_funcCB) { 2439 return (xs->orig_funcCB)(xs->orig_funcClientData, funcName, 2440 ctxNode, ctxPos, ctx, exprContext, 2441 argc, argv, result, errMsg); 2442 } 2443 } 2444 return 0; 2445} 2446 2447 2448 2449/*---------------------------------------------------------------------------- 2450| evalXPath 2451| 2452\---------------------------------------------------------------------------*/ 2453static int evalXPath ( 2454 xsltState * xs, 2455 xpathResultSet * context, 2456 domNode * currentNode, 2457 int currentPos, 2458 char * xpath, 2459 xpathResultSet * rs, 2460 char ** errMsg 2461) 2462{ 2463 int rc, hnew, docOrder = 1; 2464 ast t; 2465 domNode *savedCurrent; 2466 Tcl_HashEntry *h; 2467 2468 h = Tcl_CreateHashEntry (&(xs->xpaths), xpath, &hnew); 2469 if (!hnew) { 2470 t = (ast)Tcl_GetHashValue(h); 2471 } else { 2472 rc = xpathParse (xpath, xs->currentXSLTNode, XPATH_EXPR, NULL, NULL, 2473 &t, errMsg); 2474 if (rc < 0) { 2475 reportError (xs->currentXSLTNode, *errMsg, errMsg); 2476 return rc; 2477 } 2478 Tcl_SetHashValue(h, t); 2479 } 2480 xpathRSInit( rs ); 2481 2482 DBG(fprintf (stderr, "evalXPath evaluating xpath:\n");) 2483 DBG(printAst(3,t);) 2484 savedCurrent = xs->current; 2485 xs->current = currentNode; 2486 rc = xpathEvalSteps( t, context, currentNode, xs->currentXSLTNode, 2487 currentPos, &docOrder, &(xs->cbs), rs, errMsg); 2488 xs->current = savedCurrent; 2489 if (rc != XPATH_OK) { 2490 reportError (xs->currentXSLTNode, *errMsg, errMsg); 2491 xpathRSFree( rs ); 2492 } 2493 2494 return rc; 2495} 2496 2497 2498/*---------------------------------------------------------------------------- 2499| nodeGreater 2500| 2501\---------------------------------------------------------------------------*/ 2502static int nodeGreater ( 2503 int typeText, 2504 int asc, 2505 int upperFirst, 2506 char * strA, 2507 char * strB, 2508 double realA, 2509 double realB, 2510 int * greater 2511) 2512{ 2513 int rc; 2514#if TclOnly8Bits == 0 2515 char *strAptr, *strBptr; 2516 int lenA, lenB, len; 2517 Tcl_UniChar unicharA, unicharB; 2518#endif 2519 2520 *greater = 0; 2521 2522 if (typeText) { 2523 2524#if TclOnly8Bits 2525 /* TODO: this only works for 7 bit ASCII */ 2526 rc = STRCASECMP(strA, strB); 2527 if (rc == 0) { 2528 rc = strcmp (strA, strB); 2529 if (!upperFirst) { 2530 rc *= -1; 2531 } 2532 } 2533DBG( fprintf(stderr, "nodeGreater %d <-- strA='%s' strB='%s'\n", rc, strA, strB);) 2534#else 2535 lenA = Tcl_NumUtfChars (strA, -1); 2536 lenB = Tcl_NumUtfChars (strB, -1); 2537 len = (lenA < lenB ? lenA : lenB); 2538 rc = Tcl_UtfNcasecmp (strA, strB, len); 2539 if (rc == 0) { 2540 if (lenA > lenB) { 2541 rc = 1; 2542 } else if (lenA < lenB) { 2543 rc = -1; 2544 } 2545 } 2546 if (rc == 0) { 2547 strAptr = strA; 2548 strBptr = strB; 2549 while (len-- > 0) { 2550 strAptr += Tcl_UtfToUniChar(strAptr, &unicharA); 2551 strBptr += Tcl_UtfToUniChar(strBptr, &unicharB); 2552 if (unicharA != unicharB) { 2553 rc = unicharA - unicharB; 2554 break; 2555 } 2556 } 2557 if (!upperFirst) { 2558 rc *= -1; 2559 } 2560 } 2561#endif 2562 if (asc) *greater = (rc > 0); 2563 else *greater = (rc < 0); 2564 2565 } else { 2566DBG( fprintf(stderr, "nodeGreater realA='%f' realB='%f'\n",realA, realB);) 2567 if (IS_NAN (realA) || IS_NAN (realB)) { 2568 if (asc) { 2569 if (IS_NAN (realA) && !IS_NAN (realB)) { 2570 *greater = 0; 2571 } else { 2572 if (IS_NAN (realB) && !IS_NAN (realA)) *greater = 1; 2573 } 2574 } else { 2575 if (IS_NAN (realA) && !IS_NAN(realB)) { 2576 *greater = 1; 2577 } else { 2578 if (IS_NAN (realB) && !IS_NAN(realA)) *greater = 0; 2579 } 2580 } 2581 } else { 2582 if (asc) *greater = (realA > realB); 2583 else *greater = (realA < realB); 2584 } 2585 } 2586 return 0; 2587} 2588 2589static int fastMergeSort ( 2590 int txt, 2591 int asc, 2592 int upperFirst, 2593 domNode * a[], 2594 int * posa, 2595 domNode * b[], 2596 int * posb, 2597 char ** vs, 2598 double * vd, 2599 char ** vstmp, 2600 double * vdtmp, 2601 int size, 2602 char ** errMsg 2603) { 2604 domNode *tmp; 2605 int tmpPos, lptr, rptr, middle, i, j, gt, rc; 2606 char *tmpVs; 2607 double tmpVd; 2608 2609 if (size < 10) { 2610 /* use simple and fast insertion for small sizes ! */ 2611 for (i = 1; i < size; i++) { 2612 tmp = a [i]; 2613 tmpPos = posa [i]; 2614 tmpVs = vs [i]; 2615 tmpVd = vd [i]; 2616 j = i; 2617 if (j>0) { 2618 rc = nodeGreater(txt, asc, upperFirst, vs[j-1], tmpVs, 2619 vd[j-1], tmpVd, >); 2620 CHECK_RC; 2621 } 2622 while ( j > 0 && gt) { 2623 a [j] = a [j-1]; 2624 posa[j] = posa[j-1]; 2625 vs [j] = vs [j-1]; 2626 vd [j] = vd [j-1]; 2627 j--; 2628 if (j>0) { 2629 rc = nodeGreater(txt, asc, upperFirst, vs[j-1], tmpVs, 2630 vd[j-1], tmpVd, >); 2631 CHECK_RC; 2632 } 2633 } 2634 a [j] = tmp; 2635 posa[j] = tmpPos; 2636 vs [j] = tmpVs; 2637 vd [j] = tmpVd; 2638 } 2639 return 0; 2640 } 2641 middle = size/2; 2642 2643 rc = fastMergeSort(txt, asc, upperFirst, a, posa, b, posb, vs, vd, 2644 vstmp, vdtmp, middle, errMsg); 2645 CHECK_RC; 2646 rc = fastMergeSort(txt, asc, upperFirst, a+middle, posa+middle, b+middle, 2647 posb+middle, vs+middle, vd+middle, vstmp+middle, 2648 vdtmp+middle, size-middle, errMsg); 2649 CHECK_RC; 2650 2651 lptr = 0; 2652 rptr = middle; 2653 2654 for (i = 0; i < size; i++) { 2655 if (lptr == middle) { 2656 b [i] = a [rptr ]; 2657 posb [i] = posa[rptr ]; 2658 vstmp[i] = vs [rptr ]; 2659 vdtmp[i] = vd [rptr++]; 2660 } else if (rptr < size) { 2661 rc = nodeGreater(txt, asc, upperFirst, vs[lptr], vs[rptr], 2662 vd[lptr], vd[rptr], >); 2663 if (gt) { 2664 b [i] = a [rptr ]; 2665 posb [i] = posa[rptr ]; 2666 vstmp[i] = vs [rptr ]; 2667 vdtmp[i] = vd [rptr++]; 2668 } else { 2669 b [i] = a [lptr ]; 2670 posb [i] = posa[lptr ]; 2671 vstmp[i] = vs [lptr ]; 2672 vdtmp[i] = vd [lptr++]; 2673 } 2674 } else { 2675 b [i] = a [lptr ]; 2676 posb [i] = posa[lptr ]; 2677 vstmp[i] = vs [lptr ]; 2678 vdtmp[i] = vd [lptr++]; 2679 } 2680 } 2681 memcpy(a, b, size*sizeof(domNode*)); 2682 memcpy(posa, posb, size*sizeof(int*)); 2683 memcpy(vs, vstmp, size*sizeof(char*)); 2684 memcpy(vd, vdtmp, size*sizeof(double)); 2685 return 0; 2686} 2687 2688static int sortNodeSetFastMerge( 2689 int txt, 2690 int asc, 2691 int upperFirst, 2692 domNode * nodes[], 2693 int n, 2694 char ** vs, 2695 double * vd, 2696 int * pos, 2697 char ** errMsg 2698) 2699{ 2700 domNode **b; 2701 int *posb; 2702 char **vstmp; 2703 double *vdtmp; 2704 int rc; 2705 2706 b = (domNode **)MALLOC(n * sizeof(domNode *)); 2707 posb = (int *)MALLOC(n * sizeof(int)); 2708 vstmp = (char **)MALLOC(sizeof (char *) * n); 2709 vdtmp = (double *)MALLOC(sizeof (double) * n); 2710 2711 rc = fastMergeSort(txt, asc, upperFirst, nodes, pos, b, posb, vs, vd, 2712 vstmp, vdtmp, n, errMsg); 2713 FREE((char*)posb); 2714 FREE((char*)b); 2715 FREE((char*)vstmp); 2716 FREE((char*)vdtmp); 2717 CHECK_RC; 2718 return 0; 2719} 2720 2721/*---------------------------------------------------------------------------- 2722| xsltSetVar 2723| 2724\---------------------------------------------------------------------------*/ 2725static int xsltSetVar ( 2726 xsltState * xs, 2727 char * variableName, 2728 xpathResultSet * context, 2729 domNode * currentNode, 2730 int currentPos, 2731 char * select, 2732 domNode * actionNode, 2733 int active, 2734 char ** errMsg 2735) 2736{ 2737 xsltVariable * var; 2738 int rc; 2739 xpathResultSet rs; 2740 xsltVarFrame *tmpFrame = NULL; 2741 domNode *fragmentNode, *savedLastNode; 2742 char prefix[MAX_PREFIX_LEN]; 2743 const char *localName; 2744 domNS *ns; 2745 2746 TRACE1("xsltSetVar variableName='%s' \n", variableName); 2747 if (select!=NULL) { 2748 TRACE2("xsltSetVar variableName='%s' select='%s'\n", variableName, select); 2749 rc = evalXPath (xs, context, currentNode, currentPos, select, &rs, 2750 errMsg); 2751 CHECK_RC; 2752 } else { 2753 if (!actionNode->firstChild) { 2754 xpathRSInit (&rs); 2755 rsSetString (&rs, ""); 2756 } else { 2757 fragmentNode = domNewElementNode(xs->resultDoc, "", 2758 ELEMENT_NODE); 2759 savedLastNode = xs->lastNode; 2760 xs->lastNode = fragmentNode; 2761 /* process the children as well */ 2762 xsltPushVarFrame (xs); 2763 rc = ExecActions(xs, context, currentNode, currentPos, 2764 actionNode->firstChild, errMsg); 2765 xsltPopVarFrame (xs); 2766 CHECK_RC; 2767 xpathRSInit(&rs); 2768 rsAddNodeFast(&rs, fragmentNode); 2769 xs->lastNode = savedLastNode; 2770 } 2771 } 2772 tmpFrame = &xs->varFramesStack[xs->varFramesStackPtr]; 2773 2774 xs->varStackPtr++; 2775 if (xs->varStackPtr >= xs->varStackLen) { 2776 xs->varStack = (xsltVariable *) REALLOC ((char*)xs->varStack, 2777 sizeof (xsltVariable) 2778 * 2 * xs->varStackLen); 2779 xs->varStackLen *= 2; 2780 } 2781 var = &(xs->varStack[xs->varStackPtr]); 2782 if (tmpFrame->varStartIndex == -1) { 2783 tmpFrame->varStartIndex = xs->varStackPtr; 2784 } 2785 tmpFrame->nrOfVars++; 2786 domSplitQName (variableName, prefix, &localName); 2787 if (prefix[0] != '\0') { 2788 ns = domLookupPrefix (actionNode, prefix); 2789 if (!ns) { 2790 reportError (actionNode, "There isn't a namespace bound to" 2791 " the prefix.", errMsg); 2792 return -1; 2793 } 2794 var->uri = ns->uri; 2795 var->name = localName; 2796 } else { 2797 var->uri = NULL; 2798 var->name = variableName; 2799 } 2800 tmpFrame->polluted = 1; 2801 var->node = actionNode; 2802 var->rs = rs; 2803 var->active = active; 2804 DBG(rsPrint(&(var->rs))); 2805 return 0; 2806} 2807 2808/*---------------------------------------------------------------------------- 2809| xsltVarExists 2810| 2811\---------------------------------------------------------------------------*/ 2812static int xsltVarExists ( 2813 xsltState * xs, 2814 char * variableName, 2815 domNode * exprContext 2816) 2817{ 2818 int i, frameIndex, found = 0; 2819 char prefix[MAX_PREFIX_LEN]; 2820 const char *localName, *uri, *varName; 2821 domNS *ns; 2822 xsltVarFrame *frame; 2823 2824 TRACE1("xsltVarExists variableName='%s' \n", variableName); 2825 domSplitQName (variableName, prefix, &localName); 2826 if (prefix[0]) { 2827 ns = domLookupPrefix (exprContext, prefix); 2828 if (!ns) { 2829 /* TODO: this is an error, not only 'not found' */ 2830 return 0; 2831 } 2832 uri = ns->uri; 2833 varName = localName; 2834 } else { 2835 uri = NULL; 2836 varName = variableName; 2837 } 2838 frameIndex = xs->varFramesStackPtr; 2839 while (frameIndex >= 0) { 2840 frame = &xs->varFramesStack[frameIndex]; 2841 for (i = frame->varStartIndex; 2842 i < frame->varStartIndex + frame->nrOfVars; 2843 i++) { 2844 if ( (uri && !((&xs->varStack[i])->uri)) 2845 || (!uri && (&xs->varStack[i])->uri) 2846 || (uri && (&xs->varStack[i])->uri 2847 && (strcmp (uri, (&xs->varStack[i])->uri)!=0)) 2848 ) continue; 2849 if (strcmp((&xs->varStack[i])->name, varName)==0) { 2850 found = 1; 2851 (&xs->varStack[i])->active = 1; 2852 break; /* found the variable */ 2853 } 2854 } 2855 if (found) return 1; 2856 if (frame->stop) break; 2857 frameIndex--; 2858 } 2859 2860 return 0; 2861} 2862 2863 2864/*---------------------------------------------------------------------------- 2865| xsltGetVar 2866| 2867\---------------------------------------------------------------------------*/ 2868static int xsltGetVar ( 2869 void * clientData, 2870 char * variableName, 2871 char * varURI, 2872 xpathResultSet * result, 2873 char **errMsg 2874) 2875{ 2876 xsltState *xs = clientData; 2877 xsltVarFrame *frame; 2878 xsltVariable *var; 2879 int rc, i, frameIndex, parFrameSkiped = 0; 2880 char *select; 2881 Tcl_HashEntry *h; 2882 xsltTopLevelVar *topLevelVar; 2883 xsltVarInProcess *varInProcess, thisVarInProcess; 2884 xpathResultSet nodeList; 2885 domNode *savedCurrentXSLTNode; 2886 Tcl_DString dErrMsg; 2887 2888 TRACE1("xsltGetVar variableName='%s' \n", variableName); 2889 frameIndex = xs->varFramesStackPtr; 2890 while (frameIndex >= 0) { 2891 frame = &xs->varFramesStack[frameIndex]; 2892 if (frame->stop == 2 && !parFrameSkiped) { 2893 parFrameSkiped = 1; 2894 frameIndex--; 2895 continue; 2896 } 2897 for (i = frame->varStartIndex; 2898 i < frame->varStartIndex + frame->nrOfVars; 2899 i++) { 2900 var = &xs->varStack[i]; 2901 if (!var->active) continue; 2902 if ( (varURI && !var->uri) 2903 || (!varURI && var->uri) 2904 || (varURI && var->uri && (strcmp (varURI, var->uri)!=0)) 2905 ) continue; 2906 if (strcmp(var->name, variableName)==0) { 2907 TRACE1("xsltGetVar '%s':\n", variableName); 2908 DBG(rsPrint(&(var->rs))); 2909 rsCopy(result, &(var->rs) ); 2910 return XPATH_OK; 2911 } 2912 } 2913 if ((frame->stop == 1) && frameIndex > 1) frameIndex = 1; 2914 frameIndex--; 2915 } 2916 2917 if (xs->varsInProcess) { 2918 h = Tcl_FindHashEntry (&xs->topLevelVars, variableName); 2919 if (h) { 2920 topLevelVar = (xsltTopLevelVar *) Tcl_GetHashValue (h); 2921 /* check for circular definitions */ 2922 varInProcess = xs->varsInProcess; 2923 while (varInProcess) { 2924 if (strcmp(varInProcess->name, variableName)==0) { 2925 reportError (topLevelVar->node, "circular top level" 2926 " variabale definition detected", errMsg); 2927 return XPATH_EVAL_ERR; 2928 } 2929 varInProcess = varInProcess->next; 2930 } 2931 thisVarInProcess.name = variableName; 2932 thisVarInProcess.next = xs->varsInProcess; 2933 xs->varsInProcess = &thisVarInProcess; 2934 2935 xpathRSInit( &nodeList ); 2936 rsAddNodeFast( &nodeList, xs->xmlRootNode); 2937 savedCurrentXSLTNode = xs->currentXSLTNode; 2938 xs->currentXSLTNode = topLevelVar->node; 2939 select = getAttr (topLevelVar->node, "select", a_select); 2940 rc = xsltSetVar (xs, variableName, &nodeList, xs->xmlRootNode, 2941 0, select, topLevelVar->node, 1, errMsg); 2942 xpathRSFree ( &nodeList ); 2943 CHECK_RC; 2944 rc = xsltGetVar (xs, variableName, varURI, result, errMsg); 2945 CHECK_RC; 2946 /* remove var out of the varsInProcess list. Should be first 2947 in the list, shouldn't it? */ 2948 varInProcess = xs->varsInProcess; 2949 if (varInProcess != &thisVarInProcess) { 2950 domPanic ("error in top level vars processing"); 2951 } 2952 xs->varsInProcess = varInProcess->next; 2953 xs->currentXSLTNode = savedCurrentXSLTNode; 2954 return XPATH_OK; 2955 } 2956 } 2957 Tcl_DStringInit (&dErrMsg); 2958 Tcl_DStringAppend (&dErrMsg, "Variable \"", -1); 2959 Tcl_DStringAppend (&dErrMsg, variableName, -1); 2960 Tcl_DStringAppend (&dErrMsg, "\" has not been declared.", -1); 2961 reportError (xs->currentXSLTNode, Tcl_DStringValue (&dErrMsg), errMsg); 2962 Tcl_DStringFree (&dErrMsg); 2963 return XPATH_EVAL_ERR; 2964} 2965 2966/*---------------------------------------------------------------------------- 2967| addMatch 2968| 2969\---------------------------------------------------------------------------*/ 2970static int addMatch ( 2971 xsltState *xs, 2972 domNode *node, 2973 xsltTemplate *tpl, 2974 char *prioStr, 2975 ast a, 2976 char **errMsg 2977 ) 2978{ 2979 xsltTemplate *t, *prevTpl; 2980 int rc, hnew; 2981 Tcl_DString dStr; 2982 Tcl_HashEntry *h; 2983 2984 if (a->type == CombinePath) { 2985 t = (xsltTemplate *)MALLOC(sizeof(xsltTemplate)); 2986 t->freeAst = NULL; 2987 t->name = NULL; 2988 t->nameURI = NULL; 2989 t->mode = tpl->mode; 2990 t->modeURI = tpl->modeURI; 2991 t->content = tpl->content; 2992 t->precedence = tpl->precedence; 2993 t->sDoc = tpl->sDoc; 2994 t->next = NULL; 2995 if (prioStr) { 2996 t->prio = tpl->prio; 2997 } 2998 rc = addMatch (xs, node, t, prioStr, a->child->child, errMsg); 2999 CHECK_RC1(t); 3000 tpl->ast = a->child->next->child; 3001 } else { 3002 tpl->ast = a; 3003 } 3004 3005 if (!prioStr) { 3006 tpl->prio = xpathGetPrio(tpl->ast); 3007 TRACE1("prio = %f for \n", tpl->prio); 3008 DBG(printAst( 0, tpl->ast);) 3009 TRACE("\n"); 3010 } 3011 3012 if ((tpl->ast->type == IsElement && tpl->ast->strvalue[0] != '*') 3013 || tpl->ast->type == IsFQElement) { 3014 Tcl_DStringInit (&dStr); 3015 if (tpl->ast->type == IsFQElement) { 3016 Tcl_DStringAppend (&dStr, tpl->ast->strvalue, -1); 3017 Tcl_DStringAppend (&dStr, ":", 1); 3018 } 3019 if (tpl->mode) { 3020 if (tpl->modeURI) { 3021 Tcl_DStringAppend (&dStr, tpl->modeURI, -1); 3022 Tcl_DStringAppend (&dStr, ":", 1); 3023 } 3024 Tcl_DStringAppend (&dStr, tpl->mode, -1); 3025 Tcl_DStringAppend (&dStr, ":", 1); 3026 } 3027 if (tpl->ast->type == IsFQElement) { 3028 Tcl_DStringAppend (&dStr, tpl->ast->child->strvalue, -1); 3029 } else { 3030 Tcl_DStringAppend (&dStr, tpl->ast->strvalue, -1); 3031 } 3032 h = Tcl_CreateHashEntry (&(xs->isElementTpls), 3033 Tcl_DStringValue (&dStr), &hnew); 3034 Tcl_DStringFree (&dStr); 3035 3036 if (hnew) { 3037 tpl->next = NULL; 3038 Tcl_SetHashValue (h, tpl); 3039 } else { 3040 t = (xsltTemplate *) Tcl_GetHashValue (h); 3041 prevTpl = NULL; 3042 while ( t 3043 && t->precedence >= tpl->precedence 3044 && t->prio > tpl->prio) { 3045 prevTpl = t; 3046 t = t->next; 3047 } 3048 if (prevTpl) { 3049 tpl->next = t; 3050 prevTpl->next = tpl; 3051 } else { 3052 tpl->next = Tcl_GetHashValue (h); 3053 Tcl_SetHashValue (h, tpl); 3054 } 3055 } 3056 } else { 3057 if (xs->templates == NULL) { 3058 xs->templates = tpl; 3059 } else { 3060 t = xs->templates; 3061 prevTpl = NULL; 3062 while ( t 3063 && t->precedence >= tpl->precedence 3064 && t->prio > tpl->prio) { 3065 prevTpl = t; 3066 t = t->next; 3067 } 3068 if (prevTpl) { 3069 tpl->next = t; 3070 prevTpl->next = tpl; 3071 } else { 3072 tpl->next = xs->templates; 3073 xs->templates = tpl; 3074 } 3075 } 3076 } 3077 TRACE5("AddTemplate '%s' '%s' '%s' '%s' '%2.2f' \n\n", 3078 tpl->match, tpl->name, tpl->mode, tpl->modeURI, tpl->prio); 3079 return 0; 3080} 3081 3082/*---------------------------------------------------------------------------- 3083| xsltAddTemplate 3084| 3085\---------------------------------------------------------------------------*/ 3086static int xsltAddTemplate ( 3087 xsltState *xs, 3088 domNode *node, 3089 double precedence, 3090 char **errMsg 3091) 3092{ 3093 xsltTemplate *tpl, *t; 3094 char *prioStr, *str, prefix[MAX_PREFIX_LEN]; 3095 const char *localName; 3096 int rc, hnew; 3097 domNS *ns; 3098 Tcl_HashEntry *h; 3099 Tcl_DString dStr; 3100 xsltSubDoc *sDoc; 3101 3102 tpl = (xsltTemplate *)MALLOC(sizeof(xsltTemplate)); 3103 3104 tpl->match = getAttr(node,"match", a_match); 3105 str = getAttr(node, "name", a_name); 3106 if (!tpl->match && !str) { 3107 reportError (node, " xsl:template must have a name or" 3108 " match attribute (or both)", errMsg); 3109 FREE ((char*)tpl); 3110 return -1; 3111 } 3112 tpl->name = NULL; 3113 tpl->nameURI = NULL; 3114 if (str) { 3115 if (!domIsQNAME (str)) { 3116 reportError (node, "The value of the \"name\" attribute must" 3117 " be a qname", errMsg); 3118 FREE ((char*)tpl); 3119 return -1; 3120 } 3121 domSplitQName (str, prefix, &localName); 3122 if (prefix[0] != '\0') { 3123 ns = domLookupPrefix (node, prefix); 3124 if (!ns) { 3125 reportError (node, "The prefix of the \"name\" attribute" 3126 " value isn't bound to a namespace.", errMsg); 3127 FREE ((char*)tpl); 3128 return -1; 3129 } 3130 tpl->nameURI = ns->uri; 3131 Tcl_DStringInit (&dStr); 3132 Tcl_DStringAppend (&dStr, ns->uri, -1); 3133 Tcl_DStringAppend (&dStr, ":", 1); 3134 Tcl_DStringAppend (&dStr, localName, -1); 3135 h = Tcl_CreateHashEntry (&(xs->namedTemplates), 3136 Tcl_DStringValue (&dStr), &hnew); 3137 Tcl_DStringFree (&dStr); 3138 } else { 3139 h = Tcl_CreateHashEntry (&(xs->namedTemplates), localName, &hnew); 3140 } 3141 tpl->name = localName; 3142 if (!hnew) { 3143 t = (xsltTemplate *) Tcl_GetHashValue (h); 3144 if (t->precedence == precedence) { 3145 reportError (node, "There is already a template with the" 3146 " same name and precedence.", errMsg); 3147 FREE ((char*)tpl); 3148 return -1; 3149 } 3150 if (!t->match) { 3151 FREE ((char*)t); 3152 } 3153 } 3154 Tcl_SetHashValue (h, tpl); 3155 TRACE3("Added named Template '%s' '%2.2f' '%2.2f' \n\n", 3156 tpl->name, tpl->precedence, tpl->prio); 3157 } 3158 tpl->ast = NULL; 3159 tpl->mode = NULL; 3160 tpl->modeURI = NULL; 3161 str = getAttr (node, "mode", a_mode); 3162 if (str) { 3163 rc = 0; 3164 if (!domIsQNAME (str)) { 3165 reportError (node, "The value of the \"mode\" attribute must" 3166 " be a qname.", errMsg); 3167 rc = -1; 3168 } 3169 if (!tpl->match) { 3170 reportError (node, "A template without a \"match\" attribute must" 3171 " not have a \"mode\" attribute.", errMsg); 3172 rc = -1; 3173 } 3174 domSplitQName (str, prefix, &localName); 3175 if (prefix[0] != '\0') { 3176 ns = domLookupPrefix (node, prefix); 3177 if (!ns) { 3178 reportError (node, "The prefix of the \"mode\" attribute value" 3179 " isn't bound to a namespace.", errMsg); 3180 rc = -1; 3181 } 3182 tpl->modeURI = ns->uri; 3183 } 3184 tpl->mode = localName; 3185 if (rc < 0) { 3186 /* If the template has a name attribute, it is already stored in 3187 in the namedTemplates hash table and will be freed. */ 3188 if (!tpl->name) { 3189 FREE ((char*)tpl); 3190 } 3191 return -1; 3192 } 3193 } 3194 tpl->prio = 0.5; 3195 tpl->content = node; 3196 tpl->precedence = precedence; 3197 tpl->next = NULL; 3198 3199 prioStr = getAttr(node,"priority", a_prio); 3200 if (prioStr) { 3201 tpl->prio = (double)atof(prioStr); 3202 } 3203 3204 sDoc = xs->subDocs; 3205 while (sDoc) { 3206 if (sDoc->doc == node->ownerDocument) break; 3207 sDoc = sDoc->next; 3208 } 3209 tpl->sDoc = sDoc; 3210 3211 TRACE1("compiling XPATH '%s' ...\n", tpl->match); 3212 if (tpl->match) { 3213 rc = xpathParse(tpl->match, node, XPATH_TEMPMATCH_PATTERN, NULL, NULL, 3214 &(tpl->freeAst), errMsg); 3215 if (rc < 0) { 3216 reportError (node, *errMsg, errMsg); 3217 } else { 3218 rc = addMatch (xs, node, tpl, prioStr, tpl->freeAst, errMsg); 3219 } 3220 if (rc < 0) { 3221 if (tpl->name) { 3222 /* The template is already stored in the namedTemplates 3223 hash table. Therefor we don't free tpl here, but 3224 set tpl->match to NULL, which ensures, that the 3225 tpl will be freed while the namedTemplates hash table 3226 is cleand up. */ 3227 tpl->match = NULL; 3228 } else { 3229 free ((char*)tpl); 3230 } 3231 return rc; 3232 } 3233 } 3234 3235 return 0; 3236} 3237 3238/*---------------------------------------------------------------------------- 3239| ExecUseAttributeSets 3240| 3241\---------------------------------------------------------------------------*/ 3242static int ExecUseAttributeSets ( 3243 xsltState * xs, 3244 xpathResultSet * context, 3245 domNode * currentNode, 3246 int currentPos, 3247 domNode * actionNode, 3248 char * styles, 3249 char ** errMsg 3250) 3251{ 3252 xsltAttrSet *attrSet; 3253 char *pc, *aSet, save, *str, prefix[MAX_PREFIX_LEN]; 3254 const char *localName; 3255 int rc; 3256 domNS *ns; 3257 3258 pc = styles; 3259 while (*pc) { 3260 while (*pc && IS_XML_WHITESPACE(*pc)) pc++; 3261 if (*pc == '\0') break; 3262 aSet = pc; 3263 while (*pc && !IS_XML_WHITESPACE(*pc)) pc++; 3264 save = *pc; 3265 *pc = '\0'; 3266 TRACE1("use-attribute-set '%s' \n", aSet); 3267 attrSet = xs->attrSets; 3268 while (attrSet) { 3269 TRACE2("use-Attr: '%s' == '%s' ? \n", attrSet->name, aSet); 3270 rc = 0; 3271 if (!attrSet->uri) { 3272 if (strcmp(attrSet->name, aSet)==0) rc = 1; 3273 } 3274 else { 3275 domSplitQName (aSet, prefix, &localName); 3276 if (prefix[0] != '\0') { 3277 ns = domLookupPrefix (actionNode, prefix); 3278 if (ns) { 3279 if (strcmp (ns->uri, attrSet->uri)==0) { 3280 if (strcmp (attrSet->name, localName)==0) rc = 1; 3281 } 3282 } 3283 } 3284 } 3285 if (rc) { 3286 str = getAttr (attrSet->content, "use-attribute-sets", 3287 a_useAttributeSets); 3288 if (str) { 3289 rc = ExecUseAttributeSets (xs, context, currentNode, 3290 currentPos, attrSet->content, 3291 str, errMsg); 3292 CHECK_RC; 3293 } 3294 rc = ExecActions(xs, context, currentNode, currentPos, 3295 attrSet->content->firstChild, errMsg); 3296 CHECK_RC; 3297 } 3298 attrSet = attrSet->next; 3299 } 3300 *pc = save; 3301 } 3302 return 0; 3303} 3304 3305/*---------------------------------------------------------------------------- 3306| evalAttrTemplates 3307| 3308\---------------------------------------------------------------------------*/ 3309static int evalAttrTemplates ( 3310 xsltState * xs, 3311 xpathResultSet * context, 3312 domNode * currentNode, 3313 int currentPos, 3314 char * str, 3315 char ** out, 3316 char ** errMsg 3317) 3318{ 3319 xpathResultSet rs; 3320 char *tplStart = NULL, *tplResult, *pc, literalChar; 3321 int rc, aLen, inTpl = 0, p = 0, inLiteral = 0; 3322 3323 aLen = 500; 3324 *out = MALLOC(aLen); 3325 while (*str) { 3326 if (inTpl) { 3327 if (!inLiteral) { 3328 if (*str == '\'') { 3329 inLiteral = 1; 3330 literalChar = '\''; 3331 } else 3332 if (*str == '"') { 3333 inLiteral = 1; 3334 literalChar = '"'; 3335 } 3336 } else { 3337 if (*str == literalChar) { 3338 inLiteral = 0; 3339 } 3340 } 3341 if (*str == '}' && !inLiteral) { 3342 3343 *str = '\0'; 3344 TRACE1("attrTpl: '%s' \n", tplStart); 3345 rc = evalXPath (xs, context, currentNode, currentPos, 3346 tplStart, &rs, errMsg); 3347 *str = '}'; 3348 CHECK_RC1(*out); 3349 tplResult = xpathFuncString( &rs ); 3350 DBG(fprintf(stderr, "attrTpl tplResult='%s' \n", tplResult);) 3351 xpathRSFree( &rs ); 3352 pc = tplResult; 3353 while (*pc) { 3354 (*out)[p++] = *pc++; 3355 if (p>=aLen) { /* enlarge output buffer */ 3356 *out = REALLOC(*out, 2*aLen); 3357 aLen += aLen; 3358 } 3359 } 3360 inTpl = 0; 3361 FREE(tplResult); 3362 } 3363 } else { 3364 if (*str == '{') { 3365 if (*(str+1) == '{') { 3366 /*----------------------------------------------------- 3367 | read over escaped '{': 3368 | '{{text text}}' -> '{text text}' 3369 \----------------------------------------------------*/ 3370 str++; 3371 (*out)[p++] = *str++; 3372 if (p>=aLen) { /* enlarge output buffer */ 3373 *out = REALLOC(*out, 2*aLen); 3374 aLen += aLen; 3375 } 3376 while (*str && (*str != '}') && (*(str-1) != '}')) { 3377 (*out)[p++] = *str++; 3378 if (p>=aLen) { /* enlarge output buffer */ 3379 *out = REALLOC(*out, 2*aLen); 3380 aLen += aLen; 3381 } 3382 } 3383 if (!*str) break; 3384 } else { 3385 tplStart = str+1; 3386 inTpl = 1; 3387 inLiteral = 0; 3388 } 3389 } else { 3390 if (*str == '}' && *(str+1) == '}') { 3391 str++; 3392 } 3393 (*out)[p++] = *str; 3394 if (p>=aLen) { /* enlarge output buffer */ 3395 *out = REALLOC(*out, 2*aLen); 3396 aLen += aLen; 3397 } 3398 } 3399 } 3400 str++; 3401 } 3402 (*out)[p] = '\0'; 3403 DBG(fprintf(stderr, "evalAttrTemplates out='%s' \n", (*out) );) 3404 return 0; 3405} 3406 3407 3408/*---------------------------------------------------------------------------- 3409| setParamVars 3410| 3411\---------------------------------------------------------------------------*/ 3412static int setParamVars ( 3413 xsltState * xs, 3414 xpathResultSet * context, 3415 domNode * currentNode, 3416 int currentPos, 3417 domNode * actionNode, 3418 char ** errMsg 3419) 3420{ 3421 domNode *child; 3422 char *str, *select; 3423 int rc; 3424 3425 child = actionNode->firstChild; 3426 while (child) { 3427 if (child->nodeType == ELEMENT_NODE) { 3428 TRACE1("setParamVars child '%s' \n", child->nodeName); 3429 if (child->info == withParam) { 3430 str = getAttr(child, "name", a_name); 3431 if (str) { 3432 TRACE1("setting with-param '%s' \n", str); 3433 xs->currentXSLTNode = child; 3434 select = getAttr(child, "select", a_select); 3435 if (select && child->firstChild) { 3436 reportError (child, "An xsl:parameter element with a" 3437 " select attribute must be empty", 3438 errMsg); 3439 return -1; 3440 } 3441 TRACE1("with-param select='%s'\n", select); 3442 rc = xsltSetVar(xs, str, context, currentNode, 3443 currentPos, select, child, 0, errMsg); 3444 CHECK_RC; 3445 } else { 3446 reportError (child, "xsl:with-param: missing mandatory" 3447 " attribute \"name\".", errMsg); 3448 return -1; 3449 } 3450 } 3451 } 3452 child = child->nextSibling; 3453 } 3454 return 0; 3455} 3456 3457 3458/*---------------------------------------------------------------------------- 3459| doSortActions 3460| 3461\---------------------------------------------------------------------------*/ 3462static int doSortActions ( 3463 xsltState * xs, 3464 xpathResultSet * nodelist, 3465 domNode * actionNode, 3466 xpathResultSet * context, 3467 domNode * currentNode, 3468 int currentPos, 3469 char ** errMsg 3470) 3471{ 3472 domNode *child; 3473 char *str, *evStr, *select, *lang; 3474 char **vs = NULL; 3475 char prefix[MAX_PREFIX_LEN]; 3476 const char *localName; 3477 double *vd = NULL; 3478 int rc = 0, typeText, ascending, upperFirst, *pos = NULL, i, NaN; 3479 xpathResultSet rs; 3480 3481 child = actionNode->lastChild; /* do it backwards, so that multiple sort 3482 levels are correctly processed */ 3483 while (child) { 3484 if (child->nodeType == ELEMENT_NODE) { 3485 TRACE1("doSortActions child '%s' \n", child->nodeName); 3486 if (child->info == sort) { 3487 if (child->firstChild) { 3488 reportError (child, "xsl:sort has to be empty.", errMsg); 3489 rc = -1; 3490 break; 3491 } 3492 typeText = 1; 3493 ascending = 1; 3494 upperFirst = 1; 3495 select = getAttr(child, "select", a_select); 3496 if (!select) select = "."; 3497 xs->currentXSLTNode = child; 3498 str = getAttr(child, "data-type", a_dataType); 3499 if (str) { 3500 rc = evalAttrTemplates (xs, context, currentNode, 3501 currentPos, str, &evStr, errMsg); 3502 CHECK_RC; 3503 if (strcmp(evStr,"text")==0) typeText = 1; 3504 else if (strcmp(evStr,"number")==0) typeText = 0; 3505 else { 3506 domSplitQName (evStr, prefix, &localName); 3507 if (prefix[0] == '\0') { 3508 reportError (child, "data-type must be text, " 3509 "number or a prefixed name", errMsg); 3510 FREE(evStr); 3511 rc = -1; 3512 break; 3513 } 3514 /* OK, so it is a legal value. But we currently 3515 don't support non-standard data-types. We use 3516 the default, that is typeText = 1. */ 3517 } 3518 FREE(evStr); 3519 } 3520 str = getAttr(child, "order", a_order); 3521 if (str) { 3522 rc = evalAttrTemplates (xs, context, currentNode, 3523 currentPos, str, &evStr, errMsg); 3524 CHECK_RC; 3525 if (strcmp(evStr,"descending")==0) ascending = 0; 3526 else if (strcmp(evStr, "ascending")==0) ascending = 1; 3527 else { 3528 reportError (child, "order must be ascending or" 3529 " descending", errMsg); 3530 FREE(evStr); 3531 rc = -1; 3532 break; 3533 } 3534 FREE(evStr); 3535 } 3536 str = getAttr(child, "case-order", a_caseorder); 3537 if (str) { 3538 rc = evalAttrTemplates (xs, context, currentNode, 3539 currentPos, str, &evStr, errMsg); 3540 CHECK_RC; 3541 if (strcmp(evStr,"lower-first")==0) upperFirst = 0; 3542 else if (strcmp(evStr, "upper-first")==0) upperFirst = 1; 3543 else { 3544 reportError (child, "case-order must be lower-first" 3545 " or upper-first", errMsg); 3546 FREE(evStr); 3547 rc = -1; 3548 break; 3549 } 3550 FREE(evStr); 3551 } 3552 /* jcl: TODO */ 3553 lang = getAttr(child, "lang", a_lang); 3554 3555 TRACE4("sorting with '%s' typeText %d ascending %d nodeSetLen=%d\n", 3556 select, typeText, ascending, nodelist->nr_nodes); 3557 CHECK_RC; 3558 if (!pos) 3559 pos = (int*)MALLOC(sizeof(int) * nodelist->nr_nodes); 3560 for (i=0; i<nodelist->nr_nodes;i++) pos[i] = i; 3561 3562 xs->currentXSLTNode = child; 3563 3564 if (!vs) { 3565 vs = (char **)MALLOC(sizeof (char *) * nodelist->nr_nodes); 3566 for (i=0; i<nodelist->nr_nodes;i++) vs[i] = NULL; 3567 vd = (double *)MALLOC(sizeof (double) * nodelist->nr_nodes); 3568 for (i=0; i<nodelist->nr_nodes;i++) vd[i] = 0.0; 3569 } 3570 for (i = 0; i < nodelist->nr_nodes; i++) { 3571 xpathRSInit (&rs); 3572 rc = evalXPath (xs, nodelist, nodelist->nodes[i], i, 3573 select, &rs, errMsg); 3574 if (rc < 0) 3575 goto doSortActionCleanUp; 3576 3577 if (typeText) { 3578 vs[i] = xpathFuncString (&rs); 3579 } else { 3580 vd[i] = xpathFuncNumber (&rs, &NaN); 3581 } 3582 xpathRSFree (&rs); 3583 } 3584 rc = sortNodeSetFastMerge (typeText, ascending, upperFirst, 3585 nodelist->nodes, nodelist->nr_nodes, 3586 vs, vd, pos, errMsg); 3587 if (typeText) { 3588 for (i = 0; i < nodelist->nr_nodes; i++) { 3589 FREE(vs[i]); 3590 } 3591 } 3592 if (rc < 0) 3593 goto doSortActionCleanUp; 3594 } 3595 } 3596 child = child->previousSibling; 3597 } 3598 doSortActionCleanUp: 3599 if (pos) FREE((char*)pos); 3600 if (vs) FREE((char*)vs); 3601 if (vd) FREE((char*)vd); 3602 return rc; 3603} 3604 3605 3606/*---------------------------------------------------------------------------- 3607| xsltNumber 3608| 3609\---------------------------------------------------------------------------*/ 3610static int xsltNumber ( 3611 xsltState * xs, 3612 xpathResultSet * context, 3613 domNode * currentNode, 3614 int currentPos, 3615 domNode * actionNode, 3616 char ** errMsg 3617) 3618{ 3619 xpathResultSet rs; 3620 int rc, vs[20], NaN, hnew, i, useFormatToken, vVals = 0; 3621 int *v, *vd = NULL; 3622 long groupingSize = 0; 3623 char *value, *level, *count, *from, *str, *str1, *format; 3624 char *groupingSeparator = NULL, *groupingSizeStr = NULL; 3625 char *tail; 3626 ast t_count, t_from; 3627 domNode *node, *start; 3628 Tcl_HashEntry *h; 3629 xsltNumberFormat *f; 3630 Tcl_DString dStr; 3631 domProcessingInstructionNode *pi; 3632 3633 v = vs; 3634 value = getAttr(actionNode, "value", a_value); 3635 str = getAttr(actionNode, "format", a_format); if (!str) str = "1"; 3636 xs->currentXSLTNode = actionNode; 3637 rc = evalAttrTemplates( xs, context, currentNode, currentPos, 3638 str, &format, errMsg); 3639 CHECK_RC; 3640 f = xsltNumberFormatTokenizer (xs, format, errMsg); 3641 if (!f) { 3642 FREE(format); 3643 return -1; 3644 } 3645 str = getAttr(actionNode, "grouping-separator", a_groupingSeparator); 3646 if (str) { 3647 str1 = getAttr (actionNode, "grouping-size", a_groupingSize); 3648 if (str1) { 3649 rc = evalAttrTemplates (xs, context, currentNode, currentPos, str, 3650 &groupingSeparator, errMsg); 3651 if (rc < 0) goto xsltNumberError; 3652 rc = evalAttrTemplates (xs, context, currentNode, currentPos, str1, 3653 &groupingSizeStr, errMsg); 3654 if (rc < 0) goto xsltNumberError; 3655 groupingSize = strtol (groupingSizeStr, &tail, 10); 3656 if (groupingSize <= 0) { 3657 /* This covers both cases: non integer value after evaluation 3658 and wrong (<= 0) integer value. */ 3659 reportError (actionNode, "The value of \"grouping-size\" must" 3660 " evaluate to a positiv integer.", errMsg); 3661 goto xsltNumberError; 3662 } 3663 } 3664 } 3665 3666 if (value) { 3667 TRACE2("xsltNumber value='%s' format='%s' \n", value, format); 3668 rc = evalXPath(xs, context, currentNode, currentPos, 3669 value, &rs, errMsg); 3670 if (rc < 0) goto xsltNumberError; 3671 vVals = 1; 3672 v[0] = xpathRound(xpathFuncNumber( &rs, &NaN )); 3673 /* MARK recoverable error */ 3674 /* This is one of the not so satisfying corners of the xslt 3675 * rec. The rec doesn't say, what to do, if the value isn't a 3676 * (finit) number. E24 from the erratas doesn't makes things 3677 * much better - a little bit dubious wording and a not very 3678 * convincing decision. Well, at least saxon seems to follow 3679 * the words of E24. I'll postpone this topic. */ 3680 if (NaN) v[0] = 0; 3681 xpathRSFree( &rs ); 3682 } else { 3683 level = getAttr(actionNode, "level", a_level); 3684 if (!level) level = "single"; 3685 count = getAttr(actionNode, "count", a_count); 3686 from = getAttr(actionNode, "from", a_from); 3687 TRACE3("xsltNumber format='%s' count='%s' from='%s' \n", format, count, from); 3688 if (count) { 3689 h = Tcl_CreateHashEntry (&(xs->pattern), count, &hnew); 3690 if (!hnew) { 3691 t_count = (ast) Tcl_GetHashValue (h); 3692 } else { 3693 rc = xpathParse (count, actionNode, XPATH_FORMAT_PATTERN, NULL, 3694 NULL, &t_count, errMsg); 3695 if (rc < 0) goto xsltNumberError; 3696 Tcl_SetHashValue (h, t_count); 3697 } 3698 } else { 3699 Tcl_DStringInit (&dStr); 3700 if (currentNode->nodeType == ELEMENT_NODE) { 3701 /* TODO: This is wrong. Instead this should use the 3702 "expanded-name" of the current node. */ 3703 Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); 3704 } else 3705 if (currentNode->nodeType == ATTRIBUTE_NODE) { 3706 Tcl_DStringAppend (&dStr, "@", 1); 3707 Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); 3708 } else 3709 if (currentNode->nodeType == COMMENT_NODE) { 3710 Tcl_DStringAppend (&dStr, "comment()", -1); 3711 } else 3712 if (currentNode->nodeType == TEXT_NODE) { 3713 Tcl_DStringAppend (&dStr, "text()", -1); 3714 } else 3715 if (currentNode->nodeType == PROCESSING_INSTRUCTION_NODE) { 3716 Tcl_DStringAppend (&dStr, "processing-instruction('", -1); 3717 pi = (domProcessingInstructionNode *)currentNode; 3718 Tcl_DStringAppend (&dStr, pi->targetValue, pi->targetLength); 3719 Tcl_DStringAppend (&dStr, "')", 2); 3720 } else { 3721 reportError (actionNode, "unknown node type!!!", errMsg); 3722 return -1; 3723 } 3724 h = Tcl_CreateHashEntry (&(xs->pattern), Tcl_DStringValue(&dStr), 3725 &hnew); 3726 if (!hnew) { 3727 t_count = (ast) Tcl_GetHashValue (h); 3728 } else { 3729 rc = xpathParse (Tcl_DStringValue (&dStr), actionNode, 3730 XPATH_FORMAT_PATTERN, NULL, NULL, &t_count, 3731 errMsg); 3732 if (rc < 0) { 3733 Tcl_DStringFree (&dStr); 3734 goto xsltNumberError; 3735 } 3736 Tcl_SetHashValue (h, t_count); 3737 } 3738 Tcl_DStringFree (&dStr); 3739 } 3740 if (from) { 3741 h = Tcl_CreateHashEntry (&(xs->pattern), from, &hnew); 3742 if (!hnew) { 3743 t_from = (ast) Tcl_GetHashValue (h); 3744 } else { 3745 rc = xpathParse (from, actionNode, XPATH_FORMAT_PATTERN, NULL, 3746 NULL, &t_from, errMsg); 3747 if (rc < 0) goto xsltNumberError; 3748 Tcl_SetHashValue (h, t_from); 3749 } 3750 } 3751 3752 if (strcmp (level, "single")==0) { 3753 node = currentNode; 3754 start = NULL; 3755 if (from) { 3756 while (node) { 3757 rc = xpathMatches (t_from, actionNode, node, &(xs->cbs), 3758 errMsg); 3759 if (rc < 0) goto xsltNumberError; 3760 if (rc) break; 3761 if (node->nodeType == ATTRIBUTE_NODE) 3762 node = ((domAttrNode *)node)->parentNode; 3763 else node = node->parentNode; 3764 } 3765 } 3766 node = currentNode; 3767 while (node != start) { 3768 rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), 3769 errMsg); 3770 if (rc < 0) goto xsltNumberError; 3771 if (rc) break; 3772 if (node->nodeType == ATTRIBUTE_NODE) 3773 node = ((domAttrNode *)node)->parentNode; 3774 else node = node->parentNode; 3775 } 3776 if (node == start) { 3777 domAppendNewTextNode (xs->lastNode, "", 0, TEXT_NODE, 0); 3778 FREE(format); 3779 return 0; 3780 } else { 3781 vVals = 1; 3782 v[0] = 1; 3783 node = domPreviousSibling (node); 3784 while (node) { 3785 rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), 3786 errMsg); 3787 if (rc < 0) goto xsltNumberError; 3788 if (rc) v[0]++; 3789 node = domPreviousSibling (node); 3790 } 3791 } 3792 } else 3793 if (strcmp (level, "multiple")==0) { 3794 xpathRSInit (&rs); 3795 node = currentNode; 3796 while (node) { 3797 if (from) { 3798 rc = xpathMatches (t_from, actionNode, node, &(xs->cbs), 3799 errMsg); 3800 if (rc < 0) goto xsltNumberError; 3801 if (rc) break; 3802 } 3803 rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), 3804 errMsg); 3805 if (rc < 0) goto xsltNumberError; 3806 if (rc) rsAddNode (&rs, node); 3807 if (node->nodeType == ATTRIBUTE_NODE) 3808 node = ((domAttrNode *)node)->parentNode; 3809 else node = node->parentNode; 3810 } 3811 if (rs.nr_nodes > 20) { 3812 vd = (int *)MALLOC(sizeof (int) * rs.nr_nodes); 3813 v = vd; 3814 } 3815 vVals = rs.nr_nodes; 3816 v[0] = 0; 3817 for (i = 0; i < rs.nr_nodes; i++) { 3818 node = domPreviousSibling (rs.nodes[i]); 3819 v[i] = 1; 3820 while (node) { 3821 rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), 3822 errMsg); 3823 if (rc < 0) goto xsltNumberError; 3824 if (rc) v[i]++; 3825 node = domPreviousSibling (node); 3826 } 3827 } 3828 xpathRSFree (&rs); 3829 } else 3830 if (strcmp (level, "any")==0) { 3831 v[0] = 0; 3832 vVals = 1; 3833 node = currentNode; 3834 while (node) { 3835 if (from) { 3836 rc = xpathMatches (t_from, actionNode, node, &(xs->cbs), 3837 errMsg); 3838 if (rc < 0) goto xsltNumberError; 3839 if (rc) break; 3840 } 3841 rc = xpathMatches (t_count, actionNode, node, &(xs->cbs), 3842 errMsg); 3843 if (rc < 0) goto xsltNumberError; 3844 if (rc) v[0]++; 3845 if (domPreviousSibling (node)) { 3846 node = domPreviousSibling (node); 3847 while ((node->nodeType == ELEMENT_NODE) 3848 && node->lastChild) { 3849 node = node->lastChild; 3850 } 3851 continue; 3852 } 3853 if (node->nodeType == ATTRIBUTE_NODE) { 3854 node = ((domAttrNode *)node)->parentNode; 3855 } else { 3856 node = node->parentNode; 3857 } 3858 } 3859 } else { 3860 reportError (actionNode, "xsl:number: Wrong \"level\" attribute" 3861 " value!", errMsg); 3862 goto xsltNumberError; 3863 } 3864 } 3865 3866 Tcl_DStringInit (&dStr); 3867 useFormatToken = 0; 3868 if (f->prologLen) { 3869 Tcl_DStringAppend (&dStr, f->formatStr, f->prologLen); 3870 } 3871 for (i = 0; i < vVals -1; i++) { 3872 formatValue (f, &useFormatToken, v[i], &dStr, 3873 groupingSeparator, groupingSize, 1); 3874 } 3875 if (vVals > 0) { 3876 formatValue (f, &useFormatToken, v[vVals-1], &dStr, 3877 groupingSeparator, groupingSize, 0); 3878 if (f->epilogLen) { 3879 Tcl_DStringAppend (&dStr, f->epilogStart, f->epilogLen); 3880 } 3881 domAppendNewTextNode(xs->lastNode, Tcl_DStringValue (&dStr), 3882 Tcl_DStringLength (&dStr), TEXT_NODE, 0); 3883 } 3884 FREE(format); 3885 if (groupingSeparator) FREE (groupingSeparator); 3886 if (groupingSizeStr) FREE (groupingSizeStr); 3887 if (vd) { 3888 FREE((char *)vd); 3889 } 3890 Tcl_DStringFree (&dStr); 3891 return 0; 3892 3893 xsltNumberError: 3894 if (format) FREE (format); 3895 if (groupingSeparator) FREE (groupingSeparator); 3896 if (groupingSizeStr) FREE (groupingSizeStr); 3897 return -1; 3898} 3899 3900/*---------------------------------------------------------------------------- 3901| ExecAction 3902| 3903\---------------------------------------------------------------------------*/ 3904static int ExecAction ( 3905 xsltState * xs, 3906 xpathResultSet * context, 3907 domNode * currentNode, 3908 int currentPos, 3909 domNode * actionNode, 3910 char ** errMsg 3911) 3912{ 3913 domNode *child, *n, *n1, *savedLastNode, *fragmentNode; 3914 xsltTemplate *tpl, *currentTplRule, *tplChoosen; 3915 domAttrNode *attr, *attr1; 3916 domTextNode *tnode; 3917 domNS *ns, *ns1; 3918 xsltSubDoc *sDoc, *currentSubDoc; 3919 xsltExclExtNS *eNS; 3920 xsltNSAlias *nsAlias; 3921 Tcl_DString dStr; 3922 domProcessingInstructionNode *pi; 3923 xpathResultSet rs, nodeList; 3924 char *str, *str2, *select, *pc, *nsAT, *out; 3925 const char *mode, *modeURI, *localName, *uri, *nsStr; 3926 char prefix[MAX_PREFIX_LEN]; 3927 int rc, b, i, len, terminate, chooseState, disableEsc = 0; 3928 double currentPrio, currentPrec; 3929 Tcl_HashEntry *h; 3930 3931 if (actionNode->nodeType == TEXT_NODE) { 3932 domAppendNewTextNode(xs->lastNode, 3933 ((domTextNode*)actionNode)->nodeValue, 3934 ((domTextNode*)actionNode)->valueLength, 3935 TEXT_NODE, 0); 3936 return 0; 3937 } 3938 if (actionNode->nodeType != ELEMENT_NODE) return 0; 3939 3940 TRACE1("\nExecAction '%s' \n", actionNode->nodeName); 3941 DBG (printXML (currentNode, 3, 5);) 3942 xs->currentXSLTNode = actionNode; 3943 switch ( actionNode->info ) { 3944 3945 case applyImports: 3946 if (actionNode->firstChild) { 3947 reportError(actionNode, "xsl:apply-imports has to be empty!", 3948 errMsg); 3949 return -1; 3950 } 3951 if (!xs->currentTplRule) { 3952 reportError(actionNode, "xsl:apply-imports not allowed here!", 3953 errMsg); 3954 return -1; 3955 } 3956 tplChoosen = NULL; 3957 currentPrio = -100000.0; 3958 currentPrec = 0.0; 3959 mode = xs->currentTplRule->mode; 3960 modeURI = xs->currentTplRule->modeURI; 3961 3962 if (currentNode->nodeType == ELEMENT_NODE) { 3963 Tcl_DStringInit (&dStr); 3964 if (currentNode->namespace) { 3965 domSplitQName (currentNode->nodeName, prefix, &localName); 3966 Tcl_DStringAppend (&dStr, domNamespaceURI (currentNode), 3967 -1); 3968 Tcl_DStringAppend (&dStr, ":", 1); 3969 } 3970 if (mode) { 3971 if (modeURI) { 3972 Tcl_DStringAppend (&dStr, modeURI, -1); 3973 Tcl_DStringAppend (&dStr, ":", 1); 3974 } 3975 Tcl_DStringAppend (&dStr, mode, -1); 3976 Tcl_DStringAppend (&dStr, ":", 1); 3977 } 3978 if (currentNode->namespace) { 3979 Tcl_DStringAppend (&dStr, localName, -1); 3980 } else { 3981 Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); 3982 } 3983 h = Tcl_FindHashEntry (&xs->isElementTpls, 3984 Tcl_DStringValue (&dStr)); 3985 Tcl_DStringFree (&dStr); 3986 3987 if (h) { 3988 for (tpl = (xsltTemplate *) Tcl_GetHashValue (h); 3989 tpl != NULL; 3990 tpl = tpl->next) { 3991 if (tpl->precedence > xs->currentTplRule->precedence 3992 || tpl == xs->currentTplRule) continue; 3993 TRACE3("find element tpl match='%s' mode='%s' name='%s'\n", 3994 tpl->match, tpl->mode, tpl->name); 3995 TRACE4("tpl has prio='%f' precedence='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); 3996 rc = xpathMatches ( tpl->ast, actionNode, currentNode, 3997 &(xs->cbs), errMsg); 3998 if (rc < 0) { 3999 TRACE1("xpathMatches had errors '%s' \n", *errMsg); 4000 return rc; 4001 } 4002 if (rc == 0) continue; 4003 TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); 4004 tplChoosen = tpl; 4005 currentPrio = tpl->prio; 4006 currentPrec = tpl->precedence; 4007 break; 4008 } 4009 } 4010 } 4011 4012 TRACE2("apply-imports: current template precedence='%f' mode='%s'\n", xs->currentTplRule->precedence, xs->currentTplRule->mode); 4013 for (tpl = xs->templates; tpl != NULL; tpl = tpl->next) { 4014 TRACE4("find tpl match='%s' mode='%s' modeURI='%s' name='%s'\n", 4015 tpl->match, tpl->mode, tpl->modeURI, tpl->name); 4016 /* exclude those, which don't match the current mode 4017 and the currentTplRule */ 4018 if ( ( mode && !tpl->mode) 4019 || (!mode && tpl->mode) 4020 || ( mode && tpl->mode && (strcmp(mode,tpl->mode)!=0)) 4021 || (!modeURI && tpl->modeURI) 4022 || ( modeURI && !tpl->modeURI) 4023 || ( modeURI && tpl->modeURI && (strcmp(modeURI, tpl->modeURI)!=0)) 4024 || (tpl == xs->currentTplRule) 4025 ) { 4026 TRACE("doesn't match mode\n"); 4027 continue; 4028 } 4029 TRACE4("tpl has prio='%f' precedence='%f', currentPrio='%f', currentPrec='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); 4030 if (tpl->match && tpl->precedence < xs->currentTplRule->precedence 4031 && tpl->precedence >= currentPrec) { 4032 if (tpl->precedence > currentPrec 4033 || tpl->prio >= currentPrio) { 4034 rc = xpathMatches (tpl->ast, actionNode, currentNode, 4035 &(xs->cbs), errMsg); 4036 CHECK_RC; 4037 if (rc == 0) continue; 4038 TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); 4039 tplChoosen = tpl; 4040 currentPrec = tpl->precedence; 4041 currentPrio = tpl->prio; 4042 TRACE1("TAKING '%s' \n", tpl->match); 4043 } 4044 } 4045 } 4046 4047 if (tplChoosen == NULL) { 4048 4049 TRACE("nothing matches -> execute built-in template \n"); 4050 4051 /*-------------------------------------------------------------------- 4052 | execute built-in template 4053 \-------------------------------------------------------------------*/ 4054 if (currentNode->nodeType == TEXT_NODE) { 4055 domAppendNewTextNode(xs->lastNode, 4056 ((domTextNode*)currentNode)->nodeValue, 4057 ((domTextNode*)currentNode)->valueLength, 4058 TEXT_NODE, 0); 4059 break; 4060 } else 4061 if (currentNode->nodeType == ELEMENT_NODE) { 4062 child = currentNode->firstChild; 4063 } else 4064 if (currentNode->nodeType == ATTRIBUTE_NODE) { 4065 domAppendNewTextNode (xs->lastNode, 4066 ((domAttrNode*)currentNode)->nodeValue, 4067 ((domAttrNode*)currentNode)->valueLength, 4068 TEXT_NODE, 0); 4069 break; 4070 } else { 4071 /* for all other node we don't have to recurse deeper */ 4072 break; 4073 } 4074 xpathRSInit( &rs ); 4075 while (child) { 4076 rsAddNodeFast ( &rs, child); 4077 child = child->nextSibling; 4078 } 4079 rc = ApplyTemplates (xs, context, currentNode, currentPos, 4080 actionNode, &rs, mode, modeURI, errMsg); 4081 xpathRSFree( &rs ); 4082 CHECK_RC; 4083 4084 break; 4085 } 4086 4087 xsltPushVarFrame (xs); 4088 SETSCOPESTART; 4089 currentTplRule = xs->currentTplRule; 4090 currentSubDoc = xs->currentSubDoc; 4091 xs->currentTplRule = tplChoosen; 4092 xs->currentSubDoc = tplChoosen->sDoc; 4093 rc = ExecActions(xs, context, currentNode, currentPos, 4094 tplChoosen->content->firstChild, errMsg); 4095 xsltPopVarFrame (xs); 4096 CHECK_RC; 4097 xs->currentTplRule = currentTplRule; 4098 xs->currentSubDoc = currentSubDoc; 4099 break; 4100 4101 case applyTemplates: 4102 mode = NULL; 4103 modeURI = NULL; 4104 str = getAttr (actionNode, "mode", a_mode); 4105 if (str) { 4106 domSplitQName (str, prefix, &localName); 4107 if (prefix[0] != '\0') { 4108 ns = domLookupPrefix (actionNode, prefix); 4109 if (!ns) { 4110 reportError (actionNode, "The prefix of the \"name\"" 4111 " attribute value isn't bound to a" 4112 " namespace.", errMsg); 4113 return -1; 4114 } 4115 modeURI = ns->uri; 4116 } 4117 mode = localName; 4118 } 4119 select = getAttr(actionNode, "select", a_select); 4120 if (!select) { 4121 xpathRSInit (&rs); 4122 if (currentNode->nodeType == ELEMENT_NODE) { 4123 child = currentNode->firstChild; 4124 while (child) { 4125 rsAddNodeFast (&rs, child); 4126 child = child->nextSibling; 4127 } 4128 } 4129 } else { 4130 xpathRSInit( &nodeList ); 4131 rsAddNodeFast( &nodeList, currentNode ); 4132 DBG(rsPrint( &nodeList )); 4133 TRACE2("applyTemplates: select = '%s' mode='%s'\n", select, mode); 4134 rc = evalXPath(xs, &nodeList, currentNode, 1, select, &rs, errMsg); 4135 xpathRSFree( &nodeList ); 4136 CHECK_RC; 4137 TRACE1("applyTemplates: evalXPath for select = '%s' gave back:\n", select); 4138 DBG(rsPrint(&rs)); 4139 } 4140 4141 if (rs.type == EmptyResult) break; 4142 else if (rs.type != xNodeSetResult) { 4143 reportError (actionNode, "The \"select\" expression of" 4144 " xsl:apply-templates elements must evaluate to" 4145 " a node set.", errMsg); 4146 xpathRSFree (&rs); 4147 return -1; 4148 } 4149 4150 rc = doSortActions (xs, &rs, actionNode, context, currentNode, 4151 currentPos, errMsg); 4152 if (rc < 0) { 4153 xpathRSFree (&rs); 4154 return rc; 4155 } 4156 /* should not be necessary, because every node set is 4157 returned already in doc Order */ 4158 /* if (!sorted) sortByDocOrder(&rs); */ 4159 4160 TRACE1(" evalXPath for select = '%s': (SORTED)\n", select); 4161 DBG(rsPrint(&rs)); 4162 4163 rc = ApplyTemplates(xs, context, currentNode, currentPos, 4164 actionNode, &rs, mode, modeURI, errMsg); 4165 xpathRSFree( &rs ); 4166 CHECK_RC; 4167 break; 4168 4169 case attribute: 4170 if (xs->lastNode->firstChild) { 4171 /* Adding an Attribute to an element after 4172 children have been added to it is an error. 4173 Ignore the attribute. */ 4174 break; 4175 } 4176 nsAT = getAttr(actionNode, "namespace", a_namespace); 4177 str = getAttr(actionNode, "name", a_name); 4178 if (!str) { 4179 reportError (actionNode, "xsl:attribute: missing mandatory" 4180 " attribute \"name\".", errMsg); 4181 return -1; 4182 } 4183 4184 rc = evalAttrTemplates( xs, context, currentNode, currentPos, 4185 str, &str2, errMsg); 4186 CHECK_RC; 4187 domSplitQName (str2, prefix, &localName); 4188 if ((prefix[0] != '\0' && !domIsNCNAME (prefix)) 4189 || !domIsNCNAME (localName)) { 4190 reportError (actionNode, "xsl:attribute: Attribute name is not" 4191 " a valid QName.", errMsg); 4192 FREE(str2); 4193 return -1; 4194 } 4195 out = NULL; 4196 if (nsAT) { 4197 rc = evalAttrTemplates( xs, context, currentNode, currentPos, 4198 nsAT, &out, errMsg); 4199 CHECK_RC1(str2); 4200 } 4201 4202 Tcl_DStringInit (&dStr); 4203 if (prefix[0] == '\0' && (strcmp(str2, "xmlns")==0)) { 4204 goto ignoreAttribute; 4205 } 4206 /* It isn't allowed to create namespace attributes with 4207 xsl:attribute, a "xmlns" prefix must be rewritten; see 4208 XSLT rec 7.1.3 */ 4209 if (prefix[0] && (strcmp(prefix, "xmlns")==0)) { 4210 sprintf (prefix, "ns%d", xs->nsUniqeNr++); 4211 Tcl_DStringAppend (&dStr, prefix, -1); 4212 Tcl_DStringAppend (&dStr, ":", 1); 4213 Tcl_DStringAppend (&dStr, localName, -1); 4214 } else { 4215 if (out) { 4216 if (out[0] == '\0') { 4217 if (prefix[0] != '\0') { 4218 Tcl_DStringAppend (&dStr, localName, -1); 4219 } else { 4220 Tcl_DStringAppend (&dStr, str2, -1); 4221 } 4222 FREE(out); 4223 out = NULL; 4224 } else { 4225 if (prefix[0] == '\0') { 4226 ns = domLookupURI (xs->lastNode, out); 4227 if (ns && (ns->prefix[0] != '\0')) { 4228 Tcl_DStringAppend (&dStr, ns->prefix, -1); 4229 Tcl_DStringAppend (&dStr, ":", 1); 4230 } else { 4231 sprintf (prefix, "ns%d", xs->nsUniqeNr++); 4232 Tcl_DStringAppend (&dStr, prefix, -1); 4233 Tcl_DStringAppend (&dStr, ":", 1); 4234 } 4235 } 4236 Tcl_DStringAppend (&dStr, str2, -1); 4237 } 4238 } else { 4239 if (prefix[0] != '\0') { 4240 ns = domLookupPrefix (actionNode, prefix); 4241 if (ns) out = tdomstrdup (ns->uri); 4242 else goto ignoreAttribute; 4243 } 4244 Tcl_DStringAppend (&dStr, str2, -1); 4245 } 4246 } 4247 4248 savedLastNode = xs->lastNode; 4249 xs->lastNode = domNewElementNode (xs->resultDoc, 4250 "container", ELEMENT_NODE); 4251 xsltPushVarFrame (xs); 4252 rc = ExecActions(xs, context, currentNode, currentPos, 4253 actionNode->firstChild, errMsg); 4254 xsltPopVarFrame (xs); 4255 if (rc < 0) { 4256 if (out) FREE(out); 4257 FREE(str2); 4258 return rc; 4259 } 4260 pc = xpathGetStringValue (xs->lastNode, &len); 4261 DBG(fprintf (stderr, "xsl:attribute: create attribute \"%s\" with value \"%s\" in namespace \"%s\"\n", Tcl_DStringValue (&dStr), pc, out);) 4262 domSetAttributeNS (savedLastNode, Tcl_DStringValue (&dStr), pc, 4263 out, 1); 4264 FREE(pc); 4265 Tcl_DStringFree (&dStr); 4266 domDeleteNode (xs->lastNode, NULL, NULL); 4267 xs->lastNode = savedLastNode; 4268 ignoreAttribute: 4269 if (out) FREE(out); 4270 FREE(str2); 4271 break; 4272 4273 case attributeSet: 4274 reportError (actionNode, "xsl:attribute-set is only allowed at" 4275 " top-level.", errMsg); 4276 return -1; 4277 4278 case callTemplate: 4279 tplChoosen = NULL; 4280 currentPrec = INT_MIN; 4281 str = getAttr(actionNode, "name", a_name); 4282 if (!str) { 4283 reportError (actionNode, "xsl:call-template must have a" 4284 " \"name\" attribute", errMsg); 4285 return -1; 4286 } 4287 domSplitQName (str, prefix, &localName); 4288 uri = NULL; 4289 if (prefix[0] != '\0') { 4290 ns = domLookupPrefix (actionNode, prefix); 4291 if (!ns) { 4292 reportError (actionNode, "The prefix of the \"name\"" 4293 " attribute value isn't bound to a" 4294 " namespace.", errMsg); 4295 return -1; 4296 } 4297 uri = ns->uri; 4298 } 4299 if (uri) { 4300 Tcl_DStringInit (&dStr); 4301 Tcl_DStringAppend (&dStr, uri, -1); 4302 Tcl_DStringAppend (&dStr, ":", 1); 4303 Tcl_DStringAppend (&dStr, localName, -1); 4304 h = Tcl_FindHashEntry (&(xs->namedTemplates), 4305 Tcl_DStringValue (&dStr)); 4306 Tcl_DStringFree (&dStr); 4307 } else { 4308 h = Tcl_FindHashEntry (&(xs->namedTemplates), localName); 4309 } 4310 if (!h) { 4311 reportError (actionNode, "xsl:call-template calls a non" 4312 " existend template!", errMsg); 4313 return -1; 4314 } 4315 tplChoosen = (xsltTemplate *) Tcl_GetHashValue (h); 4316 xsltPushVarFrame (xs); 4317 SETPARAMDEF; 4318 TRACE3("call template %s match='%s' name='%s' \n", localName, 4319 tplChoosen->match, tplChoosen->name); 4320 DBG(printXML(xs->lastNode, 0, 2);) 4321 rc = setParamVars (xs, context, currentNode, currentPos, 4322 actionNode, errMsg); 4323 if (rc < 0) { 4324 xsltPopVarFrame (xs); 4325 return rc; 4326 } 4327 currentSubDoc = xs->currentSubDoc; 4328 xs->currentSubDoc = tplChoosen->sDoc; 4329 SETSCOPESTART; 4330 rc = ExecActions(xs, context, currentNode, currentPos, 4331 tplChoosen->content->firstChild, errMsg); 4332 TRACE2("called template '%s': ApplyTemplate/ExecActions rc = %d \n", localName, rc); 4333 xsltPopVarFrame (xs); 4334 CHECK_RC; 4335 xs->currentSubDoc = currentSubDoc; 4336 DBG(printXML(xs->lastNode, 0, 2);) 4337 break; 4338 4339 case choose: 4340 chooseState = 0; 4341 for( child = actionNode->firstChild; child != NULL; 4342 child = child->nextSibling) 4343 { 4344 if (child->nodeType != ELEMENT_NODE) continue; 4345 switch (child->info) { 4346 case when: 4347 if (chooseState > 1) { 4348 reportError (actionNode, "\"otherwise\" clause" 4349 " must be after all \"when\"" 4350 " clauses", errMsg); 4351 return -1; 4352 } else { 4353 chooseState = 1; 4354 } 4355 str = getAttr(child, "test", a_test); 4356 if (str) { 4357 TRACE1("checking when test '%s' \n", str); 4358 rc = evalXPath(xs, context, currentNode, 4359 currentPos, str, &rs, errMsg); 4360 CHECK_RC; 4361 b = xpathFuncBoolean( &rs ); 4362 xpathRSFree( &rs ); 4363 if (b) { 4364 TRACE("test is true!\n"); 4365 /* process the children as well */ 4366 xsltPushVarFrame (xs); 4367 rc = ExecActions(xs, context, 4368 currentNode, currentPos, 4369 child->firstChild, errMsg); 4370 xsltPopVarFrame (xs); 4371 CHECK_RC; 4372 return 0; 4373 } 4374 } else { 4375 reportError (child, "xsl:when: missing mandatory" 4376 " attribute \"test\".", errMsg); 4377 return -1; 4378 } 4379 break; 4380 4381 case otherwise: 4382 if (chooseState != 1) { 4383 if (chooseState == 0) { 4384 reportError (actionNode, "\"choose\" must" 4385 " have at least one \"when\"" 4386 " clause", errMsg); 4387 } else { 4388 reportError (child, "only one \"otherwise\"" 4389 " clause allowed inside a" 4390 " \"choose\"", errMsg); 4391 } 4392 return -1; 4393 } else { 4394 chooseState = 2; 4395 } 4396 /* process the children as well */ 4397 xsltPushVarFrame (xs); 4398 rc = ExecActions(xs, context, currentNode, currentPos, 4399 child->firstChild, errMsg); 4400 xsltPopVarFrame (xs); 4401 CHECK_RC; 4402 break; 4403 4404 default: 4405 reportError (actionNode, "only otherwise or when" 4406 " allowed in choose!", 4407 errMsg); 4408 return -1; 4409 } 4410 } 4411 if (chooseState == 0) { 4412 reportError (actionNode, "\"choose\" must have at least" 4413 " one \"when\" clause", errMsg); 4414 return -1; 4415 } 4416 break; 4417 4418 case comment: 4419 fragmentNode = domNewElementNode(xs->resultDoc, "", ELEMENT_NODE); 4420 savedLastNode = xs->lastNode; 4421 xs->lastNode = fragmentNode; 4422 xsltPushVarFrame (xs); 4423 rc = ExecActions(xs, context, currentNode, currentPos, 4424 actionNode->firstChild, errMsg); 4425 xsltPopVarFrame (xs); 4426 CHECK_RC; 4427 child = fragmentNode->firstChild; 4428 while (child) { 4429 if (child->nodeType != TEXT_NODE) { 4430 domDeleteNode (fragmentNode, NULL, NULL); 4431 reportError (actionNode, "xsl:comment must not create" 4432 " nodes other than text nodes.", errMsg); 4433 return -1; 4434 } 4435 child = child->nextSibling; 4436 } 4437 str = xpathGetStringValue (fragmentNode, &len); 4438 if (!domIsComment (str)) { 4439 reportError (actionNode, "Invalide comment value", errMsg); 4440 domDeleteNode (fragmentNode, NULL, NULL); 4441 FREE(str); 4442 return -1; 4443 } 4444 xs->lastNode = savedLastNode; 4445 domAppendNewTextNode(xs->lastNode, str, len, COMMENT_NODE, 0); 4446 domDeleteNode (fragmentNode, NULL, NULL); 4447 FREE(str); 4448 break; 4449 4450 case copy: 4451 DBG(if (currentNode->nodeType == ATTRIBUTE_NODE) { 4452 fprintf(stderr, "copy '%s' \n", ((domAttrNode*)currentNode)->nodeName); 4453 } else { 4454 fprintf(stderr, "copy '%s' \n", currentNode->nodeName); 4455 }) 4456 if (currentNode->nodeType == TEXT_NODE) { 4457 DBG(fprintf(stderr, "node is TEXT_NODE \n");) 4458 tnode = (domTextNode*)currentNode; 4459 n = (domNode*) 4460 domAppendNewTextNode(xs->lastNode, 4461 tnode->nodeValue, 4462 tnode->valueLength, 4463 TEXT_NODE, 0); 4464 } else 4465 if (currentNode->nodeType == ELEMENT_NODE) { 4466 DBG(fprintf(stderr, "node is ELEMENT_NODE \n");) 4467 savedLastNode = xs->lastNode; 4468 if (currentNode != currentNode->ownerDocument->rootNode) { 4469 n = domAppendNewElementNode(xs->lastNode, 4470 currentNode->nodeName, 4471 domNamespaceURI(currentNode) ); 4472 xs->lastNode = n; 4473 str = getAttr(actionNode, "use-attribute-sets", 4474 a_useAttributeSets); 4475 domCopyNS (currentNode, xs->lastNode); 4476 if (str) { 4477 rc = ExecUseAttributeSets (xs, context, currentNode, 4478 currentPos, actionNode, 4479 str, errMsg); 4480 CHECK_RC; 4481 } 4482 } 4483 /* process the children only for root and element nodes */ 4484 xsltPushVarFrame (xs); 4485 rc = ExecActions(xs, context, currentNode, currentPos, 4486 actionNode->firstChild, errMsg); 4487 xsltPopVarFrame (xs); 4488 CHECK_RC; 4489 xs->lastNode = savedLastNode; 4490 } else 4491 if (currentNode->nodeType == PROCESSING_INSTRUCTION_NODE) { 4492 pi = (domProcessingInstructionNode*)currentNode; 4493 n = (domNode*) 4494 domNewProcessingInstructionNode (xs->lastNode->ownerDocument, 4495 pi->targetValue, 4496 pi->targetLength, 4497 pi->dataValue, 4498 pi->dataLength); 4499 domAppendChild (xs->lastNode, n); 4500 4501 } else 4502 if (currentNode->nodeType == COMMENT_NODE) { 4503 DBG(fprintf(stderr, "node is COMMENT_NODE \n");) 4504 tnode = (domTextNode *)currentNode; 4505 n = (domNode *) domAppendNewTextNode (xs->lastNode, 4506 tnode->nodeValue, 4507 tnode->valueLength, 4508 COMMENT_NODE, 0); 4509 } else 4510 if (currentNode->nodeType == ATTRIBUTE_NODE) { 4511 DBG(fprintf(stderr, "node is ATTRIBUTE_NODE \n");) 4512 if (xs->lastNode->firstChild) { 4513 /* Adding an Attribute to an element after 4514 children have been added to it is an error. 4515 Ignore the attribute. */ 4516 break; 4517 } 4518 if (xs->lastNode == xs->resultDoc->rootNode) { 4519 reportError (actionNode, "Cannot write an attribute" 4520 " when there is no open start tag", errMsg); 4521 return -1; 4522 } 4523 attr = (domAttrNode *)currentNode; 4524 domSetAttributeNS (xs->lastNode, attr->nodeName, 4525 attr->nodeValue, 4526 domNamespaceURI (currentNode), 1); 4527 } 4528 break; 4529 4530 case copyOf: 4531 if (actionNode->firstChild) { 4532 reportError (actionNode, "xsl:copy-of has to be empty.", 4533 errMsg); 4534 return -1; 4535 } 4536 select = getAttr(actionNode, "select", a_select); 4537 if (!select) { 4538 reportError (actionNode, "xsl:copy-of: missing mandatory" 4539 " attribute \"select\".", errMsg); 4540 return -1; 4541 } 4542 4543 rc = evalXPath(xs, context, currentNode, currentPos, select, 4544 &rs, errMsg); 4545 CHECK_RC; 4546 TRACE1(" copyOf select='%s':\n", select); 4547 DBG(rsPrint(&rs)); 4548 if (rs.type == xNodeSetResult) { 4549 for (i=0; i<rs.nr_nodes; i++) { 4550 if (rs.nodes[i]->nodeType == ATTRIBUTE_NODE) { 4551 attr = (domAttrNode*)rs.nodes[i]; 4552 if (attr ->nodeFlags & IS_NS_NODE) { 4553 /* If someone selects explicitely namespace nodes 4554 to copy-of with e.g namespace::* (remember: @* 4555 doesn't select namespace nodes), we must this 4556 handle seperately.*/ 4557 /* The xmlns:xml namespace node will always 4558 be in scope, but never needed to be copied, 4559 because the result tree will also always 4560 already have it. To suppress, that the result 4561 tree gets glutted with xmlns:xml declarations 4562 (they would not harm, but ev. irritate some and 4563 are unnecessary, we check this here as a 4564 special case */ 4565 if (attr->namespace == 1) { 4566 continue; 4567 } 4568 ns = NULL; 4569 } else { 4570 ns = domGetNamespaceByIndex ( 4571 attr->parentNode->ownerDocument, 4572 attr->namespace 4573 ); 4574 } 4575 if (ns) uri = ns->uri; 4576 else uri = NULL; 4577 if (xs->lastNode == xs->resultDoc->rootNode) { 4578 reportError (actionNode, "Cannot write an" 4579 " attribute when there is no open" 4580 " start tag", errMsg); 4581 xpathRSFree (&rs); 4582 return -1; 4583 } 4584 domSetAttributeNS(xs->lastNode, attr->nodeName, 4585 attr->nodeValue, uri, 1); 4586 } else { 4587 if (*(rs.nodes[i]->nodeName) == '\0') { 4588 /* The rootNode of the Document or the rootNode 4589 of a result tree fragment */ 4590 child = rs.nodes[i]->firstChild; 4591 while (child) { 4592 domCopyTo(child, xs->lastNode, 1); 4593 child = child->nextSibling; 4594 } 4595 } else { 4596 domCopyTo (rs.nodes[i], xs->lastNode, 1); 4597 } 4598 } 4599 } 4600 } else { 4601 str = xpathFuncString( &rs ); 4602 TRACE1("copyOf: xpathString='%s' \n", str); 4603 domAppendNewTextNode(xs->lastNode, str, strlen(str), 4604 TEXT_NODE, 0); 4605 FREE(str); 4606 } 4607 xpathRSFree( &rs ); 4608 break; 4609 4610 case decimalFormat: 4611 reportError (actionNode, "xsl:decimal-format is only allowed" 4612 " at toplevel.", errMsg); 4613 return -1; 4614 4615 case element: 4616 nsAT = getAttr(actionNode, "namespace", a_namespace); 4617 str = getAttr(actionNode, "name", a_name); 4618 if (!str) { 4619 reportError (actionNode, "xsl:element: missing mandatory" 4620 " attribute \"name\".", errMsg); 4621 return -1; 4622 } 4623 4624 rc = evalAttrTemplates( xs, context, currentNode, currentPos, 4625 str, &str2, errMsg); 4626 CHECK_RC; 4627 if (!domIsNAME (str2)) { 4628 reportError (actionNode, "xsl:element: Element name is not a" 4629 " valid QName.", errMsg); 4630 FREE(str2); 4631 return -1; 4632 } 4633 out = NULL; 4634 nsStr = NULL; 4635 if (nsAT) { 4636 rc = evalAttrTemplates( xs, context, currentNode, currentPos, 4637 nsAT, &out, errMsg); 4638 CHECK_RC1(str2); 4639 nsStr = out; 4640 } else { 4641 domSplitQName (str2, prefix, &localName); 4642 if ((prefix[0] != '\0' && !domIsNCNAME (prefix)) 4643 || !domIsNCNAME (localName)) { 4644 reportError (actionNode, "xsl:element: Element name is" 4645 " not a valid QName.", errMsg); 4646 FREE(str2); 4647 return -1; 4648 } 4649 ns = domLookupPrefix (actionNode, prefix); 4650 if (ns) nsStr = ns->uri; 4651 else { 4652 if (prefix[0] != '\0') { 4653 reportError (actionNode, "xsl:element: there isn't" 4654 " a URI associated with the prefix of" 4655 " the element name.", errMsg); 4656 FREE(str2); 4657 return -1; 4658 } 4659 } 4660 } 4661 savedLastNode = xs->lastNode; 4662 xs->lastNode = domAppendNewElementNode (xs->lastNode, str2, nsStr); 4663 FREE(str2); 4664 if (nsAT) FREE(out); 4665 str = getAttr(actionNode, "use-attribute-sets", a_useAttributeSets); 4666 if (str) { 4667 TRACE1("use-attribute-sets = '%s' \n", str); 4668 rc = ExecUseAttributeSets (xs, context, currentNode, 4669 currentPos, actionNode, 4670 str, errMsg); 4671 CHECK_RC; 4672 } 4673 /* process the children as well */ 4674 if (actionNode->firstChild) { 4675 xsltPushVarFrame (xs); 4676 rc = ExecActions(xs, context, currentNode, currentPos, 4677 actionNode->firstChild, errMsg); 4678 xsltPopVarFrame (xs); 4679 } 4680 xs->lastNode = savedLastNode; 4681 CHECK_RC; 4682 break; 4683 4684 case fallback: return 0; 4685 4686 case forEach: 4687 select = getAttr(actionNode, "select", a_select); 4688 if (!select) { 4689 reportError (actionNode, "xsl:for-each: The select attribute" 4690 " is required.", errMsg); 4691 return -1; 4692 } 4693 DBG ( 4694 if (currentNode->nodeType == ELEMENT_NODE) { 4695 fprintf (stderr, 4696 "forEach select from Element Node '%s' domNode0x%x:\n", 4697 currentNode->nodeName, currentNode); 4698 if (currentNode->firstChild) { 4699 fprintf(stderr, 4700 "forEach select from child '%s' domNode0x%x:\n", 4701 currentNode->firstChild->nodeName, 4702 currentNode->firstChild); 4703 } 4704 } else if (currentNode->nodeType == ATTRIBUTE_NODE) { 4705 fprintf (stderr, "forEach select from Attribute Node '%s' Value '%s'\n", ((domAttrNode *)currentNode)->nodeName, ((domAttrNode *)currentNode)->nodeValue); 4706 } else { 4707 fprintf (stderr, "forEach select from nodetype %d\n", currentNode->nodeType); 4708 } 4709 ) 4710 xpathRSInit( &nodeList ); 4711 rsAddNodeFast( &nodeList, currentNode ); 4712 DBG(rsPrint( &nodeList )); 4713 rc = evalXPath(xs, &nodeList, currentNode, 1, select, &rs, errMsg); 4714 xpathRSFree (&nodeList); 4715 if (rc < 0) { 4716 return rc; 4717 } 4718 CHECK_RC; 4719 TRACE1("forEach: evalXPath for select = '%s' gave back:\n", select); 4720 DBG(rsPrint(&rs)); 4721 4722 if (rs.type == xNodeSetResult) { 4723 rc = doSortActions (xs, &rs, actionNode, context, currentNode, 4724 currentPos, errMsg); 4725 if (rc < 0) { 4726 xpathRSFree (&rs); 4727 return rc; 4728 } 4729 /* should not be necessary, because every node set is 4730 returned already in doc Order */ 4731 /* if (!sorted) sortByDocOrder(&rs); */ 4732 4733 TRACE1(" forEach for select = '%s': (SORTED)\n", select); 4734 DBG(rsPrint(&rs)); 4735 currentTplRule = xs->currentTplRule; 4736 xs->currentTplRule = NULL; 4737 xsltPushVarFrame (xs); 4738 for (i=0; i<rs.nr_nodes; i++) { 4739 /* process the children as well */ 4740 rc = ExecActions(xs, &rs, rs.nodes[i], i, 4741 actionNode->firstChild, errMsg); 4742 if (rc < 0) { 4743 xsltPopVarFrame (xs); 4744 xpathRSFree( &rs ); 4745 return rc; 4746 } 4747 if ((&xs->varFramesStack[xs->varFramesStackPtr])->polluted) { 4748 xsltPopVarFrame (xs); 4749 xsltPushVarFrame (xs); 4750 } 4751 } 4752 xsltPopVarFrame (xs); 4753 xs->currentTplRule = currentTplRule; 4754 } else { 4755 if (rs.type != EmptyResult) { 4756 reportError (actionNode, "The \"select\" expression of" 4757 " xsl:for-each elements must evaluate to a" 4758 " node set.", errMsg); 4759 xpathRSFree (&rs); 4760 return -1; 4761 } 4762 } 4763 xpathRSFree( &rs ); 4764 break; 4765 4766 case xsltIf: 4767 str = getAttr(actionNode, "test", a_test); 4768 if (str) { 4769 rc = evalXPath(xs, context, currentNode, currentPos, str, 4770 &rs, errMsg); 4771 CHECK_RC; 4772 b = xpathFuncBoolean( &rs ); 4773 xpathRSFree( &rs ); 4774 if (b) { 4775 /* process the children as well */ 4776 xsltPushVarFrame (xs); 4777 rc = ExecActions(xs, context, currentNode, currentPos, 4778 actionNode->firstChild, errMsg); 4779 xsltPopVarFrame (xs); 4780 CHECK_RC; 4781 } 4782 } else { 4783 reportError (actionNode, "xsl:if: missing mandatory attribute" 4784 " \"test\".", errMsg); 4785 return -1; 4786 } 4787 break; 4788 4789 case import: 4790 reportError (actionNode, "xsl:import is only allowed at toplevel.", 4791 errMsg); 4792 return -1; 4793 case include: 4794 reportError (actionNode, "xsl:include is only allowed at" 4795 " toplevel.", errMsg); 4796 return -1; 4797 case key: 4798 reportError (actionNode, "xsl:key is only allowed at toplevel.", 4799 errMsg); 4800 return -1; 4801 4802 case message: 4803 str = getAttr(actionNode,"terminate", a_terminate); 4804 if (!str) terminate = 0; 4805 else if (strcmp (str, "yes") == 0) terminate = 1; 4806 else if (strcmp (str, "no") == 0) terminate = 0; 4807 else { 4808 reportError (actionNode, "Value for terminate should equal" 4809 " 'yes' or 'no'", errMsg); 4810 return -1; 4811 } 4812 fragmentNode = domNewElementNode(xs->resultDoc, "", 4813 ELEMENT_NODE); 4814 savedLastNode = xs->lastNode; 4815 xs->lastNode = fragmentNode; 4816 xsltPushVarFrame (xs); 4817 rc = ExecActions(xs, context, currentNode, currentPos, 4818 actionNode->firstChild, errMsg); 4819 xsltPopVarFrame (xs); 4820 CHECK_RC; 4821 4822 str2 = xpathGetStringValue(fragmentNode, &len); 4823 xs->xsltMsgCB (xs->xsltMsgClientData, str2, len, terminate); 4824 FREE(str2); 4825 xs->lastNode = savedLastNode; 4826 domDeleteNode (fragmentNode, NULL, NULL); 4827 if (terminate) { 4828 reportError (actionNode, "xsl:message with attribute" 4829 " \"terminate\"=\"yes\"", errMsg); 4830 return -1; 4831 } 4832 return 0; 4833 4834 case namespaceAlias: 4835 reportError (actionNode, "xsl:namespaceAlias is only allowed" 4836 " at toplevel.", errMsg); 4837 return -1; 4838 4839 case number: 4840 if (actionNode->firstChild) { 4841 reportError (actionNode, "xsl:number has to be empty.", 4842 errMsg); 4843 return -1; 4844 } 4845 rc = xsltNumber(xs, context, currentNode, currentPos, 4846 actionNode, errMsg); 4847 CHECK_RC; 4848 break; 4849 4850 case output: return 0; 4851 4852 case otherwise: 4853 reportError (actionNode, "xsl:otherwise must be immediately" 4854 " within xsl:choose", errMsg); 4855 return -1; 4856 4857 case param: 4858 str = getAttr(actionNode, "name", a_name); 4859 if (str) { 4860 TRACE1("setting param '%s' ??\n", str); 4861 if (!xsltVarExists(xs, str, actionNode)) { 4862 TRACE1("setting param '%s': yes \n", str); 4863 select = getAttr(actionNode, "select", a_select); 4864 if (select && actionNode->firstChild) { 4865 reportError (actionNode, "An xsl:parameter element " 4866 " with a select attribute must be empty", 4867 errMsg); 4868 return -1; 4869 } 4870 TRACE1("param select='%s'\n", select); 4871 rc = xsltSetVar(xs, str, context, currentNode, 4872 currentPos, select, actionNode, 1, errMsg); 4873 CHECK_RC; 4874 } 4875 } else { 4876 reportError (actionNode, "xsl:param: missing mandatory " 4877 " attribute \"name\".", errMsg); 4878 return -1; 4879 } 4880 break; 4881 4882 case preserveSpace: return 0; 4883 4884 case procinstr: 4885 str = getAttr(actionNode, "name", a_name); 4886 if (str) { 4887 rc = evalAttrTemplates( xs, context, currentNode, currentPos, 4888 str, &str2, errMsg); 4889 CHECK_RC; 4890 if (!domIsPINAME (str2) || !domIsNCNAME(str2)) { 4891 reportError (actionNode, "xsl:processing-instruction: " 4892 "Processing instruction name is invalid.", 4893 errMsg); 4894 FREE(str2); 4895 return -1; 4896 } 4897 } else { 4898 reportError (actionNode, "xsl:processing-instruction:" 4899 " missing mandatory attribute \"name\".", errMsg); 4900 return -1; 4901 } 4902 fragmentNode = domNewElementNode(xs->resultDoc, "", ELEMENT_NODE); 4903 savedLastNode = xs->lastNode; 4904 xs->lastNode = fragmentNode; 4905 xsltPushVarFrame (xs); 4906 rc = ExecActions(xs, context, currentNode, currentPos, 4907 actionNode->firstChild, errMsg); 4908 xsltPopVarFrame (xs); 4909 CHECK_RC; 4910 child = fragmentNode->firstChild; 4911 while (child) { 4912 if (child->nodeType != TEXT_NODE) { 4913 domDeleteNode (fragmentNode, NULL, NULL); 4914 reportError (actionNode, "xsl:processing-instruction must " 4915 "not create nodes other than text nodes.", 4916 errMsg); 4917 FREE(str2); 4918 return -1; 4919 } 4920 child = child->nextSibling; 4921 } 4922 str = xpathGetStringValue (fragmentNode, &len); 4923 if (!domIsPIValue (str)) { 4924 reportError (actionNode, "Invalide processing instruction " 4925 "value", errMsg); 4926 domDeleteNode (fragmentNode, NULL, NULL); 4927 FREE(str); 4928 FREE(str2); 4929 return -1; 4930 } 4931 xs->lastNode = savedLastNode; 4932 4933 n = (domNode*)domNewProcessingInstructionNode( 4934 xs->resultDoc, str2, strlen(str2), str, len); 4935 domAppendChild(xs->lastNode, n); 4936 domDeleteNode (fragmentNode, NULL, NULL); 4937 FREE(str2); 4938 FREE(str); 4939 break; 4940 4941 case sort: 4942 case stylesheet: 4943 case stripSpace: 4944 case template: 4945 return 0; 4946 4947 case text: 4948 str = getAttr(actionNode, "disable-output-escaping", 4949 a_disableOutputEscaping); 4950 if (str) { 4951 if (strcmp (str, "yes")==0) disableEsc = 1; 4952 } 4953 pc = xpathGetStringValue (actionNode, &len); 4954 DBG(fprintf(stderr, "text: pc='%s'%d \n", pc, len);) 4955 domAppendNewTextNode(xs->lastNode, pc, len, TEXT_NODE, disableEsc); 4956 FREE(pc); 4957 break; 4958 4959 case transform: return 0; 4960 4961 case valueOf: 4962 if (actionNode->firstChild) { 4963 reportError (actionNode, "xsl:value-of has to be empty.", 4964 errMsg); 4965 return -1; 4966 } 4967 str = getAttr(actionNode, "disable-output-escaping", 4968 a_disableOutputEscaping); 4969 if (str) { 4970 if (strcmp (str, "yes")==0) disableEsc = 1; 4971 } 4972 str = getAttr(actionNode, "select", a_select); 4973 if (str) { 4974 TRACE1("valueOf: str='%s' \n", str); 4975 rc = evalXPath(xs, context, currentNode, currentPos, str, 4976 &rs, errMsg); 4977 CHECK_RC; 4978 DBG(rsPrint(&rs)); 4979 str = xpathFuncString( &rs ); 4980 TRACE1("valueOf: xpathString='%s' \n", str); 4981 domAppendNewTextNode(xs->lastNode, str, strlen(str), 4982 TEXT_NODE, disableEsc); 4983 xpathRSFree( &rs ); 4984 FREE(str); 4985 } else { 4986 reportError (actionNode, "xsl:value-of must have a" 4987 " \"select\" attribute!", errMsg); 4988 return -1; 4989 } 4990 break; 4991 4992 case variable: 4993 str = getAttr(actionNode, "name", a_name); 4994 if (str) { 4995 if (xsltVarExists (xs, str, actionNode)) { 4996 Tcl_DStringInit (&dStr); 4997 Tcl_DStringAppend (&dStr, "Variable '", -1); 4998 Tcl_DStringAppend (&dStr, str, -1); 4999 Tcl_DStringAppend ( 5000 &dStr, "' is already declared in this template", -1); 5001 reportError (actionNode, Tcl_DStringValue (&dStr), errMsg); 5002 return -1; 5003 } 5004 select = getAttr(actionNode, "select", a_select); 5005 if (select && actionNode->firstChild) { 5006 reportError (actionNode, "An xsl:variable element with a" 5007 " select attribute must be empty", errMsg); 5008 return -1; 5009 } 5010 TRACE1("variable select='%s'\n", select); 5011 rc = xsltSetVar(xs, str, context, currentNode, currentPos, 5012 select, actionNode, 1, errMsg); 5013 CHECK_RC; 5014 } else { 5015 reportError (actionNode, "xsl:variable must have a \"name\"" 5016 " attribute!", errMsg); 5017 return -1; 5018 } 5019 break; 5020 5021 case when: 5022 reportError (actionNode, "xsl:when must be immediately within" 5023 " xsl:choose", errMsg); 5024 return -1; 5025 5026 case withParam: 5027 return 0; 5028 5029 default: 5030 sDoc = xs->currentSubDoc; 5031 if (actionNode->namespace) { 5032 ns = actionNode->ownerDocument->namespaces[actionNode->namespace - 1]; 5033 eNS = sDoc->extensionNS; 5034 while (eNS) { 5035 if (eNS->uri) { 5036 if (strcmp (eNS->uri, ns->uri)==0) break; 5037 } else { 5038 if (ns->prefix[0] == '\0') break; 5039 } 5040 eNS = eNS->next; 5041 } 5042 if (eNS) { 5043 /* An extension element; process fallback */ 5044 child = actionNode->firstChild; 5045 while (child) { 5046 if (child->info == fallback) { 5047 xsltPushVarFrame (xs); 5048 rc = ExecActions (xs, context, currentNode, 5049 currentPos, child->firstChild, 5050 errMsg); 5051 xsltPopVarFrame (xs); 5052 CHECK_RC; 5053 } 5054 child = child->nextSibling; 5055 } 5056 return 0; 5057 } 5058 } 5059 savedLastNode = xs->lastNode; 5060 DBG(fprintf(stderr, "append new tag '%s' uri='%s' \n", 5061 actionNode->nodeName, domNamespaceURI(actionNode) );); 5062 xs->lastNode = domAppendLiteralNode (xs->lastNode, actionNode); 5063 n = actionNode; 5064 5065 while (n) { 5066 attr = n->firstAttr; 5067 while (attr && (attr->nodeFlags & IS_NS_NODE)) { 5068 /* xslt namespace isn't copied */ 5069 /* Well, xslt implementors doesn't seem to agree 5070 at which point this rule out of the second paragraph 5071 of 7.1.1 must be applied: before or after applying 5072 the namespace aliases (or, in other words: is this 5073 rule (of not copying the XSLT namespace for lre) 5074 considered, at the time, the lre is found in the 5075 stylesheet or at the time, the lre is written to the 5076 result doc). In deed the rec doesn't clarify this 5077 explicitly. */ 5078 if (strcmp (attr->nodeValue, XSLT_NAMESPACE)==0){ 5079 attr = attr->nextSibling; 5080 continue; 5081 } 5082 ns = n->ownerDocument->namespaces[attr->namespace-1]; 5083 rc = 0; 5084 n1 = actionNode; 5085 while (n1 != n) { 5086 attr1 = n1->firstAttr; 5087 while (attr1 && (attr1->nodeFlags & IS_NS_NODE)) { 5088 ns1 = n1->ownerDocument->namespaces[attr1->namespace-1]; 5089 if (strcmp (ns1->prefix, ns->prefix)==0) { 5090 rc = 1; 5091 break; 5092 } 5093 attr1 = attr1->nextSibling; 5094 } 5095 if (rc) break; 5096 n1 = n1->parentNode; 5097 } 5098 if (rc) { 5099 attr = attr->nextSibling; 5100 continue; 5101 } 5102 5103 str = ns->uri; 5104 nsAlias = xs->nsAliases; 5105 while (nsAlias) { 5106 if (strcmp (nsAlias->fromUri, ns->uri)==0) { 5107 ns->uri = nsAlias->toUri; 5108 break; 5109 } 5110 nsAlias = nsAlias->next; 5111 } 5112 eNS = sDoc->excludeNS; 5113 while (eNS) { 5114 if (eNS->uri) { 5115 if (strcmp (eNS->uri, ns->uri)==0) break; 5116 } else { 5117 if (ns->prefix[0] == '\0') break; 5118 } 5119 eNS = eNS->next; 5120 } 5121 if (!eNS) { 5122 eNS = sDoc->extensionNS; 5123 while (eNS) { 5124 if (eNS->uri) { 5125 if (strcmp (eNS->uri, ns->uri)==0) break; 5126 } else { 5127 if (ns->prefix[0] == '\0') break; 5128 } 5129 eNS = eNS->next; 5130 } 5131 if (!eNS) { 5132 domAddNSToNode (xs->lastNode, ns); 5133 } 5134 } 5135 ns->uri = str; 5136 attr = attr->nextSibling; 5137 } 5138 n = n->parentNode; 5139 } 5140 /* It's not clear, what to do, if the literal result 5141 element is in a namespace, that should be excluded. We 5142 follow saxon and xalan, which both add the namespace of 5143 the literal result element always to the result tree, 5144 to ensure, that the result tree is conform to the XML 5145 namespace recommendation. */ 5146 if (actionNode->namespace) { 5147 ns = actionNode->ownerDocument->namespaces[actionNode->namespace-1]; 5148 str = ns->uri; 5149 nsAlias = xs->nsAliases; 5150 while (nsAlias) { 5151 if (strcmp (nsAlias->fromUri, ns->uri)==0) { 5152 ns->uri = nsAlias->toUri; 5153 break; 5154 } 5155 nsAlias = nsAlias->next; 5156 } 5157 ns1 = domAddNSToNode (xs->lastNode, ns); 5158 if (ns1) { 5159 xs->lastNode->namespace = ns1->index; 5160 } 5161 ns->uri = str; 5162 } else { 5163 ns = domLookupPrefix (xs->lastNode, ""); 5164 if (ns) { 5165 if (strcmp (ns->uri, "")!=0) { 5166 attr = domSetAttributeNS (xs->lastNode, "xmlns", "", 5167 NULL, 1); 5168 if (attr) { 5169 xs->lastNode->namespace = attr->namespace; 5170 } 5171 } else { 5172 xs->lastNode->namespace = ns->index; 5173 } 5174 } 5175 } 5176 5177 n = xs->lastNode; 5178 /* process the attributes */ 5179 attr = actionNode->firstAttr; 5180 while (attr) { 5181 if (attr->nodeFlags & IS_NS_NODE) { 5182 attr = attr->nextSibling; 5183 continue; 5184 } 5185 /* TODO: xsl:exclude-result-prefixes attribute on literal 5186 elements on the ancestor-or-self axis */ 5187 uri = domNamespaceURI((domNode*)attr); 5188 if (uri && strcmp(uri, XSLT_NAMESPACE)==0) { 5189 domSplitQName((char*)attr->nodeName, prefix, &localName); 5190 if (strcmp(localName,"use-attribute-sets")==0) { 5191 str = attr->nodeValue; 5192 rc = ExecUseAttributeSets (xs, context, currentNode, 5193 currentPos, actionNode, 5194 str, errMsg); 5195 CHECK_RC; 5196 } 5197 } else { 5198 rc = evalAttrTemplates( xs, context, currentNode, 5199 currentPos, attr->nodeValue, &str, 5200 errMsg); 5201 CHECK_RC; 5202 if (uri) { 5203 nsAlias = xs->nsAliases; 5204 while (nsAlias) { 5205 if (strcmp (nsAlias->fromUri, uri)==0) { 5206 uri = nsAlias->toUri; 5207 break; 5208 } 5209 nsAlias = nsAlias->next; 5210 } 5211 } 5212 domSetAttributeNS (n, attr->nodeName, str, uri, 1); 5213 FREE(str); 5214 } 5215 attr = attr->nextSibling; 5216 } 5217 /* process the children as well */ 5218 xsltPushVarFrame (xs); 5219 rc = ExecActions(xs, context, currentNode, currentPos, 5220 actionNode->firstChild, errMsg); 5221 xsltPopVarFrame (xs); 5222 CHECK_RC; 5223 xs->lastNode = savedLastNode; 5224 return 0; 5225 } 5226 return 0; 5227} 5228 5229/*---------------------------------------------------------------------------- 5230| ExecActions 5231| 5232\---------------------------------------------------------------------------*/ 5233static int ExecActions ( 5234 xsltState * xs, 5235 xpathResultSet * context, 5236 domNode * currentNode, 5237 int currentPos, 5238 domNode * actionNode, 5239 char ** errMsg 5240) 5241{ 5242 domNode *savedLastNode, *savedCurrentNode; 5243 int rc; 5244 5245 savedLastNode = xs->lastNode; 5246 savedCurrentNode = xs->current; 5247 5248 while (actionNode) { 5249 xs->current = currentNode; 5250 rc = ExecAction (xs, context, currentNode, currentPos, actionNode, 5251 errMsg); 5252 if (rc < 0) { 5253 xs->lastNode = savedLastNode; 5254 xs->current = savedCurrentNode; 5255 return rc; 5256 } 5257 actionNode = actionNode->nextSibling; 5258 } 5259 xs->lastNode = savedLastNode; 5260 xs->current = savedCurrentNode; 5261 return 0; 5262} 5263 5264/*---------------------------------------------------------------------------- 5265| ApplyTemplate 5266| 5267\---------------------------------------------------------------------------*/ 5268static int ApplyTemplate ( 5269 xsltState * xs, 5270 xpathResultSet * context, 5271 domNode * currentNode, 5272 domNode * exprContext, 5273 int currentPos, 5274 const char * mode, 5275 const char * modeURI, 5276 char ** errMsg 5277) 5278{ 5279 xsltTemplate *tpl; 5280 xsltTemplate *tplChoosen, *currentTplRule; 5281 domNode *child; 5282 xpathResultSet rs; 5283 int rc; 5284 double currentPrio, currentPrec; 5285 char prefix[MAX_PREFIX_LEN]; 5286 const char *localName; 5287 Tcl_HashEntry *h; 5288 Tcl_DString dStr; 5289 xsltSubDoc *currentSubDoc; 5290 5291 TRACE2("\n\nApplyTemplate mode='%s' currentPos=%d \n", mode, currentPos); 5292 DBG(printXML (currentNode, 0, 1);) 5293 5294 /*-------------------------------------------------------------- 5295 | find template 5296 \-------------------------------------------------------------*/ 5297 tplChoosen = NULL; 5298 currentPrio = -100000.0; 5299 currentPrec = 0.0; 5300 5301 5302 if (currentNode->nodeType == ELEMENT_NODE) { 5303 Tcl_DStringInit (&dStr); 5304 if (currentNode->namespace) { 5305 domSplitQName (currentNode->nodeName, prefix, &localName); 5306 Tcl_DStringAppend (&dStr, domNamespaceURI (currentNode), -1); 5307 Tcl_DStringAppend (&dStr, ":", 1); 5308 } 5309 if (mode) { 5310 if (modeURI) { 5311 Tcl_DStringAppend (&dStr, modeURI, -1); 5312 Tcl_DStringAppend (&dStr, ":", 1); 5313 } 5314 Tcl_DStringAppend (&dStr, mode, -1); 5315 Tcl_DStringAppend (&dStr, ":", 1); 5316 } 5317 if (currentNode->namespace) { 5318 Tcl_DStringAppend (&dStr, localName, -1); 5319 } else { 5320 Tcl_DStringAppend (&dStr, currentNode->nodeName, -1); 5321 } 5322 h = Tcl_FindHashEntry (&xs->isElementTpls, Tcl_DStringValue (&dStr)); 5323 Tcl_DStringFree (&dStr); 5324 5325 if (h) { 5326 for (tpl = (xsltTemplate *) Tcl_GetHashValue (h); 5327 tpl != NULL; 5328 tpl = tpl->next) { 5329 TRACE3("find element tpl match='%s' mode='%s' name='%s'\n", 5330 tpl->match, tpl->mode, tpl->name); 5331 TRACE4("tpl has prio='%f' precedence='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); 5332 rc = xpathMatches ( tpl->ast, tpl->content, currentNode, 5333 &(xs->cbs), errMsg); 5334 if (rc < 0) { 5335 TRACE1("xpathMatches had errors '%s' \n", *errMsg); 5336 return rc; 5337 } 5338 if (rc == 0) continue; 5339 TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); 5340 tplChoosen = tpl; 5341 currentPrio = tpl->prio; 5342 currentPrec = tpl->precedence; 5343 break; 5344 } 5345 } 5346 } 5347 5348 for( tpl = xs->templates; tpl != NULL; tpl = tpl->next) { 5349 5350 TRACE3("find tpl match='%s' mode='%s' name='%s'\n", 5351 tpl->match, tpl->mode, tpl->name); 5352 5353 /* exclude those, which don't match the current mode */ 5354 if ( ( mode && !tpl->mode) 5355 || (!mode && tpl->mode) 5356 || ( mode && tpl->mode && (strcmp(mode,tpl->mode)!=0)) 5357 || (!modeURI && tpl->modeURI) 5358 || ( modeURI && !tpl->modeURI) 5359 || ( modeURI && tpl->modeURI && (strcmp(modeURI, tpl->modeURI)!=0)) 5360 ) { 5361 TRACE("doesn't match mode\n"); 5362 continue; /* doesn't match mode */ 5363 } 5364 TRACE4("tpl has prio='%f' precedence='%f', currentPrio='%f', currentPrec='%f'\n", tpl->prio, tpl->precedence, currentPrio, currentPrec); 5365 /* According to xslt rec 5.5: First test precedence */ 5366 if (tpl->precedence < currentPrec) break; 5367 if (tpl->precedence == currentPrec) { 5368 if (tpl->prio < currentPrio) break; 5369 if (tpl->prio == currentPrio 5370 && domPrecedes (tpl->content, tplChoosen->content)) 5371 break; 5372 } 5373 rc = xpathMatches ( tpl->ast, tpl->content, currentNode, &(xs->cbs), 5374 errMsg); 5375 TRACE1("xpathMatches = %d \n", rc); 5376 if (rc < 0) { 5377 TRACE1("xpathMatches had errors '%s' \n", *errMsg); 5378 return rc; 5379 } 5380 if (rc == 0) continue; 5381 TRACE3("matching '%s': %f > %f ? \n", tpl->match, tpl->prio , currentPrio); 5382 tplChoosen = tpl; 5383 TRACE1("TAKING '%s' \n", tpl->match); 5384 break; 5385 } 5386 5387 if (tplChoosen == NULL) { 5388 TRACE("nothing matches -> execute built-in template \n"); 5389 5390 /*-------------------------------------------------------------------- 5391 | execute built-in template 5392 \-------------------------------------------------------------------*/ 5393 if (currentNode->nodeType == TEXT_NODE) { 5394 domAppendNewTextNode(xs->lastNode, 5395 ((domTextNode*)currentNode)->nodeValue, 5396 ((domTextNode*)currentNode)->valueLength, 5397 TEXT_NODE, 0); 5398 return 0; 5399 } else 5400 if (currentNode->nodeType == DOCUMENT_NODE) { 5401 child = ((domDocument*)currentNode)->documentElement; 5402 } else 5403 if (currentNode->nodeType == ELEMENT_NODE) { 5404 child = currentNode->firstChild; 5405 } else 5406 if (currentNode->nodeType == ATTRIBUTE_NODE) { 5407 domAppendNewTextNode (xs->lastNode, 5408 ((domAttrNode*)currentNode)->nodeValue, 5409 ((domAttrNode*)currentNode)->valueLength, 5410 TEXT_NODE, 0); 5411 return 0; 5412 } else { 5413 return 0; /* for all other nodes we don't have to recurse deeper */ 5414 } 5415 xpathRSInit( &rs ); 5416 while (child) { 5417 rsAddNodeFast ( &rs, child); 5418 child = child->nextSibling; 5419 } 5420 rc = ApplyTemplates (xs, context, currentNode, currentPos, exprContext, 5421 &rs, mode, modeURI, errMsg); 5422 xpathRSFree( &rs ); 5423 CHECK_RC; 5424 5425 } else { 5426 TRACE1("tplChoosen '%s' \n", tplChoosen->match); 5427 currentTplRule = xs->currentTplRule; 5428 currentSubDoc = xs->currentSubDoc; 5429 xs->currentTplRule = tplChoosen; 5430 xs->currentSubDoc = tplChoosen->sDoc; 5431 DBG(printXML (tplChoosen->content->firstChild, 0, 1);) 5432 rc = ExecActions(xs, context, currentNode, currentPos, 5433 tplChoosen->content->firstChild, errMsg); 5434 TRACE1("ApplyTemplate/ExecActions rc = %d \n", rc); 5435 xs->currentTplRule = currentTplRule; 5436 xs->currentSubDoc = currentSubDoc; 5437 CHECK_RC; 5438 } 5439 return 0; 5440} 5441 5442 5443/*---------------------------------------------------------------------------- 5444| ApplyTemplates 5445| 5446\---------------------------------------------------------------------------*/ 5447static int ApplyTemplates ( 5448 xsltState * xs, 5449 xpathResultSet * context, 5450 domNode * currentNode, 5451 int currentPos, 5452 domNode * actionNode, 5453 xpathResultSet * nodeList, 5454 const char * mode, 5455 const char * modeURI, 5456 char ** errMsg 5457) 5458{ 5459 domNode * savedLastNode; 5460 int i, rc, needNewVarFrame = 1; 5461 5462 if (nodeList->type == xNodeSetResult) { 5463 savedLastNode = xs->lastNode; 5464 for (i=0; i < nodeList->nr_nodes; i++) { 5465 if (needNewVarFrame) { 5466 xsltPushVarFrame (xs); 5467 SETPARAMDEF; 5468 rc = setParamVars (xs, context, currentNode, currentPos, 5469 actionNode, errMsg); 5470 if (rc < 0) { 5471 xsltPopVarFrame (xs); 5472 xs->lastNode = savedLastNode; 5473 return rc; 5474 } 5475 SETSCOPESTART; 5476 (&xs->varFramesStack[xs->varFramesStackPtr])->polluted = 0; 5477 } 5478 rc = ApplyTemplate (xs, nodeList, nodeList->nodes[i], actionNode, 5479 i, mode, modeURI, errMsg); 5480 if (rc < 0) { 5481 xsltPopVarFrame (xs); 5482 xs->lastNode = savedLastNode; 5483 return rc; 5484 } 5485 if ((&xs->varFramesStack[xs->varFramesStackPtr])->polluted) { 5486 xsltPopVarFrame (xs); 5487 needNewVarFrame = 1; 5488 } else needNewVarFrame = 0; 5489 } 5490 if (!needNewVarFrame) { 5491 xsltPopVarFrame (xs); 5492 } 5493 xs->lastNode = savedLastNode; 5494 } else { 5495 TRACE("ApplyTemplates: nodeList not a NodeSetResult !!!\n"); 5496 DBG(rsPrint(nodeList);) 5497 } 5498 return 0; 5499} 5500 5501 5502/*---------------------------------------------------------------------------- 5503| fillElementList 5504| 5505\---------------------------------------------------------------------------*/ 5506static int fillElementList ( 5507 xsltWSInfo * wsInfo, 5508 int strip, 5509 double precedence, 5510 domNode * node, 5511 char * str, 5512 char ** errMsg 5513) 5514{ 5515 char *pc, *start, save; 5516 char prefix[MAX_PREFIX_LEN]; 5517 const char *localName; 5518 double *f; 5519 int hnew; 5520 Tcl_HashEntry *h; 5521 Tcl_DString dStr; 5522 domNS *ns; 5523 5524 pc = str; 5525 while (*pc) { 5526 while (*pc && IS_XML_WHITESPACE(*pc)) pc++; 5527 if (*pc == '\0') break; 5528 start = pc; 5529 while (*pc && !IS_XML_WHITESPACE(*pc)) pc++; 5530 save = *pc; 5531 *pc = '\0'; 5532 wsInfo->hasData = 1; 5533 if (strcmp (start, "*")==0) { 5534 if (strip) wsInfo->stripAll = 1; 5535 else wsInfo->stripAll = 0; 5536 wsInfo->wildcardPrec = precedence; 5537 } else { 5538 Tcl_DStringInit (&dStr); 5539 ns = NULL; 5540 domSplitQName (start, prefix, &localName); 5541 if (prefix[0] != '\0') { 5542 if (!domIsNCNAME (prefix)) { 5543 reportError (node, "Invalid token", errMsg); 5544 *pc = save; 5545 Tcl_DStringFree (&dStr); 5546 return -1; 5547 } 5548 ns = domLookupPrefix (node, prefix); 5549 if (!ns) { 5550 reportError (node, "prefix isn't bound to a namespace", 5551 errMsg); 5552 *pc = save; 5553 Tcl_DStringFree (&dStr); 5554 return -1; 5555 } 5556 Tcl_DStringAppend (&dStr, ns->uri, -1); 5557 Tcl_DStringAppend (&dStr, ":", 1); 5558 } 5559 if (strcmp ("*", localName) != 0) { 5560 if (!domIsNCNAME (localName)) { 5561 reportError (node, "Invalid token", errMsg); 5562 *pc = save; 5563 Tcl_DStringFree (&dStr); 5564 return -1; 5565 } 5566 } 5567 Tcl_DStringAppend (&dStr, localName, -1); 5568 if (strip) { 5569 h = Tcl_FindHashEntry (&wsInfo->preserveTokens, 5570 Tcl_DStringValue (&dStr)); 5571 } else { 5572 h = Tcl_FindHashEntry (&wsInfo->stripTokens, 5573 Tcl_DStringValue (&dStr)); 5574 } 5575 if (h) { 5576 FREE (Tcl_GetHashValue (h)); 5577 Tcl_DeleteHashEntry (h); 5578 } 5579 if (strip) { 5580 h = Tcl_CreateHashEntry (&wsInfo->stripTokens, 5581 Tcl_DStringValue (&dStr), &hnew); 5582 } else { 5583 h = Tcl_CreateHashEntry (&wsInfo->preserveTokens, 5584 Tcl_DStringValue (&dStr), &hnew); 5585 } 5586 if (hnew) { 5587 f = (double *)MALLOC(sizeof (double)); 5588 *f = precedence; 5589 Tcl_SetHashValue (h, f); 5590 } else { 5591 f = (double *)Tcl_GetHashValue (h); 5592 *f = precedence; 5593 } 5594 Tcl_DStringFree (&dStr); 5595 } 5596 *pc = save; 5597 } 5598 return 1; 5599} 5600 5601/*---------------------------------------------------------------------------- 5602| getCdataSectionElements 5603| 5604\---------------------------------------------------------------------------*/ 5605static int 5606getCdataSectionElements ( 5607 domNode * node, 5608 char * qnameList, 5609 Tcl_HashTable * HashTable, 5610 char ** errMsg 5611 ) 5612{ 5613 char *pc, *start, save, prefix[MAX_PREFIX_LEN]; 5614 const char *localName; 5615 int hnew; 5616 Tcl_HashEntry *h; 5617 5618 Tcl_DString dStr; 5619 domNS *ns; 5620 5621 Tcl_DStringInit (&dStr); 5622 pc = qnameList; 5623 while (*pc) { 5624 while (*pc && IS_XML_WHITESPACE(*pc)) pc++; 5625 if (*pc == '\0') break; 5626 start = pc; 5627 while (*pc && !IS_XML_WHITESPACE(*pc)) pc++; 5628 save = *pc; 5629 *pc = '\0'; 5630 domSplitQName (start, prefix, &localName); 5631 if (prefix[0] != '\0') { 5632 if (!domIsNCNAME (prefix)) { 5633 Tcl_DStringSetLength (&dStr, 0); 5634 Tcl_DStringAppend (&dStr, "Invalid prefix '", -1); 5635 Tcl_DStringAppend (&dStr, prefix, -1); 5636 Tcl_DStringAppend (&dStr, "'.", 2); 5637 reportError (node, Tcl_DStringValue (&dStr), errMsg); 5638 Tcl_DStringFree (&dStr); 5639 return 0; 5640 } 5641 ns = domLookupPrefix (node, prefix); 5642 if (!ns) { 5643 Tcl_DStringSetLength (&dStr, 0); 5644 Tcl_DStringAppend (&dStr, "There isn't a namespace bound to" 5645 " the prefix '", -1); 5646 Tcl_DStringAppend (&dStr, prefix, -1); 5647 Tcl_DStringAppend (&dStr, "'.", 2); 5648 reportError (node, Tcl_DStringValue (&dStr), errMsg); 5649 Tcl_DStringFree (&dStr); 5650 return 0; 5651 } 5652 Tcl_DStringAppend (&dStr, ns->uri, -1); 5653 Tcl_DStringAppend (&dStr, ":", 1); 5654 } 5655 if (!domIsNCNAME (localName)) { 5656 Tcl_DStringSetLength (&dStr, 0); 5657 Tcl_DStringAppend (&dStr, "Invalid name '", -1); 5658 Tcl_DStringAppend (&dStr, prefix, -1); 5659 Tcl_DStringAppend (&dStr, "'.", 2); 5660 reportError (node, Tcl_DStringValue (&dStr), errMsg); 5661 Tcl_DStringFree (&dStr); 5662 return 0; 5663 } 5664 Tcl_DStringAppend (&dStr, localName, -1); 5665 h = Tcl_CreateHashEntry (HashTable, Tcl_DStringValue (&dStr), &hnew); 5666 Tcl_DStringSetLength (&dStr, 0); 5667 *pc = save; 5668 } 5669 return 1; 5670} 5671 5672/*---------------------------------------------------------------------------- 5673| StripXSLTSpace 5674| 5675\---------------------------------------------------------------------------*/ 5676static void StripXSLTSpace ( 5677 domNode * node 5678) 5679{ 5680 domNode *child, *newChild, *parent; 5681 int i, len, onlySpace; 5682 char *p; 5683 5684 if (node->nodeType == TEXT_NODE) { 5685 node->info = (int)unknown; 5686 p = ((domTextNode*)node)->nodeValue; 5687 len = ((domTextNode*)node)->valueLength; 5688 onlySpace = 1; 5689 for (i=0; i<len; i++) { 5690 if (!IS_XML_WHITESPACE(*p)) { 5691 onlySpace = 0; 5692 break; 5693 } 5694 p++; 5695 } 5696 if (onlySpace) { 5697 if (node->parentNode && (node->parentNode->info == text)) { 5698 /* keep white texts below xsl:text elements */ 5699 return; 5700 } 5701 parent = node->parentNode; 5702 while (parent) { 5703 p = getAttr(parent,"xml:space", a_space); 5704 if (p!=NULL) { 5705 if (strcmp(p,"preserve")==0) return; 5706 if (strcmp(p,"default")==0) break; 5707 } 5708 parent = parent->parentNode; 5709 } 5710 DBG(fprintf(stderr, "removing domNode0x%x(len %d) under '%s' \n", 5711 node, len, node->parentNode->nodeName);) 5712 domDeleteNode (node, NULL, NULL); 5713 } 5714 } else 5715 if (node->nodeType == ELEMENT_NODE) { 5716 getTag(node); 5717 child = node->firstChild; 5718 while (child) { 5719 newChild = child->nextSibling; 5720 StripXSLTSpace (child); 5721 child = newChild; 5722 } 5723 } else { 5724 node->info = (int)unknown; 5725 } 5726} 5727 5728 5729/*---------------------------------------------------------------------------- 5730| addExclExtNS 5731| 5732\---------------------------------------------------------------------------*/ 5733static int 5734parseList ( 5735 xsltSubDoc *docData, 5736 domNode *xsltRoot, 5737 char *str, 5738 int extensionNS, 5739 char **errMsg 5740 ) 5741{ 5742 xsltExclExtNS *eNS; 5743 char *pc, *start, save; 5744 domNS *ns; 5745 5746 if (str) { 5747 pc = str; 5748 while (*pc) { 5749 while (*pc && IS_XML_WHITESPACE(*pc)) 5750 pc++; 5751 if (*pc == '\0') break; 5752 start = pc; 5753 while (*pc && !IS_XML_WHITESPACE(*pc)) 5754 pc++; 5755 save = *pc; 5756 *pc = '\0'; 5757 eNS = (xsltExclExtNS *)MALLOC(sizeof (xsltExclExtNS)); 5758 eNS->uri = NULL; 5759 if (extensionNS) { 5760 eNS->next = docData->extensionNS; 5761 docData->extensionNS = eNS; 5762 } else { 5763 eNS->next = docData->excludeNS; 5764 docData->excludeNS = eNS; 5765 } 5766 if (strcmp (start, "#default")==0) { 5767 ns = domLookupPrefix (xsltRoot, ""); 5768 if (!ns) { 5769 reportError (xsltRoot, "All prefixes listed in" 5770 " exclude-result-prefixes and" 5771 " extension-element-prefixes must be" 5772 " bound to a namespace.", 5773 errMsg); 5774 return -1; 5775 } 5776 } else { 5777 ns = domLookupPrefix (xsltRoot, start); 5778 if (!ns) { 5779 reportError (xsltRoot, "All prefixes listed in" 5780 " exclude-result-prefixes and" 5781 " extension-element-prefixes must be" 5782 " bound to a namespace.", 5783 errMsg); 5784 return -1; 5785 } 5786 eNS->uri = tdomstrdup (ns->uri); 5787 } 5788 *pc = save; 5789 } 5790 } 5791 return 1; 5792} 5793 5794static int 5795addExclExtNS ( 5796 xsltSubDoc *docData, 5797 domNode *xsltRoot, 5798 char **errMsg 5799 ) 5800{ 5801 char *str, *tailptr; 5802 int rc; 5803 double d; 5804 5805 str = getAttr (xsltRoot, "version", a_version); 5806 if (!str) { 5807 reportError (xsltRoot, "missing mandatory attribute \"version\".", 5808 errMsg); 5809 return -1; 5810 } 5811 d = strtod (str, &tailptr); 5812 if (d == 0.0 && tailptr == str) { 5813 reportError (xsltRoot, "The value of the attribute \"version\" must" 5814 " be a number.", errMsg); 5815 return -1; 5816 } 5817 if (d > 1.0) { 5818 docData->fwCmpProcessing = 1; 5819 } else { 5820 if (d != 1.0) { 5821 reportError (xsltRoot, "Strange \"version\" value.", errMsg); 5822 return -1; 5823 docData->fwCmpProcessing = 0; 5824 } 5825 } 5826 5827 str = getAttr (xsltRoot, "exclude-result-prefixes", 5828 a_excludeResultPrefixes); 5829 rc = parseList (docData, xsltRoot, str, 0, errMsg); 5830 CHECK_RC; 5831 5832 str = getAttr (xsltRoot, "extension-element-prefixes", 5833 a_extensionElementPrefixes); 5834 rc = parseList (docData, xsltRoot, str, 1, errMsg); 5835 CHECK_RC; 5836 return 1; 5837} 5838 5839/*---------------------------------------------------------------------------- 5840| getExternalDocument 5841| 5842\---------------------------------------------------------------------------*/ 5843static domDocument * 5844getExternalDocument ( 5845 Tcl_Interp *interp, 5846 xsltState *xs, 5847 domDocument *xsltDoc, 5848 const char *baseURI, 5849 const char *href, 5850 int isStylesheet, 5851 int fixedXMLSource, 5852 char **errMsg 5853 ) 5854{ 5855 Tcl_Obj *cmdPtr, *resultObj, *extbaseObj, *xmlstringObj; 5856 Tcl_Obj *channelIdObj, *resultTypeObj; 5857 int len, mode, result, storeLineColumn; 5858 char *resultType, *extbase, *xmlstring, *channelId, s[20]; 5859 char *extResolver = NULL; 5860 CONST84 char *str; 5861 domDocument *doc; 5862 xsltSubDoc *sdoc; 5863 XML_Parser parser; 5864 Tcl_Channel chan; 5865 Tcl_DString dStr; 5866 5867 if (isStylesheet && (href[0] == '\0')) { 5868 *errMsg = tdomstrdup("Recursive import/include: stylesheet tries " 5869 "to access itself."); 5870 return NULL; 5871 } 5872 cmdPtr = Tcl_NewStringObj (xsltDoc->extResolver, -1); 5873 Tcl_IncrRefCount (cmdPtr); 5874 if (baseURI) { 5875 Tcl_ListObjAppendElement(interp, cmdPtr, 5876 Tcl_NewStringObj (baseURI, 5877 strlen(baseURI))); 5878 } else { 5879 Tcl_ListObjAppendElement(interp, cmdPtr, 5880 Tcl_NewStringObj ("", 0)); 5881 } 5882 Tcl_ListObjAppendElement (interp, cmdPtr, (href ? 5883 Tcl_NewStringObj (href, strlen (href)) 5884 : Tcl_NewStringObj ("", 0))); 5885 Tcl_ListObjAppendElement (interp, cmdPtr, 5886 Tcl_NewStringObj ("", 0)); 5887 5888#if TclOnly8Bits 5889 result = Tcl_GlobalEvalObj(interp, cmdPtr); 5890#else 5891 result = Tcl_EvalObjEx (interp, cmdPtr, TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL); 5892#endif 5893 5894 Tcl_DecrRefCount (cmdPtr); 5895 resultObj = Tcl_GetObjResult (interp); 5896 Tcl_IncrRefCount (resultObj); 5897 5898 if (result != TCL_OK) { 5899 goto wrongScriptResult; 5900 } 5901 5902 result = Tcl_ListObjLength (interp, resultObj, &len); 5903 if ((result != TCL_OK) || (len != 3)) { 5904 goto wrongScriptResult; 5905 } 5906 result = Tcl_ListObjIndex (interp, resultObj, 0, &resultTypeObj); 5907 if (result != TCL_OK) { 5908 goto wrongScriptResult; 5909 } 5910 resultType = Tcl_GetString(resultTypeObj); 5911 if (strcmp (resultType, "string") == 0) { 5912 result = Tcl_ListObjIndex (interp, resultObj, 2, &xmlstringObj); 5913 xmlstring = Tcl_GetStringFromObj (xmlstringObj, &len); 5914 chan = NULL; 5915 } else if (strcmp (resultType, "channel") == 0) { 5916 xmlstring = NULL; 5917 len = 0; 5918 result = Tcl_ListObjIndex (interp, resultObj, 2, &channelIdObj); 5919 channelId = Tcl_GetString(channelIdObj); 5920 chan = Tcl_GetChannel (interp, channelId, &mode); 5921 if (chan == (Tcl_Channel) NULL) { 5922 goto wrongScriptResult; 5923 } 5924 if ((mode & TCL_READABLE) == 0) { 5925 *errMsg = tdomstrdup("-externalentitycommand returned a channel that wasn't opened for reading"); 5926 return NULL; 5927 } 5928 } else if (strcmp (resultType, "filename") == 0) { 5929 *errMsg = tdomstrdup("-externalentitycommand result type \"filename\" not yet implemented"); 5930 return NULL; 5931 } else { 5932 goto wrongScriptResult; 5933 } 5934 result = Tcl_ListObjIndex (interp, resultObj, 1, &extbaseObj); 5935 extbase = Tcl_GetString(extbaseObj); 5936 5937 /* Since stylesheets and source docouments have different white space 5938 stripping rules, an already parsed tree could only reused, if the 5939 'usage type' of the already present tree is the same as for the 5940 currently requested document */ 5941 sdoc = xs->subDocs; 5942 while (sdoc) { 5943 if (isStylesheet == sdoc->isStylesheet 5944 && sdoc->baseURI 5945 && strcmp(sdoc->baseURI, extbase) == 0) { 5946 Tcl_DecrRefCount (resultObj); 5947 return sdoc->doc; 5948 } 5949 sdoc = sdoc->next; 5950 } 5951 5952 if (xsltDoc->documentElement->nodeFlags & HAS_LINE_COLUMN) { 5953 storeLineColumn = 1; 5954 } else { 5955 storeLineColumn = 0; 5956 } 5957 5958 parser = XML_ParserCreate_MM (NULL, MEM_SUITE, NULL); 5959 5960 Tcl_ResetResult (interp); 5961 if (xsltDoc->extResolver) { 5962 extResolver = tdomstrdup (xsltDoc->extResolver); 5963 } 5964 /* keep white space, no fiddling with the encoding (is this 5965 a good idea?) */ 5966 doc = domReadDocument (parser, xmlstring, len, 0, 0, storeLineColumn, 0, 5967 chan, extbase, extResolver, 0, 5968 (int) XML_PARAM_ENTITY_PARSING_ALWAYS, interp); 5969 5970 if (doc == NULL) { 5971 DBG(fprintf (stderr, "parse error, str len %d, xmlstring: -->%s<--\n", 5972 strlen (xmlstring), xmlstring);) 5973 Tcl_DStringInit (&dStr); 5974 Tcl_DStringAppend (&dStr, "Error while processing external entity \"", 5975 -1); 5976 Tcl_DStringAppend (&dStr, href, -1); 5977 Tcl_DStringAppend (&dStr, "\":\n", -1); 5978 str = Tcl_GetStringResult (interp); 5979 if (str[0] == '\0') { 5980 Tcl_DStringAppend (&dStr, "At line ", -1); 5981 sprintf (s, "%ld", XML_GetCurrentLineNumber (parser)); 5982 Tcl_DStringAppend (&dStr, s, -1); 5983 Tcl_DStringAppend (&dStr, " character ", -1); 5984 sprintf (s, "%ld", XML_GetCurrentColumnNumber (parser)); 5985 Tcl_DStringAppend (&dStr, s, -1); 5986 Tcl_DStringAppend (&dStr, ": ", 2); 5987 Tcl_DStringAppend (&dStr, 5988 XML_ErrorString (XML_GetErrorCode(parser)), -1); 5989 } else { 5990 Tcl_DStringAppend (&dStr, str, -1); 5991 } 5992 *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); 5993 Tcl_DStringFree (&dStr); 5994 XML_ParserFree (parser); 5995 Tcl_DecrRefCount (resultObj); 5996 return NULL; 5997 } 5998 XML_ParserFree (parser); 5999 6000 /* TODO: If the stylesheet use the 6001 literal-result-element-as-stylesheet form, rewrite it to a 6002 "ordinary" stylesheet with root element xsl:stylesheet, with 6003 one template child with match pattern "/". */ 6004 6005 sdoc = (xsltSubDoc*)MALLOC(sizeof (xsltSubDoc)); 6006 sdoc->doc = doc; 6007 sdoc->baseURI = tdomstrdup (extbase); 6008 Tcl_InitHashTable (&(sdoc->keyData), TCL_STRING_KEYS); 6009 sdoc->excludeNS = NULL; 6010 sdoc->extensionNS = NULL; 6011 sdoc->fwCmpProcessing = 0; 6012 sdoc->mustFree = 1; 6013 sdoc->isStylesheet = isStylesheet; 6014 sdoc->fixedXMLSource = fixedXMLSource; 6015 if (isStylesheet) { 6016 if (addExclExtNS (sdoc, doc->documentElement, errMsg) < 0) { 6017 Tcl_DeleteHashTable (&(sdoc->keyData)); 6018 domFreeDocument (sdoc->doc, NULL, NULL); 6019 FREE (sdoc->baseURI); 6020 FREE (sdoc); 6021 Tcl_DecrRefCount (resultObj); 6022 return NULL; 6023 } 6024 StripXSLTSpace (doc->rootNode); 6025 } 6026 sdoc->next = xs->subDocs; 6027 xs->subDocs = sdoc; 6028 Tcl_DecrRefCount (resultObj); 6029 6030 return doc; 6031 6032 wrongScriptResult: 6033 *errMsg = tdomstrdup(Tcl_GetStringResult(interp)); 6034 Tcl_DecrRefCount (resultObj); 6035 return NULL; 6036} 6037 6038/*---------------------------------------------------------------------------- 6039| processTopLevelVars 6040| 6041\---------------------------------------------------------------------------*/ 6042static int processTopLevelVars ( 6043 domNode * xmlNode, 6044 xsltState * xs, 6045 char ** parameters, 6046 int ignoreUndeclaredParameters, 6047 char ** errMsg 6048 ) 6049{ 6050 int rc, i; 6051 char *select, prefix[MAX_PREFIX_LEN]; 6052 const char *localName; 6053 xpathResultSet nodeList, rs; 6054 Tcl_HashEntry *entryPtr; 6055 Tcl_HashSearch search; 6056 xsltTopLevelVar *topLevelVar; 6057 xsltVarInProcess varInProcess; 6058 xsltVariable *var; 6059 domNS *ns; 6060 Tcl_DString dStr; 6061 6062 xpathRSInit (&nodeList); 6063 rsAddNodeFast (&nodeList, xmlNode); 6064 6065 if (parameters) { 6066 i = 0; 6067 while (parameters[i]) { 6068 domSplitQName (parameters[i], prefix, &localName); 6069 ns = NULL; 6070 if (prefix[0] != '\0') { 6071 ns = domLookupPrefix (xs->xsltDoc->documentElement, prefix); 6072 if (!ns) { 6073 Tcl_DStringInit (&dStr); 6074 Tcl_DStringAppend (&dStr, "No namespace bound to prefix" 6075 " (passed parameter \"", -1); 6076 Tcl_DStringAppend (&dStr, parameters[i], -1); 6077 Tcl_DStringAppend (&dStr, "\")", -1); 6078 *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); 6079 Tcl_DStringFree (&dStr); 6080 xpathRSFree (&nodeList); 6081 return -1; 6082 } 6083 } 6084 Tcl_DStringInit (&dStr); 6085 if (ns) Tcl_DStringAppend (&dStr, ns->uri, -1); 6086 Tcl_DStringAppend (&dStr, localName, -1); 6087 entryPtr = Tcl_FindHashEntry (&xs->topLevelVars, 6088 Tcl_DStringValue (&dStr)); 6089 Tcl_DStringFree (&dStr); 6090 if (!entryPtr) { 6091 if (ignoreUndeclaredParameters) { 6092 i += 2; 6093 continue; 6094 } 6095 Tcl_DStringInit (&dStr); 6096 Tcl_DStringAppend (&dStr, "There isn't a parameter named \"", -1); 6097 Tcl_DStringAppend (&dStr, parameters[i], -1); 6098 Tcl_DStringAppend (&dStr, "\" defined at top level in the stylesheet.", -1); 6099 *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); 6100 Tcl_DStringFree (&dStr); 6101 xpathRSFree (&nodeList); 6102 return -1; 6103 } 6104 topLevelVar = (xsltTopLevelVar *) Tcl_GetHashValue (entryPtr); 6105 if (!topLevelVar->isParameter) { 6106 Tcl_DStringInit (&dStr); 6107 Tcl_DStringAppend (&dStr, "\"", 1); 6108 Tcl_DStringAppend (&dStr, parameters[i], -1); 6109 Tcl_DStringAppend (&dStr, "\" is defined as variable, not as parameter.", -1); 6110 *errMsg = tdomstrdup (Tcl_DStringValue (&dStr)); 6111 Tcl_DStringFree (&dStr); 6112 xpathRSFree (&nodeList); 6113 return -1; 6114 } 6115 if (xsltVarExists (xs, parameters[i], NULL)) { 6116 i += 2; 6117 continue; 6118 } 6119 6120 xpathRSInit (&rs); 6121 rsSetString (&rs, parameters[i+1]); 6122 6123 xs->varStackPtr++; 6124 if (xs->varStackPtr >= xs->varStackLen) { 6125 xs->varStack = (xsltVariable *) REALLOC ((char*)xs->varStack, 6126 sizeof (xsltVariable) 6127 * 2*xs->varStackLen); 6128 xs->varStackLen *= 2; 6129 } 6130 var = &(xs->varStack[xs->varStackPtr]); 6131 if (!xs->varFramesStack->nrOfVars) { 6132 xs->varFramesStack->varStartIndex = xs->varStackPtr; 6133 } 6134 xs->varFramesStack->nrOfVars++; 6135 var->name = localName; 6136 if (ns) var->uri = ns->uri; 6137 else var->uri = NULL; 6138 var->node = topLevelVar->node; 6139 var->rs = rs; 6140 var->active = 1; 6141 6142 i += 2; 6143 } 6144 } 6145 for (entryPtr = Tcl_FirstHashEntry(&xs->topLevelVars, &search); 6146 entryPtr != (Tcl_HashEntry*) NULL; 6147 entryPtr = Tcl_NextHashEntry(&search)) { 6148 topLevelVar = (xsltTopLevelVar *)Tcl_GetHashValue (entryPtr); 6149 if (xsltVarExists (xs, topLevelVar->name, topLevelVar->node)) { 6150 continue; 6151 } 6152 varInProcess.name = topLevelVar->name; 6153 varInProcess.next = NULL; 6154 xs->varsInProcess = &varInProcess; 6155 6156 xs->currentXSLTNode = topLevelVar->node; 6157 select = getAttr (topLevelVar->node, "select", a_select); 6158 if (select && topLevelVar->node->firstChild) { 6159 xpathRSFree (&nodeList); 6160 reportError (topLevelVar->node, "xsl:variable and xsl:param" 6161 " elements with a select attribute must be empty", 6162 errMsg); 6163 return -1; 6164 } 6165 rc = xsltSetVar(xs, topLevelVar->name, &nodeList, xmlNode, 0, select, 6166 topLevelVar->node, 1, errMsg); 6167 if (rc < 0) { 6168 xpathRSFree (&nodeList); 6169 return rc; 6170 } 6171 } 6172 xpathRSFree (&nodeList); 6173 xs->currentXSLTNode = NULL; 6174 xs->varsInProcess = NULL; 6175 return 0; 6176} 6177 6178/*---------------------------------------------------------------------------- 6179| processTopLevel 6180| 6181\---------------------------------------------------------------------------*/ 6182static int processTopLevel ( 6183 Tcl_Interp * interp, 6184 domNode * xsltDocumentElement, 6185 xsltState * xs, 6186 double precedence, 6187 double * precedenceLowBound, 6188 char ** errMsg 6189) 6190{ 6191 domNode *node; 6192 domDocument *extStyleSheet; 6193 int rc, hnew, clen, newdf = 0, nonImportElemSeen = 0; 6194 int ignore; 6195 double childPrecedence, childLowBound; 6196 char *str, *name, *match, *use, *href; 6197 char prefix[MAX_PREFIX_LEN]; 6198 const char *localName, *baseURI; 6199 xsltTag tag; 6200 xsltAttrSet *attrSet; 6201 xsltKeyInfo *keyInfo; 6202 xsltDecimalFormat *df; 6203 xsltTopLevelVar *topLevelVar; 6204 xsltNSAlias *nsAlias; 6205 domNS *ns, *nsFrom, *nsTo; 6206 Tcl_HashEntry *h; 6207 Tcl_DString dStr; 6208 6209 6210 DBG(fprintf (stderr, "start processTopLevel. precedence: %f precedenceLowBound %f\n", precedence, *precedenceLowBound);); 6211 node = xsltDocumentElement->firstChild; 6212 while (node) { 6213 tag = getTag (node); 6214 if (!nonImportElemSeen && tag != unknown && tag != import) { 6215 nonImportElemSeen = 1; 6216 } 6217 switch ( tag ) { 6218 6219 case attributeSet: 6220 str = getAttr(node, "name", a_name); 6221 if (str) { 6222 domSplitQName (str, prefix, &localName); 6223 ns = NULL; 6224 if (prefix[0] != '\0') { 6225 ns = domLookupPrefix (node, prefix); 6226 if (!ns) { 6227 reportError (node, "There isn't a namespace" 6228 " bound to the prefix.", errMsg); 6229 return -1; 6230 } 6231 } 6232 if (xs->attrSets) { 6233 attrSet = xs->attrSets; 6234 while (attrSet->next) attrSet = attrSet->next; 6235 attrSet->next = 6236 (xsltAttrSet*)MALLOC(sizeof(xsltAttrSet)); 6237 attrSet = attrSet->next; 6238 } else { 6239 attrSet = (xsltAttrSet*)MALLOC(sizeof(xsltAttrSet)); 6240 xs->attrSets = attrSet; 6241 } 6242 attrSet->next = NULL; 6243 attrSet->content = node; 6244 attrSet->name = localName; 6245 if (ns) { 6246 attrSet->uri = ns->uri; 6247 } else { 6248 attrSet->uri = NULL; 6249 } 6250 } else { 6251 reportError (node, "xsl:attribute-set: missing mandatory" 6252 " attribute \"name\".", errMsg); 6253 return -1; 6254 } 6255 break; 6256 6257 case decimalFormat: 6258 if (node->firstChild) { 6259 reportError (node, "xsl:decimal-format has to be empty.", 6260 errMsg); 6261 return -1; 6262 } 6263 str = getAttr(node, "name", a_name); 6264 if (str) { 6265 domSplitQName (str, prefix, &localName); 6266 ns = NULL; 6267 if (prefix[0] != '\0') { 6268 ns = domLookupPrefix (node, prefix); 6269 if (!ns) { 6270 reportError (node, "There isn't a namespace bound" 6271 " to the prefix.", errMsg); 6272 return -1; 6273 } 6274 } 6275 /* a named decimal format */ 6276 df = xs->decimalFormats->next; 6277 while (df) { 6278 if (strcmp(df->name, str)==0 6279 && ((df->uri == NULL && ns == NULL) 6280 || (df->uri != NULL 6281 && ns != NULL 6282 && (strcmp (df->uri, ns->uri)==0)))) { 6283 /* already existing, override it */ 6284 break; 6285 } 6286 df = df->next; 6287 } 6288 if (df == NULL) { 6289 df = (xsltDecimalFormat*)MALLOC(sizeof(xsltDecimalFormat)); 6290 memset (df, 0, sizeof (xsltDecimalFormat)); 6291 newdf = 1; 6292 /* initialize to defaults */ 6293#if TclOnly8Bits 6294 df->decimalSeparator = '.'; 6295 df->groupingSeparator = ','; 6296 df->infinity = "Infinity"; 6297 df->minusSign = '-'; 6298 df->NaN = "NaN"; 6299 df->percent = '%'; 6300 df->zeroDigit = '0'; 6301 df->digit = '#'; 6302 df->patternSeparator = ';'; 6303#else 6304 df->decimalSeparator = 46; 6305 df->groupingSeparator = 44; 6306 df->infinity = "Infinity"; 6307 df->minusSign = 45; 6308 df->NaN = "NaN"; 6309 df->percent = 37; 6310 df->perMille = 0x2030; 6311 df->zeroDigit = 48; 6312 df->digit = 35; 6313 df->patternSeparator = 59; 6314#endif /* TclOnly8Bits */ 6315 df->name = tdomstrdup(str); 6316 if (ns) df->uri = tdomstrdup(ns->uri); 6317 else df->uri = NULL; 6318 /* prepend into list of decimal format 6319 after the default one */ 6320 df->next = xs->decimalFormats->next; 6321 xs->decimalFormats->next = df; 6322 } 6323 } else { 6324 /* definitions for default decimal format */ 6325 df = xs->decimalFormats; 6326 } 6327 str = getAttr(node, "decimal-separator", a_decimalSeparator); 6328 if (str) { 6329#if TclOnly8Bits 6330 if (str[1] != '\0') { 6331 reportError (node, "decimal-separator has to be a" 6332 " single char", errMsg); 6333 if (newdf) FREE((char*)df); 6334 return -1; 6335 } 6336 df->decimalSeparator = str[0]; 6337#else 6338 clen = UTF8_CHAR_LEN (str[0]); 6339 if (str[clen] != '\0') { 6340 reportError (node, "decimal-separator has to be a" 6341 " single char", errMsg); 6342 if (newdf) FREE((char*)df); 6343 return -1; 6344 } 6345 Tcl_UtfToUniChar (str, &df->decimalSeparator); 6346#endif /* TclOnly8Bits */ 6347 } 6348 str = getAttr(node, "grouping-separator", a_groupingSeparator); 6349 if (str) { 6350#if TclOnly8Bits 6351 if (str[1] != '\0') { 6352 reportError (node, "grouping-separator has to be a" 6353 " single char", errMsg); 6354 if (newdf) FREE((char*)df); 6355 return -1; 6356 } 6357 df->groupingSeparator = str[0]; 6358#else 6359 clen = UTF8_CHAR_LEN (str[0]); 6360 if (str[clen] != '\0') { 6361 reportError (node, "groupingSeparator has to be a" 6362 " single char", errMsg); 6363 if (newdf) FREE((char*)df); 6364 return -1; 6365 } 6366 Tcl_UtfToUniChar (str, &df->groupingSeparator); 6367#endif /* TclOnly8Bits */ 6368 } 6369 str = getAttr(node, "infinity", a_infinity); 6370 if (str) df->infinity = str; 6371 str = getAttr(node, "minus-sign", a_minusSign); 6372 if (str) { 6373#if TclOnly8Bits 6374 if (str[1] != '\0') { 6375 reportError (node, "minus-sign has to be a single" 6376 " char", errMsg); 6377 return -1; 6378 } 6379 df->minusSign = str[0]; 6380#else 6381 clen = UTF8_CHAR_LEN (str[0]); 6382 if (str[clen] != '\0') { 6383 reportError (node, "minus-sign has to be a single" 6384 " char", errMsg); 6385 if (newdf) FREE((char*)df); 6386 return -1; 6387 } 6388 Tcl_UtfToUniChar (str, &df->minusSign); 6389#endif /* TclOnly8Bits */ 6390 } 6391 str = getAttr(node, "NaN", a_nan); 6392 if (str) df->NaN = str; 6393 str = getAttr(node, "percent", a_percent); 6394 if (str) { 6395#if TclOnly8Bits 6396 if (str[1] != '\0') { 6397 reportError (node, "percent has to be a single" 6398 " char", errMsg); 6399 return -1; 6400 } 6401 df->percent = str[0]; 6402#else 6403 clen = UTF8_CHAR_LEN (str[0]); 6404 if (str[clen] != '\0') { 6405 reportError (node, "percent has to be a single" 6406 " char", errMsg); 6407 if (newdf) FREE((char*)df); 6408 return -1; 6409 } 6410 Tcl_UtfToUniChar (str, &df->percent); 6411#endif /* TclOnly8Bits */ 6412 } 6413 str = getAttr(node, "per-mille", a_perMille); 6414 if (str) { 6415#if TclOnly8Bits 6416 reportError (node, "User defined per-mille sign not" 6417 " supported, sorry.", errMsg); 6418 return -1; 6419#else 6420 clen = UTF8_CHAR_LEN (str[0]); 6421 if (str[clen] != '\0') { 6422 reportError (node, "per-mille has to be a single" 6423 " char", errMsg); 6424 if (newdf) FREE((char*)df); 6425 return -1; 6426 } 6427 Tcl_UtfToUniChar (str, &df->perMille); 6428#endif /* TclOnly8Bits */ 6429 } 6430 str = getAttr(node, "zero-digit", a_zeroDigit); 6431 if (str) { 6432#if TclOnly8Bits 6433 if (str[1] != '\0') { 6434 reportError (node, "zero-digit has to be a single" 6435 " char", errMsg); 6436 return -1; 6437 } 6438 df->zeroDigit = str[0]; 6439#else 6440 clen = UTF8_CHAR_LEN (str[0]); 6441 if (str[clen] != '\0') { 6442 reportError (node, "zero-digit has to be a single" 6443 " char", errMsg); 6444 if (newdf) FREE((char*)df); 6445 return -1; 6446 } 6447 Tcl_UtfToUniChar (str, &df->zeroDigit); 6448#endif /* TclOnly8Bits */ 6449 } 6450 str = getAttr(node, "digit", a_digit); 6451 if (str) { 6452#if TclOnly8Bits 6453 if (str[1] != '\0') { 6454 reportError (node, "digit has to be a single char", 6455 errMsg); 6456 return -1; 6457 } 6458 df->digit = str[0]; 6459#else 6460 clen = UTF8_CHAR_LEN (str[0]); 6461 if (str[clen] != '\0') { 6462 reportError (node, "digit has to be a single char", 6463 errMsg); 6464 if (newdf) FREE((char*)df); 6465 return -1; 6466 } 6467 Tcl_UtfToUniChar (str, &df->digit); 6468#endif /* TclOnly8Bits */ 6469 } 6470 str = getAttr(node, "pattern-separator", a_patternSeparator); 6471 if (str) { 6472#if TclOnly8Bits 6473 if (str[1] != '\0') { 6474 reportError (node, "pattern-separator has to be a" 6475 " single char", errMsg); 6476 return -1; 6477 } 6478 df->patternSeparator = str[0]; 6479#else 6480 clen = UTF8_CHAR_LEN (str[0]); 6481 if (str[clen] != '\0') { 6482 reportError (node, "pattern-separator has to be a" 6483 " single char", errMsg); 6484 return -1; 6485 } 6486 Tcl_UtfToUniChar (str, &df->patternSeparator); 6487#endif /* TclOnly8Bits */ 6488 } 6489 break; 6490 6491 case import: 6492 if (nonImportElemSeen) { 6493 reportError (node, "xsl:import elements must come first", 6494 errMsg); 6495 return -1; 6496 } 6497 if (node->firstChild) { 6498 reportError (node, "xsl:import has to be empty!", errMsg); 6499 return -1; 6500 } 6501 if (!node->ownerDocument->extResolver) { 6502 reportError (node, "need resolver Script to include" 6503 " Stylesheet! (use" 6504 " \"-externalentitycommand\")", errMsg); 6505 return -1; 6506 } 6507 baseURI = findBaseURI (node); 6508 href = getAttr (node, "href", a_href); 6509 if (!href) { 6510 reportError (node, "xsl:import: missing mandatory" 6511 " attribute \"href\".", errMsg); 6512 return -1; 6513 } 6514 extStyleSheet = getExternalDocument (interp, xs, 6515 node->ownerDocument, 6516 baseURI, href, 1, 0, 6517 errMsg); 6518 if (!extStyleSheet) { 6519 return -1; 6520 } 6521 childPrecedence = (precedence + *precedenceLowBound) / 2; 6522 childLowBound = *precedenceLowBound; 6523 rc = processTopLevel (interp, extStyleSheet->documentElement, 6524 xs, childPrecedence, &childLowBound, 6525 errMsg); 6526 *precedenceLowBound = childPrecedence; 6527 if (rc != 0) { 6528 return rc; 6529 } 6530 break; 6531 6532 case include: 6533 if (node->firstChild) { 6534 reportError (node, "xsl:include has to be empty.", errMsg); 6535 return -1; 6536 } 6537 if (!node->ownerDocument->extResolver) { 6538 reportError (node, "need resolver Script to include" 6539 "Stylesheet. (use" 6540 " \"-externalentitycommand\")", errMsg); 6541 return -1; 6542 } 6543 baseURI = findBaseURI (node); 6544 href = getAttr (node, "href", a_href); 6545 if (!href) { 6546 reportError (node, "xsl:include: missing mandatory" 6547 " attribute \"href\".", errMsg); 6548 return -1; 6549 } 6550 extStyleSheet = getExternalDocument (interp, xs, 6551 node->ownerDocument, 6552 baseURI, href, 1, 0, 6553 errMsg); 6554 if (!extStyleSheet) { 6555 return -1; 6556 } 6557 xs->currentXSLTNode = extStyleSheet->documentElement; 6558 rc = processTopLevel (interp, extStyleSheet->documentElement, 6559 xs, precedence, precedenceLowBound, 6560 errMsg); 6561 if (rc != 0) { 6562 return rc; 6563 } 6564 break; 6565 6566 case key: 6567 if (node->firstChild) { 6568 reportError (node, "xsl:key has to be empty.", errMsg); 6569 return -1; 6570 } 6571 name = getAttr(node, "name", a_name); 6572 if (!name) { 6573 reportError (node, "xsl:key: missing mandatory" 6574 " attribute \"name\".", errMsg); 6575 return -1; 6576 } 6577 match = getAttr(node, "match", a_match); 6578 if (!match) { 6579 reportError (node, "xsl:key: missing mandatory" 6580 " attribute \"match\".", errMsg); 6581 return -1; 6582 } 6583 use = getAttr(node, "use", a_use); 6584 if (!use) { 6585 reportError (node, "xsl:key: missing mandatory" 6586 " attribute \"use\".", errMsg); 6587 return -1; 6588 } 6589 6590 keyInfo = (xsltKeyInfo *)MALLOC(sizeof(xsltKeyInfo)); 6591 keyInfo->node = node; 6592 rc = xpathParse (match, node, XPATH_KEY_MATCH_PATTERN, NULL, 6593 NULL, &(keyInfo->matchAst), errMsg); 6594 if (rc < 0) { 6595 reportError (node, *errMsg, errMsg); 6596 free ((char*)keyInfo); 6597 return rc; 6598 } 6599 keyInfo->use = use; 6600 rc = xpathParse (use, node, XPATH_KEY_USE_EXPR, NULL, 6601 NULL, &(keyInfo->useAst), errMsg); 6602 if (rc < 0) { 6603 reportError (node, *errMsg, errMsg); 6604 xpathFreeAst (keyInfo->matchAst); 6605 free ((char*)keyInfo); 6606 return rc; 6607 } 6608 domSplitQName (name, prefix, &localName); 6609 Tcl_DStringInit (&dStr); 6610 if (prefix[0] != '\0') { 6611 ns = domLookupPrefix (node, prefix); 6612 if (!ns) { 6613 reportError (node, "There isn't a namespace bound" 6614 " to the prefix.", errMsg); 6615 xpathFreeAst (keyInfo->matchAst); 6616 xpathFreeAst (keyInfo->useAst); 6617 FREE((char*)keyInfo); 6618 return -1; 6619 } 6620 Tcl_DStringAppend (&dStr, ns->uri, -1); 6621 } 6622 Tcl_DStringAppend (&dStr, localName, -1); 6623 h = Tcl_CreateHashEntry (&(xs->keyInfos), 6624 Tcl_DStringValue (&dStr), &hnew); 6625 Tcl_DStringFree (&dStr); 6626 if (hnew) { 6627 keyInfo->next = NULL; 6628 } else { 6629 keyInfo->next = (xsltKeyInfo *)Tcl_GetHashValue (h); 6630 } 6631 Tcl_SetHashValue (h, keyInfo); 6632 break; 6633 6634 case namespaceAlias: 6635 if (node->firstChild) { 6636 reportError (node, "xsl:namespace-alias has to be empty.", 6637 errMsg); 6638 return -1; 6639 } 6640 6641 str = getAttr (node, "stylesheet-prefix", a_stylesheetPrefix); 6642 if (!str) { 6643 reportError (node, "xsl:namespace-alias: missing" 6644 " mandatory attribute" 6645 " \"stylesheet-prefix\".", errMsg); 6646 return -1 ; 6647 } 6648 if (strcmp (str, "#default")==0) { 6649 str = NULL; 6650 nsFrom = domLookupPrefix (node, ""); 6651 } else { 6652 nsFrom = domLookupPrefix (node, str); 6653 } 6654 if (!nsFrom) { 6655 reportError (node, "xsl:namespace-alias: no namespace" 6656 " bound to the \"stylesheet-prefix\".", 6657 errMsg); 6658 return -1; 6659 } 6660 6661 str = getAttr (node, "result-prefix", a_resultPrefix); 6662 if (!str) { 6663 reportError (node, "xsl:namespace-alias: missing mandatory" 6664 " attribute \"result-prefix\".", errMsg); 6665 return -1; 6666 } 6667 if (strcmp (str, "#default")==0) { 6668 nsTo = domLookupPrefix (node, ""); 6669 } else { 6670 nsTo = domLookupPrefix (node, str); 6671 } 6672 if (!nsTo) { 6673 reportError (node, "xsl:namespace-alias: no namespace" 6674 " bound to the \"result-prefix\".", errMsg); 6675 return -1; 6676 } 6677 6678 nsAlias = xs->nsAliases; 6679 ignore = 0; 6680 while (nsAlias) { 6681 if (strcmp (nsAlias->fromUri, nsFrom->uri)==0) { 6682 if (nsAlias->precedence > precedence) { 6683 ignore = 1; 6684 } 6685 break; 6686 } 6687 nsAlias = nsAlias->next; 6688 } 6689 if (ignore) break; 6690 if (nsAlias) { 6691 FREE(nsAlias->toUri); 6692 } else { 6693 nsAlias = (xsltNSAlias *)MALLOC(sizeof (xsltNSAlias)); 6694 nsAlias->fromUri = tdomstrdup (nsFrom->uri); 6695 nsAlias->next = xs->nsAliases; 6696 xs->nsAliases = nsAlias; 6697 } 6698 nsAlias->toUri = tdomstrdup (nsTo->uri); 6699 nsAlias->precedence = precedence; 6700 break; 6701 6702 case output: 6703 if (node->firstChild) { 6704 reportError (node, "xsl:output has to be empty.", errMsg); 6705 return -1; 6706 } 6707 str = getAttr(node, "method", a_method); 6708 if (str) { 6709 if (xs->doctype.method) FREE(xs->doctype.method); 6710 xs->doctype.method = tdomstrdup(str); 6711 } 6712 str = getAttr(node, "encoding", a_encoding); 6713 if (str) { 6714 if (xs->doctype.encoding) FREE(xs->doctype.encoding); 6715 xs->doctype.encoding = tdomstrdup(str); 6716 } 6717 str = getAttr(node, "omit-xml-declaration", 6718 a_omitXMLDeclaration); 6719 if (str) { 6720 if (strcmp (str, "yes") == 0) { 6721 xs->doctype.omitXMLDeclaration = 1; 6722 } else if (strcmp (str, "no") == 0) { 6723 xs->doctype.omitXMLDeclaration = 0; 6724 } else { 6725 reportError (node, "Unexpected value for" 6726 " 'omit-xml-declaration' attribute", 6727 errMsg); 6728 return -1; 6729 } 6730 } 6731 str = getAttr(node, "standalone", a_standalone); 6732 if (str) { 6733 if (strcmp (str, "yes") == 0) { 6734 xs->doctype.standalone = 1; 6735 } else if (strcmp (str, "no") == 0) { 6736 xs->doctype.standalone = 0; 6737 } else { 6738 reportError (node, "Unexpected value for 'standalone'" 6739 " attribute", errMsg); 6740 return -1; 6741 } 6742 } 6743 str = getAttr(node, "doctype-public", a_doctypePublic); 6744 if (str) { 6745 if (xs->doctype.publicId) { 6746 FREE ((char*) xs->doctype.publicId); 6747 } 6748 xs->doctype.publicId = tdomstrdup(str); 6749 } 6750 str = getAttr(node, "doctype-system", a_doctypeSystem); 6751 if (str) { 6752 if (xs->doctype.systemId) { 6753 FREE ((char*) xs->doctype.systemId); 6754 } 6755 xs->doctype.systemId = tdomstrdup(str); 6756 } 6757 str = getAttr(node, "cdata-section-elements", 6758 a_cdataSectionElements); 6759 if (str) { 6760 if (!xs->doctype.cdataSectionElements) { 6761 xs->doctype.cdataSectionElements = 6762 (Tcl_HashTable *) MALLOC (sizeof (Tcl_HashTable)); 6763 Tcl_InitHashTable (xs->doctype.cdataSectionElements, 6764 TCL_STRING_KEYS); 6765 } 6766 if (!getCdataSectionElements (node, str, 6767 xs->doctype.cdataSectionElements, errMsg)) { 6768 return -1; 6769 } 6770 } 6771 str = getAttr(node, "indent", a_indent); 6772 if (str) { 6773 if (strcmp (str, "yes") == 0) { 6774 xs->indentOutput = 1; 6775 } else if (strcmp (str, "no") == 0) { 6776 xs->indentOutput = 0; 6777 } else { 6778 reportError (node, "Unexpected value for 'indent'" 6779 " attribute.", errMsg); 6780 return -1; 6781 } 6782 } 6783 str = getAttr(node, "media-type", a_mediaType); 6784 if (str) { 6785 if (xs->doctype.mediaType) FREE(xs->doctype.mediaType); 6786 xs->doctype.mediaType = tdomstrdup(str); 6787 } 6788 break; 6789 6790 case preserveSpace: 6791 if (node->firstChild) { 6792 reportError (node, "xsl:preserve-space has to be empty.", 6793 errMsg); 6794 return -1; 6795 } 6796 str = getAttr(node, "elements", a_elements); 6797 if (str) { 6798 rc = fillElementList(&xs->wsInfo, 0, precedence, 6799 node, str, errMsg); 6800 CHECK_RC; 6801 } else { 6802 reportError (node, "xsl:preserve-space: missing required" 6803 " attribute \"elements\".", errMsg); 6804 return -1; 6805 } 6806 break; 6807 6808 case stripSpace: 6809 if (node->firstChild) { 6810 reportError (node, "xsl:strip-space has to be empty.", 6811 errMsg); 6812 return -1; 6813 } 6814 str = getAttr(node, "elements", a_elements); 6815 if (str) { 6816 rc = fillElementList(&xs->wsInfo, 1, precedence, node, 6817 str, errMsg); 6818 CHECK_RC; 6819 } else { 6820 reportError (node, "xsl:strip-space: missing required" 6821 " attribute \"elements\".", errMsg); 6822 return -1; 6823 } 6824 break; 6825 6826 case template: 6827 rc = xsltAddTemplate (xs, node, precedence, errMsg); 6828 CHECK_RC; 6829 break; 6830 6831 case param: 6832 case variable: 6833 str = getAttr(node, "name", a_name); 6834 if (!str) { 6835 reportError (node, "xsl:variable and xsl:param elements" 6836 " must have a \"name\" attribute.", errMsg); 6837 return -1; 6838 } 6839 domSplitQName (str, prefix, &localName); 6840 ns = NULL; 6841 if (prefix[0] != '\0') { 6842 ns = domLookupPrefix (node, prefix); 6843 if (!ns) { 6844 reportError (node, "There isn't a namespace bound" 6845 " to the prefix.", errMsg); 6846 return -1; 6847 } 6848 } 6849 Tcl_DStringInit (&dStr); 6850 if (ns) { 6851 Tcl_DStringAppend (&dStr, ns->uri, -1); 6852 } 6853 Tcl_DStringAppend (&dStr, localName, -1); 6854 h = Tcl_CreateHashEntry (&(xs->topLevelVars), 6855 Tcl_DStringValue (&dStr), &hnew); 6856 Tcl_DStringFree (&dStr); 6857 if (!hnew) { 6858 topLevelVar = (xsltTopLevelVar *)Tcl_GetHashValue (h); 6859 /* Since imported stylesheets are processed at the 6860 point at which they encounters the definitions are 6861 already in increasing order of import precedence. 6862 Therefor we have only to check, if there is a 6863 top level var or parm with the same precedence */ 6864 if (topLevelVar->precedence == precedence) { 6865 reportError (node, "There is already a variable" 6866 " or parameter with this name with the" 6867 " same import precedence.", errMsg); 6868 return -1; 6869 } 6870 } else { 6871 topLevelVar = (xsltTopLevelVar *) 6872 MALLOC (sizeof (xsltTopLevelVar)); 6873 Tcl_SetHashValue (h, topLevelVar); 6874 } 6875 topLevelVar->node = node; 6876 topLevelVar->name = str; 6877 if (tag == param) { 6878 topLevelVar->isParameter = 1; 6879 } else { 6880 topLevelVar->isParameter = 0; 6881 } 6882 topLevelVar->precedence = precedence; 6883 6884 break; 6885 6886 default: 6887 if (node->nodeType == ELEMENT_NODE) { 6888 if (!node->namespace) { 6889 reportError (node, "Top level elements must have a" 6890 " non-null namespace URI.", errMsg); 6891 return -1; 6892 } 6893 if (strcmp (XSLT_NAMESPACE, domNamespaceURI (node))==0) { 6894 if (!xs->currentSubDoc->fwCmpProcessing) { 6895 reportError (node, "XSLT element not allowed" 6896 " on top level or unknown XSLT" 6897 " element.", errMsg); 6898 6899 return -1; 6900 } 6901 } 6902 } else if (node->nodeType == TEXT_NODE) { 6903 char *pc; 6904 int i, only_whites; 6905 6906 only_whites = 1; 6907 for (i=0, pc = ((domTextNode*)node)->nodeValue; 6908 i < ((domTextNode*)node)->valueLength; 6909 i++, pc++) { 6910 if (!IS_XML_WHITESPACE(*pc)) { 6911 only_whites = 0; 6912 break; 6913 } 6914 } 6915 if (!only_whites) { 6916 reportError (node, "Non-whitespace text is not" 6917 " allowed between top level elements.", 6918 errMsg); 6919 return -1; 6920 } 6921 } 6922 6923 break; 6924 } 6925 node = node->nextSibling; 6926 } 6927 return 0; 6928} 6929 6930/*---------------------------------------------------------------------------- 6931| xsltFreeState 6932| 6933\---------------------------------------------------------------------------*/ 6934static void 6935xsltFreeState ( 6936 xsltState * xs 6937) { 6938 xsltDecimalFormat *df, *dfsave; 6939 xsltKeyInfo *ki, *kisave; 6940 xsltNodeSet *kvalues; 6941 xsltSubDoc *sd, *sdsave; 6942 xsltAttrSet *as, *assave; 6943 xsltTemplate *tpl, *tplsave; 6944 xsltNumberFormat *nf; 6945 ast t; 6946 xsltTopLevelVar *tlv; 6947 xsltNSAlias *nsAlias, *nsAliasSave; 6948 xsltExclExtNS *eNS, *eNSsave; 6949 Tcl_HashEntry *entryPtr, *entryPtr1; 6950 Tcl_HashSearch search, search1; 6951 Tcl_HashTable *htable; 6952 double *f; 6953 6954 6955 if (xs->doctype.systemId) FREE(xs->doctype.systemId); 6956 if (xs->doctype.publicId) FREE(xs->doctype.publicId); 6957 if (xs->doctype.internalSubset) FREE(xs->doctype.internalSubset); 6958 if (xs->doctype.cdataSectionElements) { 6959 Tcl_DeleteHashTable (xs->doctype.cdataSectionElements); 6960 FREE (xs->doctype.cdataSectionElements); 6961 } 6962 for (entryPtr = Tcl_FirstHashEntry (&xs->namedTemplates, &search); 6963 entryPtr != (Tcl_HashEntry*) NULL; 6964 entryPtr = Tcl_NextHashEntry (&search)) { 6965 tpl = (xsltTemplate *) Tcl_GetHashValue (entryPtr); 6966 if (!tpl->match) { 6967 FREE(tpl); 6968 } 6969 } 6970 Tcl_DeleteHashTable (&xs->namedTemplates); 6971 6972 for (entryPtr = Tcl_FirstHashEntry (&xs->isElementTpls, &search); 6973 entryPtr != (Tcl_HashEntry*) NULL; 6974 entryPtr = Tcl_NextHashEntry (&search)) { 6975 tpl = (xsltTemplate *) Tcl_GetHashValue (entryPtr); 6976 while (tpl) { 6977 if (tpl->freeAst) xpathFreeAst (tpl->freeAst); 6978 tplsave = tpl; 6979 tpl = tpl->next; 6980 FREE(tplsave); 6981 } 6982 } 6983 Tcl_DeleteHashTable (&xs->isElementTpls); 6984 6985 for (entryPtr = Tcl_FirstHashEntry(&xs->xpaths, &search); 6986 entryPtr != (Tcl_HashEntry*) NULL; 6987 entryPtr = Tcl_NextHashEntry(&search)) { 6988 t = (ast) Tcl_GetHashValue (entryPtr); 6989 xpathFreeAst (t); 6990 } 6991 Tcl_DeleteHashTable(&xs->xpaths); 6992 6993 for (entryPtr = Tcl_FirstHashEntry(&xs->pattern, &search); 6994 entryPtr != (Tcl_HashEntry*) NULL; 6995 entryPtr = Tcl_NextHashEntry(&search)) { 6996 t = (ast) Tcl_GetHashValue (entryPtr); 6997 xpathFreeAst (t); 6998 } 6999 Tcl_DeleteHashTable(&xs->pattern); 7000 7001 for (entryPtr = Tcl_FirstHashEntry(&xs->formats, &search); 7002 entryPtr != (Tcl_HashEntry*) NULL; 7003 entryPtr = Tcl_NextHashEntry(&search)) { 7004 nf = (xsltNumberFormat *) Tcl_GetHashValue (entryPtr); 7005 FREE(nf->tokens); 7006 FREE(nf); 7007 } 7008 Tcl_DeleteHashTable(&xs->formats); 7009 7010 if (&xs->topLevelVars) { 7011 for (entryPtr = Tcl_FirstHashEntry(&xs->topLevelVars, &search); 7012 entryPtr != (Tcl_HashEntry*) NULL; 7013 entryPtr = Tcl_NextHashEntry(&search)) { 7014 tlv = (xsltTopLevelVar *) Tcl_GetHashValue (entryPtr); 7015 FREE(tlv); 7016 } 7017 Tcl_DeleteHashTable (&xs->topLevelVars); 7018 } 7019 7020 /*--- free key definition information ---*/ 7021 for (entryPtr = Tcl_FirstHashEntry (&xs->keyInfos, &search); 7022 entryPtr != (Tcl_HashEntry*) NULL; 7023 entryPtr = Tcl_NextHashEntry (&search)) { 7024 ki = (xsltKeyInfo *) Tcl_GetHashValue (entryPtr); 7025 while (ki) { 7026 kisave = ki; 7027 ki = ki->next; 7028 xpathFreeAst (kisave->matchAst); 7029 xpathFreeAst (kisave->useAst); 7030 FREE(kisave); 7031 } 7032 } 7033 Tcl_DeleteHashTable (&xs->keyInfos); 7034 7035 /*--- free sub documents ---*/ 7036 sd = xs->subDocs; 7037 while (sd) { 7038 sdsave = sd; 7039 sd = sd->next; 7040 for (entryPtr = Tcl_FirstHashEntry (&sdsave->keyData, &search); 7041 entryPtr != (Tcl_HashEntry*) NULL; 7042 entryPtr = Tcl_NextHashEntry (&search)) { 7043 htable = (Tcl_HashTable *) Tcl_GetHashValue (entryPtr); 7044 for (entryPtr1 = Tcl_FirstHashEntry (htable, &search1); 7045 entryPtr1 != (Tcl_HashEntry*) NULL; 7046 entryPtr1 = Tcl_NextHashEntry (&search1)) { 7047 kvalues = (xsltNodeSet *) Tcl_GetHashValue (entryPtr1); 7048 FREE(kvalues->nodes); 7049 FREE(kvalues); 7050 } 7051 Tcl_DeleteHashTable (htable); 7052 FREE(htable); 7053 } 7054 Tcl_DeleteHashTable (&sdsave->keyData); 7055 eNS = sdsave->excludeNS; 7056 while (eNS) { 7057 if (eNS->uri) FREE(eNS->uri); 7058 eNSsave = eNS; 7059 eNS = eNS->next; 7060 FREE(eNSsave); 7061 } 7062 eNS = sdsave->extensionNS; 7063 while (eNS) { 7064 if (eNS->uri) FREE(eNS->uri); 7065 eNSsave = eNS; 7066 eNS = eNS->next; 7067 FREE(eNSsave); 7068 } 7069 if (sdsave->baseURI) FREE(sdsave->baseURI); 7070 if (sdsave->mustFree) { 7071 domFreeDocument (sdsave->doc, NULL, NULL); 7072 } 7073 FREE(sdsave); 7074 } 7075 7076 nsAlias = xs->nsAliases; 7077 while (nsAlias) { 7078 nsAliasSave = nsAlias; 7079 nsAlias = nsAlias->next; 7080 if (nsAliasSave->fromUri) FREE(nsAliasSave->fromUri); 7081 if (nsAliasSave->toUri) FREE(nsAliasSave->toUri); 7082 FREE(nsAliasSave); 7083 } 7084 7085 /*--- free decimal formats ---*/ 7086 df = xs->decimalFormats; 7087 while (df) { 7088 dfsave = df; 7089 df = df->next; 7090 if (dfsave->name) FREE(dfsave->name); 7091 if (dfsave->uri) FREE(dfsave->uri); 7092 FREE(dfsave); 7093 } 7094 7095 /*--- free attribute sets ---*/ 7096 as = xs->attrSets; 7097 while (as) { 7098 assave = as; 7099 as = as->next; 7100 FREE(assave); 7101 } 7102 7103 /*--- free templates ---*/ 7104 tpl = xs->templates; 7105 while (tpl) { 7106 tplsave = tpl; 7107 if (tpl->freeAst) xpathFreeAst (tpl->freeAst); 7108 tpl = tpl->next; 7109 FREE(tplsave); 7110 } 7111 7112 for (entryPtr = Tcl_FirstHashEntry (&(xs->wsInfo.stripTokens), &search); 7113 entryPtr != (Tcl_HashEntry*) NULL; 7114 entryPtr = Tcl_NextHashEntry (&search)) { 7115 f = (double *) Tcl_GetHashValue (entryPtr); 7116 FREE(f); 7117 } 7118 Tcl_DeleteHashTable (&(xs->wsInfo.stripTokens)); 7119 7120 for (entryPtr = Tcl_FirstHashEntry (&(xs->wsInfo.preserveTokens), &search); 7121 entryPtr != (Tcl_HashEntry*) NULL; 7122 entryPtr = Tcl_NextHashEntry (&search)) { 7123 f = (double *) Tcl_GetHashValue (entryPtr); 7124 FREE(f); 7125 } 7126 Tcl_DeleteHashTable (&(xs->wsInfo.preserveTokens)); 7127 7128 FREE(xs->varFramesStack); 7129 FREE(xs->varStack); 7130 if (xs->doctype.method) FREE(xs->doctype.method); 7131 if (xs->doctype.encoding) FREE(xs->doctype.encoding); 7132 if (xs->doctype.mediaType) FREE(xs->doctype.mediaType); 7133 FREE (xs); 7134} 7135 7136void 7137xsltFreeStateWrapper ( 7138 void *clientData 7139 ) 7140{ 7141 xsltFreeState ((xsltState *)clientData); 7142} 7143 7144/*---------------------------------------------------------------------------- 7145| xsltResetState 7146| 7147\---------------------------------------------------------------------------*/ 7148static void 7149xsltResetState ( 7150 xsltState * xs 7151 ) 7152{ 7153 xsltSubDoc *sd, *sdsave, *lastSubDoc = NULL; 7154 xsltNodeSet *kvalues; 7155 Tcl_HashEntry *entryPtr, *entryPtr1; 7156 Tcl_HashSearch search, search1; 7157 Tcl_HashTable *htable; 7158 7159 7160 7161 7162 /* Free the sub documents, which are resolved relative to nodes in 7163 * the xml source. */ 7164 /* XML documents don't have excludeNS and extensionNS information 7165 and the already parsed XSLT documents information is 7166 preserved, therefor we don't touch excludeNS and extensionNS 7167 information */ 7168 /* This loop works only as coded, because, the first subdoc will 7169 * always be the primary xslt doc, so xs->subDocs will not 7170 * change. Crusty stuff, this code. */ 7171 sd = xs->subDocs; 7172 while (sd) { 7173 sdsave = sd; 7174 sd = sd->next; 7175 if (sdsave->isStylesheet || sdsave->fixedXMLSource) { 7176 if (lastSubDoc) { 7177 lastSubDoc->next = sdsave; 7178 } else { 7179 xs->subDocs = sdsave; 7180 } 7181 lastSubDoc = sdsave; 7182 sdsave->next = NULL; 7183 } else { 7184 for (entryPtr = Tcl_FirstHashEntry (&sdsave->keyData, &search); 7185 entryPtr != (Tcl_HashEntry*) NULL; 7186 entryPtr = Tcl_NextHashEntry (&search)) { 7187 htable = (Tcl_HashTable *) Tcl_GetHashValue (entryPtr); 7188 for (entryPtr1 = Tcl_FirstHashEntry (htable, &search1); 7189 entryPtr1 != (Tcl_HashEntry*) NULL; 7190 entryPtr1 = Tcl_NextHashEntry (&search1)) { 7191 kvalues = (xsltNodeSet *) Tcl_GetHashValue (entryPtr1); 7192 FREE(kvalues->nodes); 7193 FREE(kvalues); 7194 } 7195 Tcl_DeleteHashTable (htable); 7196 FREE(htable); 7197 } 7198 Tcl_DeleteHashTable (&sdsave->keyData); 7199 7200 if (sdsave->mustFree) { 7201 domFreeDocument (sdsave->doc, NULL, NULL); 7202 } 7203 if (sdsave->baseURI) FREE(sdsave->baseURI); 7204 7205 FREE(sdsave); 7206 } 7207 } 7208 xs->nsUniqeNr = 0; 7209 /* In theory, the varFramesStack and varStack pointers should 7210 be always back to there inital state. But to be sure, we 7211 re-initialize, just in case of a bizarre error or something. */ 7212 xs->varFramesStackPtr = -1; 7213 xs->varStackPtr = -1; 7214} 7215 7216/*---------------------------------------------------------------------------- 7217| xsltCompileStylesheet 7218| 7219\---------------------------------------------------------------------------*/ 7220void * 7221xsltCompileStylesheet ( 7222 domDocument * xsltDoc, 7223 xpathFuncCallback funcCB, 7224 void * xpathFuncClientData, 7225 int guardXSLTTree, 7226 char ** errMsg 7227 ) 7228{ 7229 domNode *node; 7230 int rc; 7231 char *tailptr; 7232 const char *baseURI; 7233 double d, precedence, precedenceLowBound; 7234 xsltState *xs; 7235 xsltSubDoc *sdoc; 7236 domAttrNode *attr; 7237 xsltTemplate *tpl; 7238 7239 *errMsg = NULL; 7240 xs = (xsltState *) MALLOC (sizeof (xsltState)); 7241 7242 Tcl_InitHashTable ( &(xs->namedTemplates), TCL_STRING_KEYS); 7243 Tcl_InitHashTable ( &(xs->isElementTpls), TCL_STRING_KEYS); 7244 xs->cbs.varCB = xsltGetVar; 7245 xs->cbs.varClientData = (void*)xs; 7246 xs->cbs.funcCB = xsltXPathFuncs; 7247 xs->cbs.funcClientData = xs; 7248 xs->orig_funcCB = funcCB; 7249 xs->orig_funcClientData = xpathFuncClientData; 7250 xs->xsltMsgCB = NULL; 7251 xs->xsltMsgClientData = NULL; 7252 xs->varFramesStack = (xsltVarFrame *)MALLOC(sizeof (xsltVarFrame)*4); 7253 xs->varFramesStackPtr = -1; 7254 xs->varFramesStackLen = 4; 7255 xs->varStack = (xsltVariable *)MALLOC(sizeof (xsltVariable)*8); 7256 xs->varStackPtr = -1; 7257 xs->varStackLen = 8; 7258 xs->templates = NULL; 7259 xs->lastNode = NULL; 7260 xs->attrSets = NULL; 7261 xs->decimalFormats = (xsltDecimalFormat*)MALLOC(sizeof (xsltDecimalFormat)); 7262 xs->subDocs = NULL; 7263 xs->currentTplRule = NULL; 7264 xs->currentXSLTNode = NULL; 7265 xs->xsltDoc = xsltDoc; 7266 xs->varsInProcess = NULL; 7267 xs->nsAliases = NULL; 7268 xs->nsUniqeNr = 0; 7269 Tcl_InitHashTable ( &(xs->wsInfo.stripTokens), TCL_STRING_KEYS); 7270 Tcl_InitHashTable ( &(xs->wsInfo.preserveTokens), TCL_STRING_KEYS); 7271 xs->wsInfo.hasData = 0; 7272 xs->wsInfo.stripAll = 0; 7273 xs->wsInfo.wildcardPrec = 0.0; 7274 Tcl_InitHashTable ( &(xs->xpaths), TCL_STRING_KEYS); 7275 Tcl_InitHashTable ( &(xs->pattern), TCL_STRING_KEYS); 7276 Tcl_InitHashTable ( &(xs->formats), TCL_STRING_KEYS); 7277 Tcl_InitHashTable ( &(xs->topLevelVars), TCL_STRING_KEYS); 7278 Tcl_InitHashTable ( &(xs->keyInfos), TCL_STRING_KEYS); 7279 xs->decimalFormats->name = NULL; 7280 xs->decimalFormats->uri = NULL; 7281#if TclOnly8Bits 7282 xs->decimalFormats->decimalSeparator = '.'; 7283 xs->decimalFormats->groupingSeparator = ','; 7284 xs->decimalFormats->minusSign = '-'; 7285 xs->decimalFormats->percent = '%'; 7286 xs->decimalFormats->zeroDigit = '0'; 7287 xs->decimalFormats->digit = '#'; 7288 xs->decimalFormats->patternSeparator = ';'; 7289#else 7290 xs->decimalFormats->decimalSeparator = 46; 7291 xs->decimalFormats->groupingSeparator = 44; 7292 xs->decimalFormats->minusSign = 45; 7293 xs->decimalFormats->percent = 37; 7294 xs->decimalFormats->perMille = 0x2030; 7295 xs->decimalFormats->zeroDigit = 48; 7296 xs->decimalFormats->digit = 35; 7297 xs->decimalFormats->patternSeparator = 59; 7298#endif /* TclOnly8Bits */ 7299 xs->decimalFormats->infinity = "Infinity"; 7300 xs->decimalFormats->NaN = "NaN"; 7301 xs->decimalFormats->next = NULL; 7302 xs->indentOutput = 0; 7303 memset (&xs->doctype, 0, sizeof (domDocInfo)); 7304 7305 node = xsltDoc->documentElement; 7306 7307 /* add the xslt doc to the doc list */ 7308 sdoc = (xsltSubDoc*)MALLOC(sizeof (xsltSubDoc)); 7309 sdoc->doc = xsltDoc; 7310 baseURI = findBaseURI (xsltDoc->documentElement); 7311 if (baseURI) { 7312 sdoc->baseURI = tdomstrdup (baseURI); 7313 } else { 7314 sdoc->baseURI = NULL; 7315 } 7316 Tcl_InitHashTable (&(sdoc->keyData), TCL_STRING_KEYS); 7317 sdoc->excludeNS = NULL; 7318 sdoc->extensionNS = NULL; 7319 sdoc->fwCmpProcessing = 0; 7320 sdoc->isStylesheet = 1; 7321 sdoc->next = xs->subDocs; 7322 sdoc->mustFree = !guardXSLTTree; 7323 sdoc->fixedXMLSource = 0; 7324 xs->subDocs = sdoc; 7325 7326 xs->currentSubDoc = sdoc; 7327 7328 if ((getTag(node) != stylesheet) && (getTag(node) != transform)) { 7329 /* Check for "Literal Result Element as Stylesheet" (XSLT rec 2.3) */ 7330 attr = domGetAttributeNodeNS (node, XSLT_NAMESPACE, "version"); 7331 if (!attr) { 7332 reportError (node, "The supplied DOM tree does not appear to be" 7333 " a stylesheet.", errMsg); 7334 goto error; 7335 } 7336 d = strtod (attr->nodeValue, &tailptr); 7337 if (d == 0.0 && tailptr == attr->nodeValue) { 7338 reportError (node, "The value of the attribute \"version\" must" 7339 " be a number.", errMsg); 7340 goto error; 7341 } 7342 if (d > 1.0) { 7343 sdoc->fwCmpProcessing = 1; 7344 } else if (d < 1.0) { 7345 reportError (node, "Strange \"xsl:version\" value, don't know," 7346 " how to handle.", errMsg); 7347 goto error; 7348 } 7349 StripXSLTSpace (xsltDoc->rootNode); 7350 /* According to XSLT rec 2.3 we add the literal result element as 7351 template, which matches "/" */ 7352 tpl = (xsltTemplate *) MALLOC (sizeof (xsltTemplate)); 7353 tpl->match = "/"; 7354 tpl->name = NULL; 7355 tpl->nameURI = NULL; 7356 tpl->mode = NULL; 7357 tpl->modeURI = NULL; 7358 tpl->prio = 0.5; 7359 tpl->content = node->ownerDocument->rootNode; 7360 tpl->precedence = 1.0; 7361 tpl->next = NULL; 7362 tpl->sDoc = sdoc; 7363 rc = xpathParse (tpl->match, node, XPATH_TEMPMATCH_PATTERN, NULL, NULL, 7364 &(tpl->freeAst), errMsg); 7365 tpl->ast = tpl->freeAst; 7366 xs->templates = tpl; 7367 if (rc < 0) goto error; 7368 } else { 7369 rc = addExclExtNS (sdoc, node, errMsg); 7370 if (rc < 0) goto error; 7371 7372 StripXSLTSpace (xsltDoc->rootNode); 7373 precedence = 1.0; 7374 precedenceLowBound = 0.0; 7375 rc = 0; 7376 rc = processTopLevel (xpathFuncClientData, node, xs, precedence, 7377 &precedenceLowBound, errMsg); 7378 if (rc != 0) goto error; 7379 } 7380 7381 return xs; 7382 7383 error: 7384 xsltFreeState (xs); 7385 return NULL; 7386} 7387 7388/*---------------------------------------------------------------------------- 7389| xsltProcess 7390| 7391\---------------------------------------------------------------------------*/ 7392int xsltProcess ( 7393 domDocument * xsltDoc, 7394 domNode * xmlNode, 7395 void * xsltCmdData, 7396 char ** parameters, 7397 int ignoreUndeclaredParameters, 7398 xpathFuncCallback funcCB, 7399 void * xpathFuncClientData, 7400 xsltMsgCB xsltMsgCB, 7401 void * xsltMsgClientData, 7402 char ** errMsg, 7403 domDocument ** resultDoc 7404 ) 7405{ 7406 xpathResultSet nodeList; 7407 domNode *node; 7408 int rc, hnew; 7409 const char *baseURI; 7410 xsltState *xs; 7411 xsltSubDoc *sdoc; 7412 Tcl_HashEntry *entryPtr; 7413 Tcl_HashSearch search; 7414 7415 *errMsg = NULL; 7416 if (xsltCmdData) { 7417 xs = (xsltState *) xsltCmdData; 7418 } else { 7419 xs = (xsltState *) xsltCompileStylesheet (xsltDoc, funcCB, 7420 xpathFuncClientData, 7421 1, errMsg); 7422 if (!xs) return -1; 7423 } 7424 7425 if (xmlNode->nodeType == DOCUMENT_NODE) { 7426 xmlNode = ((domDocument *)xmlNode)->rootNode; 7427 } else { 7428 xmlNode = xmlNode->ownerDocument->rootNode; 7429 } 7430 DBG(printXML(xmlNode, 0, 1);) 7431 7432 if (xmlNode->ownerDocument->nodeFlags & NEEDS_RENUMBERING) { 7433 domRenumberTree (xmlNode->ownerDocument->rootNode); 7434 xmlNode->ownerDocument->nodeFlags &= ~NEEDS_RENUMBERING; 7435 } 7436 7437 xs->resultDoc = domCreateDoc(NULL, 0); 7438 if (xs->doctype.systemId) { 7439 xs->resultDoc->doctype = (domDocInfo *)MALLOC (sizeof (domDocInfo)); 7440 memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); 7441 xs->resultDoc->doctype->systemId = tdomstrdup (xs->doctype.systemId); 7442 } 7443 if (xs->doctype.publicId) { 7444 if (!xs->resultDoc->doctype) { 7445 xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); 7446 memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); 7447 } 7448 xs->resultDoc->doctype->publicId = tdomstrdup (xs->doctype.publicId); 7449 } 7450 if (xs->doctype.encoding) { 7451 if (!xs->resultDoc->doctype) { 7452 xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); 7453 memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); 7454 } 7455 xs->resultDoc->doctype->encoding = tdomstrdup (xs->doctype.encoding); 7456 } 7457 if (xs->doctype.mediaType) { 7458 if (!xs->resultDoc->doctype) { 7459 xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); 7460 memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); 7461 } 7462 xs->resultDoc->doctype->mediaType = tdomstrdup (xs->doctype.mediaType); 7463 } 7464 if (xs->doctype.standalone) { 7465 if (!xs->resultDoc->doctype) { 7466 xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); 7467 memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); 7468 } 7469 xs->resultDoc->doctype->standalone = 1; 7470 } 7471 if (xs->indentOutput) { 7472 xs->resultDoc->nodeFlags |= OUTPUT_DEFAULT_INDENT; 7473 } 7474 if (xs->doctype.cdataSectionElements) { 7475 if (!xs->resultDoc->doctype) { 7476 xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); 7477 memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); 7478 } 7479 xs->resultDoc->doctype->cdataSectionElements = 7480 (Tcl_HashTable *) MALLOC (sizeof (Tcl_HashTable)); 7481 Tcl_InitHashTable (xs->resultDoc->doctype->cdataSectionElements, 7482 TCL_STRING_KEYS); 7483 for (entryPtr = Tcl_FirstHashEntry (xs->doctype.cdataSectionElements, 7484 &search); 7485 entryPtr != (Tcl_HashEntry*) NULL; 7486 entryPtr = Tcl_NextHashEntry (&search)) { 7487 Tcl_CreateHashEntry (xs->resultDoc->doctype->cdataSectionElements, 7488 Tcl_GetHashKey ( 7489 xs->doctype.cdataSectionElements, entryPtr 7490 ), &hnew); 7491 } 7492 } 7493 7494 xs->xmlRootNode = xmlNode; 7495 xs->lastNode = xs->resultDoc->rootNode; 7496 xs->xsltMsgCB = xsltMsgCB; 7497 xs->xsltMsgClientData = xsltMsgClientData; 7498 7499 7500 xsltPushVarFrame(xs); 7501 xpathRSInit( &nodeList ); 7502 rsAddNodeFast( &nodeList, xmlNode); 7503 7504 /* strip space from the XML document, if necessary */ 7505 if (xs->wsInfo.hasData) { 7506 StripXMLSpace (xs, xmlNode); 7507 } 7508 7509 /* add the xml doc to the doc list */ 7510 sdoc = (xsltSubDoc*)MALLOC(sizeof (xsltSubDoc)); 7511 sdoc->doc = xmlNode->ownerDocument; 7512 baseURI = findBaseURI (xmlNode); 7513 if (baseURI) { 7514 sdoc->baseURI = tdomstrdup (baseURI); 7515 } else { 7516 sdoc->baseURI = NULL; 7517 } 7518 Tcl_InitHashTable (&(sdoc->keyData), TCL_STRING_KEYS); 7519 sdoc->excludeNS = NULL; 7520 sdoc->extensionNS = NULL; 7521 sdoc->fwCmpProcessing = 0; 7522 sdoc->isStylesheet = 0; 7523 sdoc->mustFree = 0; 7524 sdoc->fixedXMLSource = 0; 7525 sdoc->next = xs->subDocs; 7526 xs->subDocs = sdoc; 7527 7528 xs->currentSubDoc = sdoc; 7529 7530 rc = processTopLevelVars (xmlNode, xs, parameters, 7531 ignoreUndeclaredParameters, errMsg); 7532 if (rc != 0) goto error; 7533 7534 node = xs->xsltDoc->documentElement; 7535 rc = ApplyTemplates (xs, &nodeList, xmlNode, 0, node, &nodeList, NULL, 7536 NULL, errMsg); 7537 if (rc != 0) goto error; 7538 7539 /* Rudimentary xsl:output support */ 7540 if (xs->doctype.method) { 7541 if (!xs->resultDoc->doctype) { 7542 xs->resultDoc->doctype = (domDocInfo*)MALLOC (sizeof (domDocInfo)); 7543 memset (xs->resultDoc->doctype, 0, (sizeof (domDocInfo))); 7544 } 7545 xs->resultDoc->doctype->method = tdomstrdup (xs->doctype.method); 7546 } else { 7547 /* default output method */ 7548 node = xs->resultDoc->rootNode->firstChild; 7549 while (node) { 7550 if (node->nodeType == TEXT_NODE) { 7551 char *pc; 7552 int i, only_whites; 7553 7554 only_whites = 1; 7555 for (i=0, pc = ((domTextNode*)node)->nodeValue; 7556 i < ((domTextNode*)node)->valueLength; 7557 i++, pc++) { 7558 if (!IS_XML_WHITESPACE(*pc)) { 7559 only_whites = 0; 7560 break; 7561 } 7562 } 7563 if (!only_whites) break; 7564 } 7565 if (node->nodeType == ELEMENT_NODE) { 7566 if (STRCASECMP(node->nodeName, "html")==0) { 7567 if (!xs->resultDoc->doctype) { 7568 xs->resultDoc->doctype = 7569 (domDocInfo*)MALLOC (sizeof (domDocInfo)); 7570 memset (xs->resultDoc->doctype, 0, 7571 (sizeof (domDocInfo))); 7572 } 7573 xs->resultDoc->doctype->method = tdomstrdup ("html"); 7574 } 7575 break; 7576 } 7577 node = node->nextSibling; 7578 } 7579 } 7580 /* Make the first ELEMENT_NODE the documentElement. There could 7581 be text, comment or PI nodes before the first element node. 7582 If the root node doesn't have an element node under it's childs, 7583 fall back to the firstChild as documentElement. */ 7584 domSetDocumentElement (xs->resultDoc); 7585 7586 *resultDoc = xs->resultDoc; 7587 7588 xsltPopVarFrame (xs); 7589 xpathRSFree( &nodeList ); 7590 if (xsltCmdData) { 7591 xsltResetState (xs); 7592 } else { 7593 xsltFreeState (xs); 7594 } 7595 return 0; 7596 7597 error: 7598 xsltPopVarFrame (xs); 7599 xpathRSFree( &nodeList ); 7600 domFreeDocument (xs->resultDoc, NULL, NULL); 7601 if (xsltCmdData) { 7602 xsltResetState (xs); 7603 } else { 7604 xsltFreeState (xs); 7605 } 7606 return -1; 7607 7608} /* xsltProcess */ 7609 7610