Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentransform.c
Go to the documentation of this file.
00001 /* 00002 * transform.c: Implementation of the XSL Transformation 1.0 engine 00003 * transform part, i.e. applying a Stylesheet to a document 00004 * 00005 * References: 00006 * http://www.w3.org/TR/1999/REC-xslt-19991116 00007 * 00008 * Michael Kay "XSLT Programmer's Reference" pp 637-643 00009 * Writing Multiple Output Files 00010 * 00011 * XSLT-1.1 Working Draft 00012 * http://www.w3.org/TR/xslt11#multiple-output 00013 * 00014 * See Copyright for the status of this software. 00015 * 00016 * daniel@veillard.com 00017 */ 00018 00019 #define IN_LIBXSLT 00020 #include "libxslt.h" 00021 00022 #include <string.h> 00023 00024 #include <libxml/xmlmemory.h> 00025 #include <libxml/parser.h> 00026 #include <libxml/tree.h> 00027 #include <libxml/valid.h> 00028 #include <libxml/hash.h> 00029 #include <libxml/encoding.h> 00030 #include <libxml/xmlerror.h> 00031 #include <libxml/xpath.h> 00032 #include <libxml/parserInternals.h> 00033 #include <libxml/xpathInternals.h> 00034 #include <libxml/HTMLtree.h> 00035 #include <libxml/debugXML.h> 00036 #include <libxml/uri.h> 00037 #include "xslt.h" 00038 #include "xsltInternals.h" 00039 #include "xsltutils.h" 00040 #include "pattern.h" 00041 #include "transform.h" 00042 #include "variables.h" 00043 #include "numbersInternals.h" 00044 #include "namespaces.h" 00045 #include "attributes.h" 00046 #include "templates.h" 00047 #include "imports.h" 00048 #include "keys.h" 00049 #include "documents.h" 00050 #include "extensions.h" 00051 #include "extra.h" 00052 #include "preproc.h" 00053 #include "security.h" 00054 00055 #ifdef WITH_XSLT_DEBUG 00056 #define WITH_XSLT_DEBUG_EXTRA 00057 #define WITH_XSLT_DEBUG_PROCESS 00058 #endif 00059 00060 #define XSLT_GENERATE_HTML_DOCTYPE 00061 #ifdef XSLT_GENERATE_HTML_DOCTYPE 00062 static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, 00063 const xmlChar **systemID); 00064 #endif 00065 00066 int xsltMaxDepth = 3000; 00067 00068 /* 00069 * Useful macros 00070 */ 00071 00072 #ifndef FALSE 00073 # define FALSE (0 == 1) 00074 # define TRUE (!FALSE) 00075 #endif 00076 00077 #define IS_BLANK_NODE(n) \ 00078 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) 00079 00080 00081 /* 00082 * Forward declarations 00083 */ 00084 00085 static xmlNsPtr 00086 xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur); 00087 00088 static xmlNodePtr 00089 xsltCopyTreeInternal(xsltTransformContextPtr ctxt, 00090 xmlNodePtr invocNode, 00091 xmlNodePtr node, 00092 xmlNodePtr insert, int isLRE, int topElemVisited); 00093 00094 static void 00095 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, 00096 xmlNodePtr contextNode, xmlNodePtr list, 00097 xsltTemplatePtr templ); 00098 00099 static void 00100 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, 00101 xmlNodePtr contextNode, 00102 xmlNodePtr list, 00103 xsltTemplatePtr templ, 00104 xsltStackElemPtr withParams); 00105 00115 static int 00116 templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value) 00117 { 00118 if (ctxt->templMax == 0) { 00119 ctxt->templMax = 4; 00120 ctxt->templTab = 00121 (xsltTemplatePtr *) xmlMalloc(ctxt->templMax * 00122 sizeof(ctxt->templTab[0])); 00123 if (ctxt->templTab == NULL) { 00124 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 00125 return (0); 00126 } 00127 } 00128 if (ctxt->templNr >= ctxt->templMax) { 00129 ctxt->templMax *= 2; 00130 ctxt->templTab = 00131 (xsltTemplatePtr *) xmlRealloc(ctxt->templTab, 00132 ctxt->templMax * 00133 sizeof(ctxt->templTab[0])); 00134 if (ctxt->templTab == NULL) { 00135 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 00136 return (0); 00137 } 00138 } 00139 ctxt->templTab[ctxt->templNr] = value; 00140 ctxt->templ = value; 00141 return (ctxt->templNr++); 00142 } 00151 static xsltTemplatePtr 00152 templPop(xsltTransformContextPtr ctxt) 00153 { 00154 xsltTemplatePtr ret; 00155 00156 if (ctxt->templNr <= 0) 00157 return (0); 00158 ctxt->templNr--; 00159 if (ctxt->templNr > 0) 00160 ctxt->templ = ctxt->templTab[ctxt->templNr - 1]; 00161 else 00162 ctxt->templ = (xsltTemplatePtr) 0; 00163 ret = ctxt->templTab[ctxt->templNr]; 00164 ctxt->templTab[ctxt->templNr] = 0; 00165 return (ret); 00166 } 00167 00180 void 00181 xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level) 00182 { 00183 xsltStackElemPtr variable; 00184 00185 if (ctxt->varsNr <= 0) 00186 return; 00187 00188 do { 00189 if (ctxt->varsNr <= limitNr) 00190 break; 00191 variable = ctxt->varsTab[ctxt->varsNr - 1]; 00192 if (variable->level <= level) 00193 break; 00194 if (variable->level >= 0) 00195 xsltFreeStackElemList(variable); 00196 ctxt->varsNr--; 00197 } while (ctxt->varsNr != 0); 00198 if (ctxt->varsNr > 0) 00199 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; 00200 else 00201 ctxt->vars = NULL; 00202 } 00203 00210 static void 00211 xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt) 00212 { 00213 xsltStackElemPtr param; 00214 00215 for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) { 00216 param = ctxt->varsTab[ctxt->varsNr -1]; 00217 /* 00218 * Free xsl:param items. 00219 * xsl:with-param items will have a level of -1 or -2. 00220 */ 00221 if (param->level >= 0) { 00222 xsltFreeStackElemList(param); 00223 } 00224 } 00225 if (ctxt->varsNr > 0) 00226 ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; 00227 else 00228 ctxt->vars = NULL; 00229 } 00230 00240 static int 00241 profPush(xsltTransformContextPtr ctxt, long value) 00242 { 00243 if (ctxt->profMax == 0) { 00244 ctxt->profMax = 4; 00245 ctxt->profTab = 00246 (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0])); 00247 if (ctxt->profTab == NULL) { 00248 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 00249 return (0); 00250 } 00251 } 00252 if (ctxt->profNr >= ctxt->profMax) { 00253 ctxt->profMax *= 2; 00254 ctxt->profTab = 00255 (long *) xmlRealloc(ctxt->profTab, 00256 ctxt->profMax * sizeof(ctxt->profTab[0])); 00257 if (ctxt->profTab == NULL) { 00258 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 00259 return (0); 00260 } 00261 } 00262 ctxt->profTab[ctxt->profNr] = value; 00263 ctxt->prof = value; 00264 return (ctxt->profNr++); 00265 } 00274 static long 00275 profPop(xsltTransformContextPtr ctxt) 00276 { 00277 long ret; 00278 00279 if (ctxt->profNr <= 0) 00280 return (0); 00281 ctxt->profNr--; 00282 if (ctxt->profNr > 0) 00283 ctxt->prof = ctxt->profTab[ctxt->profNr - 1]; 00284 else 00285 ctxt->prof = (long) 0; 00286 ret = ctxt->profTab[ctxt->profNr]; 00287 ctxt->profTab[ctxt->profNr] = 0; 00288 return (ret); 00289 } 00290 00291 /************************************************************************ 00292 * * 00293 * XInclude default settings * 00294 * * 00295 ************************************************************************/ 00296 00297 static int xsltDoXIncludeDefault = 0; 00298 00305 void 00306 xsltSetXIncludeDefault(int xinclude) { 00307 xsltDoXIncludeDefault = (xinclude != 0); 00308 } 00309 00317 int 00318 xsltGetXIncludeDefault(void) { 00319 return(xsltDoXIncludeDefault); 00320 } 00321 00322 unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL; 00323 00330 void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) { 00331 xsltDefaultTrace = val; 00332 } 00333 00341 xsltDebugTraceCodes xsltDebugGetDefaultTrace() { 00342 return xsltDefaultTrace; 00343 } 00344 00345 /************************************************************************ 00346 * * 00347 * Handling of Transformation Contexts * 00348 * * 00349 ************************************************************************/ 00350 00351 static xsltTransformCachePtr 00352 xsltTransformCacheCreate(void) 00353 { 00354 xsltTransformCachePtr ret; 00355 00356 ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache)); 00357 if (ret == NULL) { 00358 xsltTransformError(NULL, NULL, NULL, 00359 "xsltTransformCacheCreate : malloc failed\n"); 00360 return(NULL); 00361 } 00362 memset(ret, 0, sizeof(xsltTransformCache)); 00363 return(ret); 00364 } 00365 00366 static void 00367 xsltTransformCacheFree(xsltTransformCachePtr cache) 00368 { 00369 if (cache == NULL) 00370 return; 00371 /* 00372 * Free tree fragments. 00373 */ 00374 if (cache->RVT) { 00375 xmlDocPtr tmp, cur = cache->RVT; 00376 while (cur) { 00377 tmp = cur; 00378 cur = (xmlDocPtr) cur->next; 00379 if (tmp->_private != NULL) { 00380 /* 00381 * Tree the document info. 00382 */ 00383 xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private); 00384 xmlFree(tmp->_private); 00385 } 00386 xmlFreeDoc(tmp); 00387 } 00388 } 00389 /* 00390 * Free vars/params. 00391 */ 00392 if (cache->stackItems) { 00393 xsltStackElemPtr tmp, cur = cache->stackItems; 00394 while (cur) { 00395 tmp = cur; 00396 cur = cur->next; 00397 /* 00398 * REVISIT TODO: Should be call a destruction-function 00399 * instead? 00400 */ 00401 xmlFree(tmp); 00402 } 00403 } 00404 xmlFree(cache); 00405 } 00406 00416 xsltTransformContextPtr 00417 xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { 00418 xsltTransformContextPtr cur; 00419 xsltDocumentPtr docu; 00420 int i; 00421 00422 xsltInitGlobals(); 00423 00424 cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext)); 00425 if (cur == NULL) { 00426 xsltTransformError(NULL, NULL, (xmlNodePtr)doc, 00427 "xsltNewTransformContext : malloc failed\n"); 00428 return(NULL); 00429 } 00430 memset(cur, 0, sizeof(xsltTransformContext)); 00431 00432 cur->cache = xsltTransformCacheCreate(); 00433 if (cur->cache == NULL) 00434 goto internal_err; 00435 /* 00436 * setup of the dictionary must be done early as some of the 00437 * processing later like key handling may need it. 00438 */ 00439 cur->dict = xmlDictCreateSub(style->dict); 00440 cur->internalized = ((style->internalized) && (cur->dict != NULL)); 00441 #ifdef WITH_XSLT_DEBUG 00442 xsltGenericDebug(xsltGenericDebugContext, 00443 "Creating sub-dictionary from stylesheet for transformation\n"); 00444 #endif 00445 00446 /* 00447 * initialize the template stack 00448 */ 00449 cur->templTab = (xsltTemplatePtr *) 00450 xmlMalloc(10 * sizeof(xsltTemplatePtr)); 00451 if (cur->templTab == NULL) { 00452 xsltTransformError(NULL, NULL, (xmlNodePtr) doc, 00453 "xsltNewTransformContext: out of memory\n"); 00454 goto internal_err; 00455 } 00456 cur->templNr = 0; 00457 cur->templMax = 5; 00458 cur->templ = NULL; 00459 00460 /* 00461 * initialize the variables stack 00462 */ 00463 cur->varsTab = (xsltStackElemPtr *) 00464 xmlMalloc(10 * sizeof(xsltStackElemPtr)); 00465 if (cur->varsTab == NULL) { 00466 xmlGenericError(xmlGenericErrorContext, 00467 "xsltNewTransformContext: out of memory\n"); 00468 goto internal_err; 00469 } 00470 cur->varsNr = 0; 00471 cur->varsMax = 10; 00472 cur->vars = NULL; 00473 cur->varsBase = 0; 00474 00475 /* 00476 * the profiling stack is not initialized by default 00477 */ 00478 cur->profTab = NULL; 00479 cur->profNr = 0; 00480 cur->profMax = 0; 00481 cur->prof = 0; 00482 00483 cur->style = style; 00484 xmlXPathInit(); 00485 cur->xpathCtxt = xmlXPathNewContext(doc); 00486 if (cur->xpathCtxt == NULL) { 00487 xsltTransformError(NULL, NULL, (xmlNodePtr) doc, 00488 "xsltNewTransformContext : xmlXPathNewContext failed\n"); 00489 goto internal_err; 00490 } 00491 /* 00492 * Create an XPath cache. 00493 */ 00494 if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1) 00495 goto internal_err; 00496 /* 00497 * Initialize the extras array 00498 */ 00499 if (style->extrasNr != 0) { 00500 cur->extrasMax = style->extrasNr + 20; 00501 cur->extras = (xsltRuntimeExtraPtr) 00502 xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra)); 00503 if (cur->extras == NULL) { 00504 xmlGenericError(xmlGenericErrorContext, 00505 "xsltNewTransformContext: out of memory\n"); 00506 goto internal_err; 00507 } 00508 cur->extrasNr = style->extrasNr; 00509 for (i = 0;i < cur->extrasMax;i++) { 00510 cur->extras[i].info = NULL; 00511 cur->extras[i].deallocate = NULL; 00512 cur->extras[i].val.ptr = NULL; 00513 } 00514 } else { 00515 cur->extras = NULL; 00516 cur->extrasNr = 0; 00517 cur->extrasMax = 0; 00518 } 00519 00520 XSLT_REGISTER_VARIABLE_LOOKUP(cur); 00521 XSLT_REGISTER_FUNCTION_LOOKUP(cur); 00522 cur->xpathCtxt->nsHash = style->nsHash; 00523 /* 00524 * Initialize the registered external modules 00525 */ 00526 xsltInitCtxtExts(cur); 00527 /* 00528 * Setup document element ordering for later efficiencies 00529 * (bug 133289) 00530 */ 00531 if (xslDebugStatus == XSLT_DEBUG_NONE) 00532 xmlXPathOrderDocElems(doc); 00533 /* 00534 * Must set parserOptions before calling xsltNewDocument 00535 * (bug 164530) 00536 */ 00537 cur->parserOptions = XSLT_PARSE_OPTIONS; 00538 docu = xsltNewDocument(cur, doc); 00539 if (docu == NULL) { 00540 xsltTransformError(cur, NULL, (xmlNodePtr)doc, 00541 "xsltNewTransformContext : xsltNewDocument failed\n"); 00542 goto internal_err; 00543 } 00544 docu->main = 1; 00545 cur->document = docu; 00546 cur->inst = NULL; 00547 cur->outputFile = NULL; 00548 cur->sec = xsltGetDefaultSecurityPrefs(); 00549 cur->debugStatus = xslDebugStatus; 00550 cur->traceCode = (unsigned long*) &xsltDefaultTrace; 00551 cur->xinclude = xsltGetXIncludeDefault(); 00552 cur->keyInitLevel = 0; 00553 00554 return(cur); 00555 00556 internal_err: 00557 if (cur != NULL) 00558 xsltFreeTransformContext(cur); 00559 return(NULL); 00560 } 00561 00568 void 00569 xsltFreeTransformContext(xsltTransformContextPtr ctxt) { 00570 if (ctxt == NULL) 00571 return; 00572 00573 /* 00574 * Shutdown the extension modules associated to the stylesheet 00575 * used if needed. 00576 */ 00577 xsltShutdownCtxtExts(ctxt); 00578 00579 if (ctxt->xpathCtxt != NULL) { 00580 ctxt->xpathCtxt->nsHash = NULL; 00581 xmlXPathFreeContext(ctxt->xpathCtxt); 00582 } 00583 if (ctxt->templTab != NULL) 00584 xmlFree(ctxt->templTab); 00585 if (ctxt->varsTab != NULL) 00586 xmlFree(ctxt->varsTab); 00587 if (ctxt->profTab != NULL) 00588 xmlFree(ctxt->profTab); 00589 if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) { 00590 int i; 00591 00592 for (i = 0;i < ctxt->extrasNr;i++) { 00593 if ((ctxt->extras[i].deallocate != NULL) && 00594 (ctxt->extras[i].info != NULL)) 00595 ctxt->extras[i].deallocate(ctxt->extras[i].info); 00596 } 00597 xmlFree(ctxt->extras); 00598 } 00599 xsltFreeGlobalVariables(ctxt); 00600 xsltFreeDocuments(ctxt); 00601 xsltFreeCtxtExts(ctxt); 00602 xsltFreeRVTs(ctxt); 00603 xsltTransformCacheFree(ctxt->cache); 00604 xmlDictFree(ctxt->dict); 00605 #ifdef WITH_XSLT_DEBUG 00606 xsltGenericDebug(xsltGenericDebugContext, 00607 "freeing transformation dictionary\n"); 00608 #endif 00609 memset(ctxt, -1, sizeof(xsltTransformContext)); 00610 xmlFree(ctxt); 00611 } 00612 00613 /************************************************************************ 00614 * * 00615 * Copy of Nodes in an XSLT fashion * 00616 * * 00617 ************************************************************************/ 00618 00619 xmlNodePtr xsltCopyTree(xsltTransformContextPtr ctxt, 00620 xmlNodePtr node, xmlNodePtr insert, int literal); 00621 00633 static xmlNodePtr 00634 xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) { 00635 xmlNodePtr ret; 00636 00637 if ((cur == NULL) || (parent == NULL)) 00638 return(NULL); 00639 if (parent == NULL) { 00640 xmlFreeNode(cur); 00641 return(NULL); 00642 } 00643 ret = xmlAddChild(parent, cur); 00644 00645 return(ret); 00646 } 00647 00659 static xmlNodePtr 00660 xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, 00661 const xmlChar *string, int len) { 00662 /* 00663 * optimization 00664 */ 00665 if ((len <= 0) || (string == NULL) || (target == NULL)) 00666 return(target); 00667 00668 if (ctxt->lasttext == target->content) { 00669 00670 if (ctxt->lasttuse + len >= ctxt->lasttsize) { 00671 xmlChar *newbuf; 00672 int size; 00673 00674 size = ctxt->lasttsize + len + 100; 00675 size *= 2; 00676 newbuf = (xmlChar *) xmlRealloc(target->content,size); 00677 if (newbuf == NULL) { 00678 xsltTransformError(ctxt, NULL, target, 00679 "xsltCopyText: text allocation failed\n"); 00680 return(NULL); 00681 } 00682 ctxt->lasttsize = size; 00683 ctxt->lasttext = newbuf; 00684 target->content = newbuf; 00685 } 00686 memcpy(&(target->content[ctxt->lasttuse]), string, len); 00687 ctxt->lasttuse += len; 00688 target->content[ctxt->lasttuse] = 0; 00689 } else { 00690 xmlNodeAddContent(target, string); 00691 ctxt->lasttext = target->content; 00692 len = xmlStrlen(target->content); 00693 ctxt->lasttsize = len; 00694 ctxt->lasttuse = len; 00695 } 00696 return(target); 00697 } 00698 00712 xmlNodePtr 00713 xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, 00714 const xmlChar *string, int noescape) 00715 { 00716 xmlNodePtr copy; 00717 int len; 00718 00719 if (string == NULL) 00720 return(NULL); 00721 00722 #ifdef WITH_XSLT_DEBUG_PROCESS 00723 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 00724 "xsltCopyTextString: copy text %s\n", 00725 string)); 00726 #endif 00727 00728 /* 00729 * Play save and reset the merging mechanism for every new 00730 * target node. 00731 */ 00732 if ((target == NULL) || (target->children == NULL)) { 00733 ctxt->lasttext = NULL; 00734 } 00735 00736 /* handle coalescing of text nodes here */ 00737 len = xmlStrlen(string); 00738 if ((ctxt->type == XSLT_OUTPUT_XML) && 00739 (ctxt->style->cdataSection != NULL) && 00740 (target != NULL) && 00741 (target->type == XML_ELEMENT_NODE) && 00742 (((target->ns == NULL) && 00743 (xmlHashLookup2(ctxt->style->cdataSection, 00744 target->name, NULL) != NULL)) || 00745 ((target->ns != NULL) && 00746 (xmlHashLookup2(ctxt->style->cdataSection, 00747 target->name, target->ns->href) != NULL)))) 00748 { 00749 /* 00750 * Process "cdata-section-elements". 00751 */ 00752 if ((target->last != NULL) && 00753 (target->last->type == XML_CDATA_SECTION_NODE)) 00754 { 00755 return(xsltAddTextString(ctxt, target->last, string, len)); 00756 } 00757 copy = xmlNewCDataBlock(ctxt->output, string, len); 00758 } else if (noescape) { 00759 /* 00760 * Process "disable-output-escaping". 00761 */ 00762 if ((target != NULL) && (target->last != NULL) && 00763 (target->last->type == XML_TEXT_NODE) && 00764 (target->last->name == xmlStringTextNoenc)) 00765 { 00766 return(xsltAddTextString(ctxt, target->last, string, len)); 00767 } 00768 copy = xmlNewTextLen(string, len); 00769 if (copy != NULL) 00770 copy->name = xmlStringTextNoenc; 00771 } else { 00772 /* 00773 * Default processing. 00774 */ 00775 if ((target != NULL) && (target->last != NULL) && 00776 (target->last->type == XML_TEXT_NODE) && 00777 (target->last->name == xmlStringText)) { 00778 return(xsltAddTextString(ctxt, target->last, string, len)); 00779 } 00780 copy = xmlNewTextLen(string, len); 00781 } 00782 if (copy != NULL) { 00783 if (target != NULL) 00784 copy = xsltAddChild(target, copy); 00785 ctxt->lasttext = copy->content; 00786 ctxt->lasttsize = len; 00787 ctxt->lasttuse = len; 00788 } else { 00789 xsltTransformError(ctxt, NULL, target, 00790 "xsltCopyTextString: text copy failed\n"); 00791 ctxt->lasttext = NULL; 00792 } 00793 return(copy); 00794 } 00795 00808 static xmlNodePtr 00809 xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target, 00810 xmlNodePtr cur, int interned) 00811 { 00812 xmlNodePtr copy; 00813 00814 if ((cur->type != XML_TEXT_NODE) && 00815 (cur->type != XML_CDATA_SECTION_NODE)) 00816 return(NULL); 00817 if (cur->content == NULL) 00818 return(NULL); 00819 00820 #ifdef WITH_XSLT_DEBUG_PROCESS 00821 if (cur->type == XML_CDATA_SECTION_NODE) { 00822 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 00823 "xsltCopyText: copy CDATA text %s\n", 00824 cur->content)); 00825 } else if (cur->name == xmlStringTextNoenc) { 00826 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 00827 "xsltCopyText: copy unescaped text %s\n", 00828 cur->content)); 00829 } else { 00830 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, 00831 "xsltCopyText: copy text %s\n", 00832 cur->content)); 00833 } 00834 #endif 00835 00836 /* 00837 * Play save and reset the merging mechanism for every new 00838 * target node. 00839 */ 00840 if ((target == NULL) || (target->children == NULL)) { 00841 ctxt->lasttext = NULL; 00842 } 00843 00844 if ((ctxt->style->cdataSection != NULL) && 00845 (ctxt->type == XSLT_OUTPUT_XML) && 00846 (target != NULL) && 00847 (target->type == XML_ELEMENT_NODE) && 00848 (((target->ns == NULL) && 00849 (xmlHashLookup2(ctxt->style->cdataSection, 00850 target->name, NULL) != NULL)) || 00851 ((target->ns != NULL) && 00852 (xmlHashLookup2(ctxt->style->cdataSection, 00853 target->name, target->ns->href) != NULL)))) 00854 { 00855 /* 00856 * Process "cdata-section-elements". 00857 */ 00858 /* 00859 * OPTIMIZE TODO: xsltCopyText() is also used for attribute content. 00860 */ 00861 /* 00862 * TODO: Since this doesn't merge adjacent CDATA-section nodes, 00863 * we'll get: <![CDATA[x]]><!CDATA[y]]>. 00864 * TODO: Reported in #321505. 00865 */ 00866 if ((target->last != NULL) && 00867 (target->last->type == XML_CDATA_SECTION_NODE)) 00868 { 00869 /* 00870 * Append to existing CDATA-section node. 00871 */ 00872 copy = xsltAddTextString(ctxt, target->last, cur->content, 00873 xmlStrlen(cur->content)); 00874 goto exit; 00875 } else { 00876 unsigned int len; 00877 00878 len = xmlStrlen(cur->content); 00879 copy = xmlNewCDataBlock(ctxt->output, cur->content, len); 00880 if (copy == NULL) 00881 goto exit; 00882 ctxt->lasttext = copy->content; 00883 ctxt->lasttsize = len; 00884 ctxt->lasttuse = len; 00885 } 00886 } else if ((target != NULL) && 00887 (target->last != NULL) && 00888 /* both escaped or both non-escaped text-nodes */ 00889 (((target->last->type == XML_TEXT_NODE) && 00890 (target->last->name == cur->name)) || 00891 /* non-escaped text nodes and CDATA-section nodes */ 00892 (((target->last->type == XML_CDATA_SECTION_NODE) && 00893 (cur->name == xmlStringTextNoenc))))) 00894 { 00895 /* 00896 * we are appending to an existing text node 00897 */ 00898 copy = xsltAddTextString(ctxt, target->last, cur->content, 00899 xmlStrlen(cur->content)); 00900 goto exit; 00901 } else if ((interned) && (target != NULL) && 00902 (target->doc != NULL) && 00903 (target->doc->dict == ctxt->dict)) 00904 { 00905 /* 00906 * TODO: DO we want to use this also for "text" output? 00907 */ 00908 copy = xmlNewTextLen(NULL, 0); 00909 if (copy == NULL) 00910 goto exit; 00911 if (cur->name == xmlStringTextNoenc) 00912 copy->name = xmlStringTextNoenc; 00913 00914 /* 00915 * Must confirm that content is in dict (bug 302821) 00916 * TODO: This check should be not needed for text coming 00917 * from the stylesheets 00918 */ 00919 if (xmlDictOwns(ctxt->dict, cur->content)) 00920 copy->content = cur->content; 00921 else { 00922 if ((copy->content = xmlStrdup(cur->content)) == NULL) 00923 return NULL; 00924 } 00925 } else { 00926 /* 00927 * normal processing. keep counters to extend the text node 00928 * in xsltAddTextString if needed. 00929 */ 00930 unsigned int len; 00931 00932 len = xmlStrlen(cur->content); 00933 copy = xmlNewTextLen(cur->content, len); 00934 if (copy == NULL) 00935 goto exit; 00936 if (cur->name == xmlStringTextNoenc) 00937 copy->name = xmlStringTextNoenc; 00938 ctxt->lasttext = copy->content; 00939 ctxt->lasttsize = len; 00940 ctxt->lasttuse = len; 00941 } 00942 if (copy != NULL) { 00943 if (target != NULL) { 00944 copy->doc = target->doc; 00945 /* 00946 * MAYBE TODO: Maybe we should reset the ctxt->lasttext here 00947 * to ensure that the optimized text-merging mechanism 00948 * won't interfere with normal node-merging in any case. 00949 */ 00950 copy = xsltAddChild(target, copy); 00951 } 00952 } else { 00953 xsltTransformError(ctxt, NULL, target, 00954 "xsltCopyText: text copy failed\n"); 00955 } 00956 00957 exit: 00958 if ((copy == NULL) || (copy->content == NULL)) { 00959 xsltTransformError(ctxt, NULL, target, 00960 "Internal error in xsltCopyText(): " 00961 "Failed to copy the string.\n"); 00962 ctxt->state = XSLT_STATE_STOPPED; 00963 } 00964 return(copy); 00965 } 00966 00982 static xmlAttrPtr 00983 xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, 00984 xmlNodePtr target, xmlAttrPtr attr) 00985 { 00986 xmlAttrPtr copy; 00987 xmlChar *value; 00988 00989 if (attr == NULL) 00990 return(NULL); 00991 00992 if (target->type != XML_ELEMENT_NODE) { 00993 xsltTransformError(ctxt, NULL, invocNode, 00994 "Cannot add an attribute node to a non-element node.\n"); 00995 return(NULL); 00996 } 00997 00998 if (target->children != NULL) { 00999 xsltTransformError(ctxt, NULL, invocNode, 01000 "Attribute nodes must be added before " 01001 "any child nodes to an element.\n"); 01002 return(NULL); 01003 } 01004 01005 value = xmlNodeListGetString(attr->doc, attr->children, 1); 01006 if (attr->ns != NULL) { 01007 xmlNsPtr ns; 01008 01009 ns = xsltGetSpecialNamespace(ctxt, invocNode, 01010 attr->ns->href, attr->ns->prefix, target); 01011 if (ns == NULL) { 01012 xsltTransformError(ctxt, NULL, invocNode, 01013 "Namespace fixup error: Failed to acquire an in-scope " 01014 "namespace binding of the copied attribute '{%s}%s'.\n", 01015 attr->ns->href, attr->name); 01016 /* 01017 * TODO: Should we just stop here? 01018 */ 01019 } 01020 /* 01021 * Note that xmlSetNsProp() will take care of duplicates 01022 * and assigns the new namespace even to a duplicate. 01023 */ 01024 copy = xmlSetNsProp(target, ns, attr->name, value); 01025 } else { 01026 copy = xmlSetNsProp(target, NULL, attr->name, value); 01027 } 01028 if (value != NULL) 01029 xmlFree(value); 01030 01031 if (copy == NULL) 01032 return(NULL); 01033 01034 #if 0 01035 /* 01036 * NOTE: This was optimized according to bug #342695. 01037 * TODO: Can this further be optimized, if source and target 01038 * share the same dict and attr->children is just 1 text node 01039 * which is in the dict? How probable is such a case? 01040 */ 01041 /* 01042 * TODO: Do we need to create an empty text node if the value 01043 * is the empty string? 01044 */ 01045 value = xmlNodeListGetString(attr->doc, attr->children, 1); 01046 if (value != NULL) { 01047 txtNode = xmlNewDocText(target->doc, NULL); 01048 if (txtNode == NULL) 01049 return(NULL); 01050 if ((target->doc != NULL) && 01051 (target->doc->dict != NULL)) 01052 { 01053 txtNode->content = 01054 (xmlChar *) xmlDictLookup(target->doc->dict, 01055 BAD_CAST value, -1); 01056 xmlFree(value); 01057 } else 01058 txtNode->content = value; 01059 copy->children = txtNode; 01060 } 01061 #endif 01062 01063 return(copy); 01064 } 01065 01081 static int 01082 xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt, 01083 xmlNodePtr invocNode, 01084 xmlNodePtr target, xmlAttrPtr attr) 01085 { 01086 xmlAttrPtr copy; 01087 xmlNsPtr origNs = NULL, copyNs = NULL; 01088 xmlChar *value; 01089 01090 /* 01091 * Don't use xmlCopyProp() here, since it will try to 01092 * reconciliate namespaces. 01093 */ 01094 while (attr != NULL) { 01095 /* 01096 * Find a namespace node in the tree of @target. 01097 * Avoid searching for the same ns. 01098 */ 01099 if (attr->ns != origNs) { 01100 origNs = attr->ns; 01101 if (attr->ns != NULL) { 01102 copyNs = xsltGetSpecialNamespace(ctxt, invocNode, 01103 attr->ns->href, attr->ns->prefix, target); 01104 if (copyNs == NULL) 01105 return(-1); 01106 } else 01107 copyNs = NULL; 01108 } 01109 /* 01110 * If attribute has a value, we need to copy it (watching out 01111 * for possible entities) 01112 */ 01113 if ((attr->children) && (attr->children->type == XML_TEXT_NODE) && 01114 (attr->children->next == NULL)) { 01115 copy = xmlNewNsProp(target, copyNs, attr->name, 01116 attr->children->content); 01117 } else if (attr->children != NULL) { 01118 value = xmlNodeListGetString(attr->doc, attr->children, 1); 01119 copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value); 01120 xmlFree(value); 01121 } else { 01122 copy = xmlNewNsProp(target, copyNs, attr->name, NULL); 01123 } 01124 01125 if (copy == NULL) 01126 return(-1); 01127 01128 attr = attr->next; 01129 } 01130 return(0); 01131 } 01132 01157 static xmlNodePtr 01158 xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node, 01159 xmlNodePtr insert, int isLRE) 01160 { 01161 xmlNodePtr copy; 01162 01163 if ((node->type == XML_DTD_NODE) || (insert == NULL)) 01164 return(NULL); 01165 if ((node->type == XML_TEXT_NODE) || 01166 (node->type == XML_CDATA_SECTION_NODE)) 01167 return(xsltCopyText(ctxt, insert, node, 0)); 01168 01169 copy = xmlDocCopyNode(node, insert->doc, 0); 01170 if (copy != NULL) { 01171 copy->doc = ctxt->output; 01172 copy = xsltAddChild(insert, copy); 01173 01174 if (node->type == XML_ELEMENT_NODE) { 01175 /* 01176 * Add namespaces as they are needed 01177 */ 01178 if (node->nsDef != NULL) { 01179 /* 01180 * TODO: Remove the LRE case in the refactored code 01181 * gets enabled. 01182 */ 01183 if (isLRE) 01184 xsltCopyNamespaceList(ctxt, copy, node->nsDef); 01185 else 01186 xsltCopyNamespaceListInternal(copy, node->nsDef); 01187 } 01188 01189 /* 01190 * URGENT TODO: The problem with this is that it does not 01191 * copy over all namespace nodes in scope. 01192 * The damn thing about this is, that we would need to 01193 * use the xmlGetNsList(), for every single node; this is 01194 * also done in xsltCopyTreeInternal(), but only for the top node. 01195 */ 01196 if (node->ns != NULL) { 01197 if (isLRE) { 01198 /* 01199 * REVISIT TODO: Since the non-refactored code still does 01200 * ns-aliasing, we need to call xsltGetNamespace() here. 01201 * Remove this when ready. 01202 */ 01203 copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy); 01204 } else { 01205 copy->ns = xsltGetSpecialNamespace(ctxt, 01206 node, node->ns->href, node->ns->prefix, copy); 01207 01208 } 01209 } else if ((insert->type == XML_ELEMENT_NODE) && 01210 (insert->ns != NULL)) 01211 { 01212 /* 01213 * "Undeclare" the default namespace. 01214 */ 01215 xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy); 01216 } 01217 } 01218 } else { 01219 xsltTransformError(ctxt, NULL, node, 01220 "xsltShallowCopyElem: copy %s failed\n", node->name); 01221 } 01222 return(copy); 01223 } 01224 01244 static xmlNodePtr 01245 xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, 01246 xmlNodePtr list, 01247 xmlNodePtr insert, int isLRE, int topElemVisited) 01248 { 01249 xmlNodePtr copy, ret = NULL; 01250 01251 while (list != NULL) { 01252 copy = xsltCopyTreeInternal(ctxt, invocNode, 01253 list, insert, isLRE, topElemVisited); 01254 if (copy != NULL) { 01255 if (ret == NULL) { 01256 ret = copy; 01257 } 01258 } 01259 list = list->next; 01260 } 01261 return(ret); 01262 } 01263 01280 static xmlNsPtr 01281 xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) { 01282 xmlNsPtr ret = NULL; 01283 xmlNsPtr p = NULL, q, luNs; 01284 01285 if (ns == NULL) 01286 return(NULL); 01287 /* 01288 * One can add namespaces only on element nodes 01289 */ 01290 if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) 01291 elem = NULL; 01292 01293 do { 01294 if (ns->type != XML_NAMESPACE_DECL) 01295 break; 01296 /* 01297 * Avoid duplicating namespace declarations on the tree. 01298 */ 01299 if (elem != NULL) { 01300 if ((elem->ns != NULL) && 01301 xmlStrEqual(elem->ns->prefix, ns->prefix) && 01302 xmlStrEqual(elem->ns->href, ns->href)) 01303 { 01304 ns = ns->next; 01305 continue; 01306 } 01307 luNs = xmlSearchNs(elem->doc, elem, ns->prefix); 01308 if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href))) 01309 { 01310 ns = ns->next; 01311 continue; 01312 } 01313 } 01314 q = xmlNewNs(elem, ns->href, ns->prefix); 01315 if (p == NULL) { 01316 ret = p = q; 01317 } else if (q != NULL) { 01318 p->next = q; 01319 p = q; 01320 } 01321 ns = ns->next; 01322 } while (ns != NULL); 01323 return(ret); 01324 } 01325 01337 static xmlNsPtr 01338 xsltShallowCopyNsNode(xsltTransformContextPtr ctxt, 01339 xmlNodePtr invocNode, 01340 xmlNodePtr insert, 01341 xmlNsPtr ns) 01342 { 01343 /* 01344 * TODO: Contrary to header comments, this is declared as int. 01345 * be modified to return a node pointer, or NULL if any error 01346 */ 01347 xmlNsPtr tmpns; 01348 01349 if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE)) 01350 return(NULL); 01351 01352 if (insert->children != NULL) { 01353 xsltTransformError(ctxt, NULL, invocNode, 01354 "Namespace nodes must be added before " 01355 "any child nodes are added to an element.\n"); 01356 return(NULL); 01357 } 01358 /* 01359 * BIG NOTE: Xalan-J simply overwrites any ns-decls with 01360 * an equal prefix. We definitively won't do that. 01361 * 01362 * MSXML 4.0 and the .NET ignores ns-decls for which an 01363 * equal prefix is already in use. 01364 * 01365 * Saxon raises an error like: 01366 * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace 01367 * nodes with the same name". 01368 * 01369 * NOTE: We'll currently follow MSXML here. 01370 * REVISIT TODO: Check if it's better to follow Saxon here. 01371 */ 01372 if (ns->prefix == NULL) { 01373 /* 01374 * If we are adding ns-nodes to an element using e.g. 01375 * <xsl:copy-of select="/foo/namespace::*">, then we need 01376 * to ensure that we don't incorrectly declare a default 01377 * namespace on an element in no namespace, which otherwise 01378 * would move the element incorrectly into a namespace, if 01379 * the node tree is serialized. 01380 */ 01381 if (insert->ns == NULL) 01382 goto occupied; 01383 } else if ((ns->prefix[0] == 'x') && 01384 xmlStrEqual(ns->prefix, BAD_CAST "xml")) 01385 { 01386 /* 01387 * The XML namespace is built in. 01388 */ 01389 return(NULL); 01390 } 01391 01392 if (insert->nsDef != NULL) { 01393 tmpns = insert->nsDef; 01394 do { 01395 if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) { 01396 if ((tmpns->prefix == ns->prefix) || 01397 xmlStrEqual(tmpns->prefix, ns->prefix)) 01398 { 01399 /* 01400 * Same prefix. 01401 */ 01402 if (xmlStrEqual(tmpns->href, ns->href)) 01403 return(NULL); 01404 goto occupied; 01405 } 01406 } 01407 tmpns = tmpns->next; 01408 } while (tmpns != NULL); 01409 } 01410 tmpns = xmlSearchNs(insert->doc, insert, ns->prefix); 01411 if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href)) 01412 return(NULL); 01413 /* 01414 * Declare a new namespace. 01415 * TODO: The problem (wrt efficiency) with this xmlNewNs() is 01416 * that it will again search the already declared namespaces 01417 * for a duplicate :-/ 01418 */ 01419 return(xmlNewNs(insert, ns->href, ns->prefix)); 01420 01421 occupied: 01422 /* 01423 * TODO: We could as well raise an error here (like Saxon does), 01424 * or at least generate a warning. 01425 */ 01426 return(NULL); 01427 } 01428 01448 static xmlNodePtr 01449 xsltCopyTreeInternal(xsltTransformContextPtr ctxt, 01450 xmlNodePtr invocNode, 01451 xmlNodePtr node, 01452 xmlNodePtr insert, int isLRE, int topElemVisited) 01453 { 01454 xmlNodePtr copy; 01455 01456 if (node == NULL) 01457 return(NULL); 01458 switch (node->type) { 01459 case XML_ELEMENT_NODE: 01460 case XML_ENTITY_REF_NODE: 01461 case XML_ENTITY_NODE: 01462 case XML_PI_NODE: 01463 case XML_COMMENT_NODE: 01464 case XML_DOCUMENT_NODE: 01465 case XML_HTML_DOCUMENT_NODE: 01466 #ifdef LIBXML_DOCB_ENABLED 01467 case XML_DOCB_DOCUMENT_NODE: 01468 #endif 01469 break; 01470 case XML_TEXT_NODE: { 01471 int noenc = (node->name == xmlStringTextNoenc); 01472 return(xsltCopyTextString(ctxt, insert, node->content, noenc)); 01473 } 01474 case XML_CDATA_SECTION_NODE: 01475 return(xsltCopyTextString(ctxt, insert, node->content, 0)); 01476 case XML_ATTRIBUTE_NODE: 01477 return((xmlNodePtr) 01478 xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node)); 01479 case XML_NAMESPACE_DECL: 01480 return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode, 01481 insert, (xmlNsPtr) node)); 01482 01483 case XML_DOCUMENT_TYPE_NODE: 01484 case XML_DOCUMENT_FRAG_NODE: 01485 case XML_NOTATION_NODE: 01486 case XML_DTD_NODE: 01487 case XML_ELEMENT_DECL: 01488 case XML_ATTRIBUTE_DECL: 01489 case XML_ENTITY_DECL: 01490 case XML_XINCLUDE_START: 01491 case XML_XINCLUDE_END: 01492 return(NULL); 01493 } 01494 if (XSLT_IS_RES_TREE_FRAG(node)) { 01495 if (node->children != NULL) 01496 copy = xsltCopyTreeList(ctxt, invocNode, 01497 node->children, insert, 0, 0); 01498 else 01499 copy = NULL; 01500 return(copy); 01501 } 01502 copy = xmlDocCopyNode(node, insert->doc, 0); 01503 if (copy != NULL) { 01504 copy->doc = ctxt->output; 01505 copy = xsltAddChild(insert, copy); 01506 /* 01507 * The node may have been coalesced into another text node. 01508 */ 01509 if (insert->last != copy) 01510 return(insert->last); 01511 copy->next = NULL; 01512 01513 if (node->type == XML_ELEMENT_NODE) { 01514 /* 01515 * Copy in-scope namespace nodes. 01516 * 01517 * REVISIT: Since we try to reuse existing in-scope ns-decls by 01518 * using xmlSearchNsByHref(), this will eventually change 01519 * the prefix of an original ns-binding; thus it might 01520 * break QNames in element/attribute content. 01521 * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation 01522 * context, plus a ns-lookup function, which writes directly 01523 * to a given list, then we wouldn't need to create/free the 01524 * nsList every time. 01525 */ 01526 if ((topElemVisited == 0) && 01527 (node->parent != NULL) && 01528 (node->parent->type != XML_DOCUMENT_NODE) && 01529 (node->parent->type != XML_HTML_DOCUMENT_NODE)) 01530 { 01531 xmlNsPtr *nsList, *curns, ns; 01532 01533 /* 01534 * If this is a top-most element in a tree to be 01535 * copied, then we need to ensure that all in-scope 01536 * namespaces are copied over. For nodes deeper in the 01537 * tree, it is sufficient to reconcile only the ns-decls 01538 * (node->nsDef entries). 01539 */ 01540 01541 nsList = xmlGetNsList(node->doc, node); 01542 if (nsList != NULL) { 01543 curns = nsList; 01544 do { 01545 /* 01546 * Search by prefix first in order to break as less 01547 * QNames in element/attribute content as possible. 01548 */ 01549 ns = xmlSearchNs(insert->doc, insert, 01550 (*curns)->prefix); 01551 01552 if ((ns == NULL) || 01553 (! xmlStrEqual(ns->href, (*curns)->href))) 01554 { 01555 ns = NULL; 01556 /* 01557 * Search by namespace name. 01558 * REVISIT TODO: Currently disabled. 01559 */ 01560 #if 0 01561 ns = xmlSearchNsByHref(insert->doc, 01562 insert, (*curns)->href); 01563 #endif 01564 } 01565 if (ns == NULL) { 01566 /* 01567 * Declare a new namespace on the copied element. 01568 */ 01569 ns = xmlNewNs(copy, (*curns)->href, 01570 (*curns)->prefix); 01571 /* TODO: Handle errors */ 01572 } 01573 if (node->ns == *curns) { 01574 /* 01575 * If this was the original's namespace then set 01576 * the generated counterpart on the copy. 01577 */ 01578 copy->ns = ns; 01579 } 01580 curns++; 01581 } while (*curns != NULL); 01582 xmlFree(nsList); 01583 } 01584 } else if (node->nsDef != NULL) { 01585 /* 01586 * Copy over all namespace declaration attributes. 01587 */ 01588 if (node->nsDef != NULL) { 01589 if (isLRE) 01590 xsltCopyNamespaceList(ctxt, copy, node->nsDef); 01591 else 01592 xsltCopyNamespaceListInternal(copy, node->nsDef); 01593 } 01594 } 01595 /* 01596 * Set the namespace. 01597 */ 01598 if (node->ns != NULL) { 01599 if (copy->ns == NULL) { 01600 /* 01601 * This will map copy->ns to one of the newly created 01602 * in-scope ns-decls, OR create a new ns-decl on @copy. 01603 */ 01604 copy->ns = xsltGetSpecialNamespace(ctxt, invocNode, 01605 node->ns->href, node->ns->prefix, copy); 01606 } 01607 } else if ((insert->type == XML_ELEMENT_NODE) && 01608 (insert->ns != NULL)) 01609 { 01610 /* 01611 * "Undeclare" the default namespace on @copy with xmlns="". 01612 */ 01613 xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy); 01614 } 01615 /* 01616 * Copy attribute nodes. 01617 */ 01618 if (node->properties != NULL) { 01619 xsltCopyAttrListNoOverwrite(ctxt, invocNode, 01620 copy, node->properties); 01621 } 01622 if (topElemVisited == 0) 01623 topElemVisited = 1; 01624 } 01625 /* 01626 * Copy the subtree. 01627 */ 01628 if (node->children != NULL) { 01629 xsltCopyTreeList(ctxt, invocNode, 01630 node->children, copy, isLRE, topElemVisited); 01631 } 01632 } else { 01633 xsltTransformError(ctxt, NULL, invocNode, 01634 "xsltCopyTreeInternal: Copying of '%s' failed.\n", node->name); 01635 } 01636 return(copy); 01637 } 01638 01654 xmlNodePtr 01655 xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr node, 01656 xmlNodePtr insert, int literal) 01657 { 01658 return(xsltCopyTreeInternal(ctxt, node, node, insert, literal, 0)); 01659 01660 } 01661 01662 /************************************************************************ 01663 * * 01664 * Error/fallback processing * 01665 * * 01666 ************************************************************************/ 01667 01678 static int 01679 xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node, 01680 xmlNodePtr inst) { 01681 01682 xmlNodePtr child; 01683 int ret = 0; 01684 01685 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || 01686 (inst->children == NULL)) 01687 return(0); 01688 01689 child = inst->children; 01690 while (child != NULL) { 01691 if ((IS_XSLT_ELEM(child)) && 01692 (xmlStrEqual(child->name, BAD_CAST "fallback"))) { 01693 #ifdef WITH_XSLT_DEBUG_PARSING 01694 xsltGenericDebug(xsltGenericDebugContext, 01695 "applying xsl:fallback\n"); 01696 #endif 01697 ret++; 01698 xsltApplySequenceConstructor(ctxt, node, child->children, 01699 NULL); 01700 } 01701 child = child->next; 01702 } 01703 return(ret); 01704 } 01705 01706 /************************************************************************ 01707 * * 01708 * Default processing * 01709 * * 01710 ************************************************************************/ 01711 01734 static void 01735 xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, 01736 xsltStackElemPtr params) { 01737 xmlNodePtr copy; 01738 xmlNodePtr delete = NULL, cur; 01739 int nbchild = 0, oldSize; 01740 int childno = 0, oldPos; 01741 xsltTemplatePtr template; 01742 01743 CHECK_STOPPED; 01744 /* 01745 * Handling of leaves 01746 */ 01747 switch (node->type) { 01748 case XML_DOCUMENT_NODE: 01749 case XML_HTML_DOCUMENT_NODE: 01750 case XML_ELEMENT_NODE: 01751 break; 01752 case XML_CDATA_SECTION_NODE: 01753 #ifdef WITH_XSLT_DEBUG_PROCESS 01754 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01755 "xsltDefaultProcessOneNode: copy CDATA %s\n", 01756 node->content)); 01757 #endif 01758 copy = xsltCopyText(ctxt, ctxt->insert, node, 0); 01759 if (copy == NULL) { 01760 xsltTransformError(ctxt, NULL, node, 01761 "xsltDefaultProcessOneNode: cdata copy failed\n"); 01762 } 01763 return; 01764 case XML_TEXT_NODE: 01765 #ifdef WITH_XSLT_DEBUG_PROCESS 01766 if (node->content == NULL) { 01767 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01768 "xsltDefaultProcessOneNode: copy empty text\n")); 01769 return; 01770 } else { 01771 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01772 "xsltDefaultProcessOneNode: copy text %s\n", 01773 node->content)); 01774 } 01775 #endif 01776 copy = xsltCopyText(ctxt, ctxt->insert, node, 0); 01777 if (copy == NULL) { 01778 xsltTransformError(ctxt, NULL, node, 01779 "xsltDefaultProcessOneNode: text copy failed\n"); 01780 } 01781 return; 01782 case XML_ATTRIBUTE_NODE: 01783 cur = node->children; 01784 while ((cur != NULL) && (cur->type != XML_TEXT_NODE)) 01785 cur = cur->next; 01786 if (cur == NULL) { 01787 xsltTransformError(ctxt, NULL, node, 01788 "xsltDefaultProcessOneNode: no text for attribute\n"); 01789 } else { 01790 #ifdef WITH_XSLT_DEBUG_PROCESS 01791 if (cur->content == NULL) { 01792 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01793 "xsltDefaultProcessOneNode: copy empty text\n")); 01794 } else { 01795 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01796 "xsltDefaultProcessOneNode: copy text %s\n", 01797 cur->content)); 01798 } 01799 #endif 01800 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); 01801 if (copy == NULL) { 01802 xsltTransformError(ctxt, NULL, node, 01803 "xsltDefaultProcessOneNode: text copy failed\n"); 01804 } 01805 } 01806 return; 01807 default: 01808 return; 01809 } 01810 /* 01811 * Handling of Elements: first pass, cleanup and counting 01812 */ 01813 cur = node->children; 01814 while (cur != NULL) { 01815 switch (cur->type) { 01816 case XML_TEXT_NODE: 01817 case XML_CDATA_SECTION_NODE: 01818 case XML_DOCUMENT_NODE: 01819 case XML_HTML_DOCUMENT_NODE: 01820 case XML_ELEMENT_NODE: 01821 case XML_PI_NODE: 01822 case XML_COMMENT_NODE: 01823 nbchild++; 01824 break; 01825 case XML_DTD_NODE: 01826 /* Unlink the DTD, it's still reachable using doc->intSubset */ 01827 if (cur->next != NULL) 01828 cur->next->prev = cur->prev; 01829 if (cur->prev != NULL) 01830 cur->prev->next = cur->next; 01831 break; 01832 default: 01833 #ifdef WITH_XSLT_DEBUG_PROCESS 01834 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01835 "xsltDefaultProcessOneNode: skipping node type %d\n", 01836 cur->type)); 01837 #endif 01838 delete = cur; 01839 } 01840 cur = cur->next; 01841 if (delete != NULL) { 01842 #ifdef WITH_XSLT_DEBUG_PROCESS 01843 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01844 "xsltDefaultProcessOneNode: removing ignorable blank node\n")); 01845 #endif 01846 xmlUnlinkNode(delete); 01847 xmlFreeNode(delete); 01848 delete = NULL; 01849 } 01850 } 01851 if (delete != NULL) { 01852 #ifdef WITH_XSLT_DEBUG_PROCESS 01853 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01854 "xsltDefaultProcessOneNode: removing ignorable blank node\n")); 01855 #endif 01856 xmlUnlinkNode(delete); 01857 xmlFreeNode(delete); 01858 delete = NULL; 01859 } 01860 01861 /* 01862 * Handling of Elements: second pass, actual processing 01863 */ 01864 oldSize = ctxt->xpathCtxt->contextSize; 01865 oldPos = ctxt->xpathCtxt->proximityPosition; 01866 cur = node->children; 01867 while (cur != NULL) { 01868 childno++; 01869 switch (cur->type) { 01870 case XML_DOCUMENT_NODE: 01871 case XML_HTML_DOCUMENT_NODE: 01872 case XML_ELEMENT_NODE: 01873 ctxt->xpathCtxt->contextSize = nbchild; 01874 ctxt->xpathCtxt->proximityPosition = childno; 01875 xsltProcessOneNode(ctxt, cur, params); 01876 break; 01877 case XML_CDATA_SECTION_NODE: 01878 template = xsltGetTemplate(ctxt, cur, NULL); 01879 if (template) { 01880 #ifdef WITH_XSLT_DEBUG_PROCESS 01881 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01882 "xsltDefaultProcessOneNode: applying template for CDATA %s\n", 01883 cur->content)); 01884 #endif 01885 /* 01886 * Instantiate the xsl:template. 01887 */ 01888 xsltApplyXSLTTemplate(ctxt, cur, template->content, 01889 template, params); 01890 } else /* if (ctxt->mode == NULL) */ { 01891 #ifdef WITH_XSLT_DEBUG_PROCESS 01892 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01893 "xsltDefaultProcessOneNode: copy CDATA %s\n", 01894 cur->content)); 01895 #endif 01896 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); 01897 if (copy == NULL) { 01898 xsltTransformError(ctxt, NULL, cur, 01899 "xsltDefaultProcessOneNode: cdata copy failed\n"); 01900 } 01901 } 01902 break; 01903 case XML_TEXT_NODE: 01904 template = xsltGetTemplate(ctxt, cur, NULL); 01905 if (template) { 01906 #ifdef WITH_XSLT_DEBUG_PROCESS 01907 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01908 "xsltDefaultProcessOneNode: applying template for text %s\n", 01909 cur->content)); 01910 #endif 01911 ctxt->xpathCtxt->contextSize = nbchild; 01912 ctxt->xpathCtxt->proximityPosition = childno; 01913 /* 01914 * Instantiate the xsl:template. 01915 */ 01916 xsltApplyXSLTTemplate(ctxt, cur, template->content, 01917 template, params); 01918 } else /* if (ctxt->mode == NULL) */ { 01919 #ifdef WITH_XSLT_DEBUG_PROCESS 01920 if (cur->content == NULL) { 01921 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01922 "xsltDefaultProcessOneNode: copy empty text\n")); 01923 } else { 01924 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01925 "xsltDefaultProcessOneNode: copy text %s\n", 01926 cur->content)); 01927 } 01928 #endif 01929 copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); 01930 if (copy == NULL) { 01931 xsltTransformError(ctxt, NULL, cur, 01932 "xsltDefaultProcessOneNode: text copy failed\n"); 01933 } 01934 } 01935 break; 01936 case XML_PI_NODE: 01937 case XML_COMMENT_NODE: 01938 template = xsltGetTemplate(ctxt, cur, NULL); 01939 if (template) { 01940 #ifdef WITH_XSLT_DEBUG_PROCESS 01941 if (cur->type == XML_PI_NODE) { 01942 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01943 "xsltDefaultProcessOneNode: template found for PI %s\n", 01944 cur->name)); 01945 } else if (cur->type == XML_COMMENT_NODE) { 01946 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01947 "xsltDefaultProcessOneNode: template found for comment\n")); 01948 } 01949 #endif 01950 ctxt->xpathCtxt->contextSize = nbchild; 01951 ctxt->xpathCtxt->proximityPosition = childno; 01952 /* 01953 * Instantiate the xsl:template. 01954 */ 01955 xsltApplyXSLTTemplate(ctxt, cur, template->content, 01956 template, params); 01957 } 01958 break; 01959 default: 01960 break; 01961 } 01962 cur = cur->next; 01963 } 01964 ctxt->xpathCtxt->contextSize = oldSize; 01965 ctxt->xpathCtxt->proximityPosition = oldPos; 01966 } 01967 01977 void 01978 xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 01979 xsltStackElemPtr withParams) 01980 { 01981 xsltTemplatePtr templ; 01982 xmlNodePtr oldNode; 01983 01984 templ = xsltGetTemplate(ctxt, contextNode, NULL); 01985 /* 01986 * If no template is found, apply the default rule. 01987 */ 01988 if (templ == NULL) { 01989 #ifdef WITH_XSLT_DEBUG_PROCESS 01990 if (contextNode->type == XML_DOCUMENT_NODE) { 01991 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01992 "xsltProcessOneNode: no template found for /\n")); 01993 } else if (contextNode->type == XML_CDATA_SECTION_NODE) { 01994 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01995 "xsltProcessOneNode: no template found for CDATA\n")); 01996 } else if (contextNode->type == XML_ATTRIBUTE_NODE) { 01997 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 01998 "xsltProcessOneNode: no template found for attribute %s\n", 01999 ((xmlAttrPtr) contextNode)->name)); 02000 } else { 02001 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 02002 "xsltProcessOneNode: no template found for %s\n", contextNode->name)); 02003 } 02004 #endif 02005 oldNode = ctxt->node; 02006 ctxt->node = contextNode; 02007 xsltDefaultProcessOneNode(ctxt, contextNode, withParams); 02008 ctxt->node = oldNode; 02009 return; 02010 } 02011 02012 if (contextNode->type == XML_ATTRIBUTE_NODE) { 02013 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; 02014 /* 02015 * Set the "current template rule". 02016 */ 02017 ctxt->currentTemplateRule = templ; 02018 02019 #ifdef WITH_XSLT_DEBUG_PROCESS 02020 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 02021 "xsltProcessOneNode: applying template '%s' for attribute %s\n", 02022 templ->match, contextNode->name)); 02023 #endif 02024 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); 02025 02026 ctxt->currentTemplateRule = oldCurTempRule; 02027 } else { 02028 xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; 02029 /* 02030 * Set the "current template rule". 02031 */ 02032 ctxt->currentTemplateRule = templ; 02033 02034 #ifdef WITH_XSLT_DEBUG_PROCESS 02035 if (contextNode->type == XML_DOCUMENT_NODE) { 02036 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 02037 "xsltProcessOneNode: applying template '%s' for /\n", 02038 templ->match)); 02039 } else { 02040 XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, 02041 "xsltProcessOneNode: applying template '%s' for %s\n", 02042 templ->match, contextNode->name)); 02043 } 02044 #endif 02045 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); 02046 02047 ctxt->currentTemplateRule = oldCurTempRule; 02048 } 02049 } 02050 02051 static xmlNodePtr 02052 xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt, 02053 xmlNodePtr contextNode, 02054 xmlNodePtr list, 02055 xsltTemplatePtr templ, 02056 int *addCallResult) 02057 { 02058 xmlNodePtr debugedNode = NULL; 02059 02060 if (ctxt->debugStatus != XSLT_DEBUG_NONE) { 02061 if (templ) { 02062 *addCallResult = xslAddCall(templ, templ->elem); 02063 } else { 02064 *addCallResult = xslAddCall(NULL, list); 02065 } 02066 switch (ctxt->debugStatus) { 02067 case XSLT_DEBUG_RUN_RESTART: 02068 case XSLT_DEBUG_QUIT: 02069 if (*addCallResult) 02070 xslDropCall(); 02071 return(NULL); 02072 } 02073 if (templ) { 02074 xslHandleDebugger(templ->elem, contextNode, templ, ctxt); 02075 debugedNode = templ->elem; 02076 } else if (list) { 02077 xslHandleDebugger(list, contextNode, templ, ctxt); 02078 debugedNode = list; 02079 } else if (ctxt->inst) { 02080 xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt); 02081 debugedNode = ctxt->inst; 02082 } 02083 } 02084 return(debugedNode); 02085 } 02086 02099 int 02100 xsltLocalVariablePush(xsltTransformContextPtr ctxt, 02101 xsltStackElemPtr variable, 02102 int level) 02103 { 02104 if (ctxt->varsMax == 0) { 02105 ctxt->varsMax = 10; 02106 ctxt->varsTab = 02107 (xsltStackElemPtr *) xmlMalloc(ctxt->varsMax * 02108 sizeof(ctxt->varsTab[0])); 02109 if (ctxt->varsTab == NULL) { 02110 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); 02111 return (-1); 02112 } 02113 } 02114 if (ctxt->varsNr >= ctxt->varsMax) { 02115 ctxt->varsMax *= 2; 02116 ctxt->varsTab = 02117 (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, 02118 ctxt->varsMax * 02119 sizeof(ctxt->varsTab[0])); 02120 if (ctxt->varsTab == NULL) { 02121 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); 02122 return (-1); 02123 } 02124 } 02125 ctxt->varsTab[ctxt->varsNr++] = variable; 02126 ctxt->vars = variable; 02127 variable->level = level; 02128 return(0); 02129 } 02130 02137 static void 02138 xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) 02139 { 02140 xmlDocPtr cur = ctxt->localRVT, tmp; 02141 02142 while ((cur != NULL) && (cur != base)) { 02143 if (cur->psvi == (void *) ((long) 1)) { 02144 cur = (xmlDocPtr) cur->next; 02145 } else { 02146 tmp = cur; 02147 cur = (xmlDocPtr) cur->next; 02148 02149 if (tmp == ctxt->localRVT) 02150 ctxt->localRVT = cur; 02151 02152 /* 02153 * We need ctxt->localRVTBase for extension instructions 02154 * which return values (like EXSLT's function). 02155 */ 02156 if (tmp == ctxt->localRVTBase) 02157 ctxt->localRVTBase = cur; 02158 02159 if (tmp->prev) 02160 tmp->prev->next = (xmlNodePtr) cur; 02161 if (cur) 02162 cur->prev = tmp->prev; 02163 xsltReleaseRVT(ctxt, tmp); 02164 } 02165 } 02166 } 02167 02183 static void 02184 xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, 02185 xmlNodePtr contextNode, xmlNodePtr list, 02186 xsltTemplatePtr templ) 02187 { 02188 xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; 02189 xmlNodePtr cur, insert, copy = NULL; 02190 int level = 0, oldVarsNr; 02191 xmlDocPtr oldLocalFragmentTop, oldLocalFragmentBase; 02192 02193 #ifdef XSLT_REFACTORED 02194 xsltStylePreCompPtr info; 02195 #endif 02196 02197 #ifdef WITH_DEBUGGER 02198 int addCallResult = 0; 02199 xmlNodePtr debuggedNode = NULL; 02200 #endif 02201 02202 if (ctxt == NULL) 02203 return; 02204 02205 #ifdef WITH_DEBUGGER 02206 if (ctxt->debugStatus != XSLT_DEBUG_NONE) { 02207 debuggedNode = 02208 xsltDebuggerStartSequenceConstructor(ctxt, contextNode, 02209 list, templ, &addCallResult); 02210 if (debuggedNode == NULL) 02211 return; 02212 } 02213 #endif 02214 02215 if (list == NULL) 02216 return; 02217 CHECK_STOPPED; 02218 02219 oldLocalFragmentTop = ctxt->localRVT; 02220 oldInsert = insert = ctxt->insert; 02221 oldInst = oldCurInst = ctxt->inst; 02222 oldContextNode = ctxt->node; 02223 /* 02224 * Save current number of variables on the stack; new vars are popped when 02225 * exiting. 02226 */ 02227 oldVarsNr = ctxt->varsNr; 02228 /* 02229 * Process the sequence constructor. 02230 */ 02231 cur = list; 02232 while (cur != NULL) { 02233 ctxt->inst = cur; 02234 02235 #ifdef WITH_DEBUGGER 02236 switch (ctxt->debugStatus) { 02237 case XSLT_DEBUG_RUN_RESTART: 02238 case XSLT_DEBUG_QUIT: 02239 break; 02240 02241 } 02242 #endif 02243 /* 02244 * Test; we must have a valid insertion point. 02245 */ 02246 if (insert == NULL) { 02247 02248 #ifdef WITH_XSLT_DEBUG_PROCESS 02249 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02250 "xsltApplySequenceConstructor: insert == NULL !\n")); 02251 #endif 02252 goto error; 02253 } 02254 02255 #ifdef WITH_DEBUGGER 02256 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur)) 02257 xslHandleDebugger(cur, contextNode, templ, ctxt); 02258 #endif 02259 02260 #ifdef XSLT_REFACTORED 02261 if (cur->type == XML_ELEMENT_NODE) { 02262 info = (xsltStylePreCompPtr) cur->psvi; 02263 /* 02264 * We expect a compiled representation on: 02265 * 1) XSLT instructions of this XSLT version (1.0) 02266 * (with a few exceptions) 02267 * 2) Literal result elements 02268 * 3) Extension instructions 02269 * 4) XSLT instructions of future XSLT versions 02270 * (forwards-compatible mode). 02271 */ 02272 if (info == NULL) { 02273 /* 02274 * Handle the rare cases where we don't expect a compiled 02275 * representation on an XSLT element. 02276 */ 02277 if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) { 02278 xsltMessage(ctxt, contextNode, cur); 02279 goto skip_children; 02280 } 02281 /* 02282 * Something really went wrong: 02283 */ 02284 xsltTransformError(ctxt, NULL, cur, 02285 "Internal error in xsltApplySequenceConstructor(): " 02286 "The element '%s' in the stylesheet has no compiled " 02287 "representation.\n", 02288 cur->name); 02289 goto skip_children; 02290 } 02291 02292 if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) { 02293 xsltStyleItemLRElementInfoPtr lrInfo = 02294 (xsltStyleItemLRElementInfoPtr) info; 02295 /* 02296 * Literal result elements 02297 * -------------------------------------------------------- 02298 */ 02299 #ifdef WITH_XSLT_DEBUG_PROCESS 02300 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 02301 xsltGenericDebug(xsltGenericDebugContext, 02302 "xsltApplySequenceConstructor: copy literal result " 02303 "element '%s'\n", cur->name)); 02304 #endif 02305 /* 02306 * Copy the raw element-node. 02307 * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert)) 02308 * == NULL) 02309 * goto error; 02310 */ 02311 copy = xmlDocCopyNode(cur, insert->doc, 0); 02312 if (copy == NULL) { 02313 xsltTransformError(ctxt, NULL, cur, 02314 "Internal error in xsltApplySequenceConstructor(): " 02315 "Failed to copy literal result element '%s'.\n", 02316 cur->name); 02317 goto error; 02318 } else { 02319 /* 02320 * Add the element-node to the result tree. 02321 */ 02322 copy->doc = ctxt->output; 02323 copy = xsltAddChild(insert, copy); 02324 /* 02325 * Create effective namespaces declarations. 02326 * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef); 02327 */ 02328 if (lrInfo->effectiveNs != NULL) { 02329 xsltEffectiveNsPtr effNs = lrInfo->effectiveNs; 02330 xmlNsPtr ns, lastns = NULL; 02331 02332 while (effNs != NULL) { 02333 /* 02334 * Avoid generating redundant namespace 02335 * declarations; thus lookup if there is already 02336 * such a ns-decl in the result. 02337 */ 02338 ns = xmlSearchNs(copy->doc, copy, effNs->prefix); 02339 if ((ns != NULL) && 02340 (xmlStrEqual(ns->href, effNs->nsName))) 02341 { 02342 effNs = effNs->next; 02343 continue; 02344 } 02345 ns = xmlNewNs(copy, effNs->nsName, effNs->prefix); 02346 if (ns == NULL) { 02347 xsltTransformError(ctxt, NULL, cur, 02348 "Internal error in " 02349 "xsltApplySequenceConstructor(): " 02350 "Failed to copy a namespace " 02351 "declaration.\n"); 02352 goto error; 02353 } 02354 02355 if (lastns == NULL) 02356 copy->nsDef = ns; 02357 else 02358 lastns->next =ns; 02359 lastns = ns; 02360 02361 effNs = effNs->next; 02362 } 02363 02364 } 02365 /* 02366 * NOTE that we don't need to apply ns-alising: this was 02367 * already done at compile-time. 02368 */ 02369 if (cur->ns != NULL) { 02370 /* 02371 * If there's no such ns-decl in the result tree, 02372 * then xsltGetSpecialNamespace() will 02373 * create a ns-decl on the copied node. 02374 */ 02375 copy->ns = xsltGetSpecialNamespace(ctxt, cur, 02376 cur->ns->href, cur->ns->prefix, copy); 02377 } else { 02378 /* 02379 * Undeclare the default namespace if needed. 02380 * This can be skipped, if the result element has 02381 * no ns-decls, in which case the result element 02382 * obviously does not declare a default namespace; 02383 * AND there's either no parent, or the parent 02384 * element is in no namespace; this means there's no 02385 * default namespace is scope to care about. 02386 * 02387 * REVISIT: This might result in massive 02388 * generation of ns-decls if nodes in a default 02389 * namespaces are mixed with nodes in no namespace. 02390 * 02391 */ 02392 if (copy->nsDef || 02393 ((insert != NULL) && 02394 (insert->type == XML_ELEMENT_NODE) && 02395 (insert->ns != NULL))) 02396 { 02397 xsltGetSpecialNamespace(ctxt, cur, 02398 NULL, NULL, copy); 02399 } 02400 } 02401 } 02402 /* 02403 * SPEC XSLT 2.0 "Each attribute of the literal result 02404 * element, other than an attribute in the XSLT namespace, 02405 * is processed to produce an attribute for the element in 02406 * the result tree." 02407 * NOTE: See bug #341325. 02408 */ 02409 if (cur->properties != NULL) { 02410 xsltAttrListTemplateProcess(ctxt, copy, cur->properties); 02411 } 02412 } else if (IS_XSLT_ELEM_FAST(cur)) { 02413 /* 02414 * XSLT instructions 02415 * -------------------------------------------------------- 02416 */ 02417 if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) { 02418 /* 02419 * We hit an unknown XSLT element. 02420 * Try to apply one of the fallback cases. 02421 */ 02422 ctxt->insert = insert; 02423 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { 02424 xsltTransformError(ctxt, NULL, cur, 02425 "The is no fallback behaviour defined for " 02426 "the unknown XSLT element '%s'.\n", 02427 cur->name); 02428 } 02429 ctxt->insert = oldInsert; 02430 } else if (info->func != NULL) { 02431 /* 02432 * Execute the XSLT instruction. 02433 */ 02434 ctxt->insert = insert; 02435 02436 info->func(ctxt, contextNode, cur, 02437 (xsltElemPreCompPtr) info); 02438 02439 /* 02440 * Cleanup temporary tree fragments. 02441 */ 02442 if (oldLocalFragmentTop != ctxt->localRVT) 02443 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 02444 02445 ctxt->insert = oldInsert; 02446 } else if (info->type == XSLT_FUNC_VARIABLE) { 02447 xsltStackElemPtr tmpvar = ctxt->vars; 02448 02449 xsltParseStylesheetVariable(ctxt, cur); 02450 02451 if (tmpvar != ctxt->vars) { 02452 /* 02453 * TODO: Using a @tmpvar is an annoying workaround, but 02454 * the current mechanisms do not provide any other way 02455 * of knowing if the var was really pushed onto the 02456 * stack. 02457 */ 02458 ctxt->vars->level = level; 02459 } 02460 } else if (info->type == XSLT_FUNC_MESSAGE) { 02461 /* 02462 * TODO: Won't be hit, since we don't compile xsl:message. 02463 */ 02464 xsltMessage(ctxt, contextNode, cur); 02465 } else { 02466 xsltTransformError(ctxt, NULL, cur, 02467 "Unexpected XSLT element '%s'.\n", cur->name); 02468 } 02469 goto skip_children; 02470 02471 } else { 02472 xsltTransformFunction func; 02473 /* 02474 * Extension intructions (elements) 02475 * -------------------------------------------------------- 02476 */ 02477 if (cur->psvi == xsltExtMarker) { 02478 /* 02479 * The xsltExtMarker was set during the compilation 02480 * of extension instructions if there was no registered 02481 * handler for this specific extension function at 02482 * compile-time. 02483 * Libxslt will now lookup if a handler is 02484 * registered in the context of this transformation. 02485 */ 02486 func = (xsltTransformFunction) 02487 xsltExtElementLookup(ctxt, cur->name, cur->ns->href); 02488 } else 02489 func = ((xsltElemPreCompPtr) cur->psvi)->func; 02490 02491 if (func == NULL) { 02492 /* 02493 * No handler available. 02494 * Try to execute fallback behaviour via xsl:fallback. 02495 */ 02496 #ifdef WITH_XSLT_DEBUG_PROCESS 02497 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 02498 xsltGenericDebug(xsltGenericDebugContext, 02499 "xsltApplySequenceConstructor: unknown extension %s\n", 02500 cur->name)); 02501 #endif 02502 ctxt->insert = insert; 02503 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { 02504 xsltTransformError(ctxt, NULL, cur, 02505 "Unknown extension instruction '{%s}%s'.\n", 02506 cur->ns->href, cur->name); 02507 } 02508 ctxt->insert = oldInsert; 02509 } else { 02510 /* 02511 * Execute the handler-callback. 02512 */ 02513 #ifdef WITH_XSLT_DEBUG_PROCESS 02514 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02515 "xsltApplySequenceConstructor: extension construct %s\n", 02516 cur->name)); 02517 #endif 02518 ctxt->insert = insert; 02519 /* 02520 * We need the fragment base for extension instructions 02521 * which return values (like EXSLT's function). 02522 */ 02523 oldLocalFragmentBase = ctxt->localRVTBase; 02524 ctxt->localRVTBase = NULL; 02525 02526 func(ctxt, contextNode, cur, cur->psvi); 02527 02528 ctxt->localRVTBase = oldLocalFragmentBase; 02529 /* 02530 * Cleanup temporary tree fragments. 02531 */ 02532 if (oldLocalFragmentTop != ctxt->localRVT) 02533 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 02534 02535 ctxt->insert = oldInsert; 02536 } 02537 goto skip_children; 02538 } 02539 02540 } else if (XSLT_IS_TEXT_NODE(cur)) { 02541 /* 02542 * Text 02543 * ------------------------------------------------------------ 02544 */ 02545 #ifdef WITH_XSLT_DEBUG_PROCESS 02546 if (cur->name == xmlStringTextNoenc) { 02547 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 02548 xsltGenericDebug(xsltGenericDebugContext, 02549 "xsltApplySequenceConstructor: copy unescaped text '%s'\n", 02550 cur->content)); 02551 } else { 02552 XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, 02553 xsltGenericDebug(xsltGenericDebugContext, 02554 "xsltApplySequenceConstructor: copy text '%s'\n", 02555 cur->content)); 02556 } 02557 #endif 02558 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) 02559 goto error; 02560 } 02561 02562 #else /* XSLT_REFACTORED */ 02563 02564 if (IS_XSLT_ELEM(cur)) { 02565 /* 02566 * This is an XSLT node 02567 */ 02568 xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi; 02569 02570 if (info == NULL) { 02571 if (IS_XSLT_NAME(cur, "message")) { 02572 xsltMessage(ctxt, contextNode, cur); 02573 } else { 02574 /* 02575 * That's an error try to apply one of the fallback cases 02576 */ 02577 ctxt->insert = insert; 02578 if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { 02579 xsltGenericError(xsltGenericErrorContext, 02580 "xsltApplySequenceConstructor: %s was not compiled\n", 02581 cur->name); 02582 } 02583 ctxt->insert = oldInsert; 02584 } 02585 goto skip_children; 02586 } 02587 02588 if (info->func != NULL) { 02589 oldCurInst = ctxt->inst; 02590 ctxt->inst = cur; 02591 ctxt->insert = insert; 02592 oldLocalFragmentBase = ctxt->localRVTBase; 02593 ctxt->localRVTBase = NULL; 02594 02595 info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); 02596 02597 ctxt->localRVTBase = oldLocalFragmentBase; 02598 /* 02599 * Cleanup temporary tree fragments. 02600 */ 02601 if (oldLocalFragmentTop != ctxt->localRVT) 02602 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 02603 02604 ctxt->insert = oldInsert; 02605 ctxt->inst = oldCurInst; 02606 goto skip_children; 02607 } 02608 02609 if (IS_XSLT_NAME(cur, "variable")) { 02610 xsltStackElemPtr tmpvar = ctxt->vars; 02611 02612 oldCurInst = ctxt->inst; 02613 ctxt->inst = cur; 02614 02615 xsltParseStylesheetVariable(ctxt, cur); 02616 02617 ctxt->inst = oldCurInst; 02618 02619 if (tmpvar != ctxt->vars) { 02620 /* 02621 * TODO: Using a @tmpvar is an annoying workaround, but 02622 * the current mechanisms do not provide any other way 02623 * of knowing if the var was really pushed onto the 02624 * stack. 02625 */ 02626 ctxt->vars->level = level; 02627 } 02628 } else if (IS_XSLT_NAME(cur, "message")) { 02629 xsltMessage(ctxt, contextNode, cur); 02630 } else { 02631 xsltTransformError(ctxt, NULL, cur, 02632 "Unexpected XSLT element '%s'.\n", cur->name); 02633 } 02634 goto skip_children; 02635 } else if ((cur->type == XML_TEXT_NODE) || 02636 (cur->type == XML_CDATA_SECTION_NODE)) { 02637 02638 /* 02639 * This text comes from the stylesheet 02640 * For stylesheets, the set of whitespace-preserving 02641 * element names consists of just xsl:text. 02642 */ 02643 #ifdef WITH_XSLT_DEBUG_PROCESS 02644 if (cur->type == XML_CDATA_SECTION_NODE) { 02645 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02646 "xsltApplySequenceConstructor: copy CDATA text %s\n", 02647 cur->content)); 02648 } else if (cur->name == xmlStringTextNoenc) { 02649 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02650 "xsltApplySequenceConstructor: copy unescaped text %s\n", 02651 cur->content)); 02652 } else { 02653 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02654 "xsltApplySequenceConstructor: copy text %s\n", 02655 cur->content)); 02656 } 02657 #endif 02658 if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) 02659 goto error; 02660 } else if ((cur->type == XML_ELEMENT_NODE) && 02661 (cur->ns != NULL) && (cur->psvi != NULL)) { 02662 xsltTransformFunction function; 02663 02664 oldCurInst = ctxt->inst; 02665 ctxt->inst = cur; 02666 /* 02667 * Flagged as an extension element 02668 */ 02669 if (cur->psvi == xsltExtMarker) 02670 function = (xsltTransformFunction) 02671 xsltExtElementLookup(ctxt, cur->name, cur->ns->href); 02672 else 02673 function = ((xsltElemPreCompPtr) cur->psvi)->func; 02674 02675 if (function == NULL) { 02676 xmlNodePtr child; 02677 int found = 0; 02678 02679 #ifdef WITH_XSLT_DEBUG_PROCESS 02680 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02681 "xsltApplySequenceConstructor: unknown extension %s\n", 02682 cur->name)); 02683 #endif 02684 /* 02685 * Search if there are fallbacks 02686 */ 02687 child = cur->children; 02688 while (child != NULL) { 02689 if ((IS_XSLT_ELEM(child)) && 02690 (IS_XSLT_NAME(child, "fallback"))) 02691 { 02692 found = 1; 02693 xsltApplySequenceConstructor(ctxt, contextNode, 02694 child->children, NULL); 02695 } 02696 child = child->next; 02697 } 02698 02699 if (!found) { 02700 xsltTransformError(ctxt, NULL, cur, 02701 "xsltApplySequenceConstructor: failed to find extension %s\n", 02702 cur->name); 02703 } 02704 } else { 02705 #ifdef WITH_XSLT_DEBUG_PROCESS 02706 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02707 "xsltApplySequenceConstructor: extension construct %s\n", 02708 cur->name)); 02709 #endif 02710 02711 ctxt->insert = insert; 02712 /* 02713 * We need the fragment base for extension instructions 02714 * which return values (like EXSLT's function). 02715 */ 02716 oldLocalFragmentBase = ctxt->localRVTBase; 02717 ctxt->localRVTBase = NULL; 02718 02719 function(ctxt, contextNode, cur, cur->psvi); 02720 /* 02721 * Cleanup temporary tree fragments. 02722 */ 02723 if (oldLocalFragmentTop != ctxt->localRVT) 02724 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 02725 02726 ctxt->localRVTBase = oldLocalFragmentBase; 02727 ctxt->insert = oldInsert; 02728 02729 } 02730 ctxt->inst = oldCurInst; 02731 goto skip_children; 02732 } else if (cur->type == XML_ELEMENT_NODE) { 02733 #ifdef WITH_XSLT_DEBUG_PROCESS 02734 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02735 "xsltApplySequenceConstructor: copy node %s\n", 02736 cur->name)); 02737 #endif 02738 oldCurInst = ctxt->inst; 02739 ctxt->inst = cur; 02740 02741 if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL) 02742 goto error; 02743 /* 02744 * Add extra namespaces inherited from the current template 02745 * if we are in the first level children and this is a 02746 * "real" template. 02747 */ 02748 if ((templ != NULL) && (oldInsert == insert) && 02749 (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) { 02750 int i; 02751 xmlNsPtr ns, ret; 02752 02753 for (i = 0; i < ctxt->templ->inheritedNsNr; i++) { 02754 const xmlChar *URI = NULL; 02755 xsltStylesheetPtr style; 02756 ns = ctxt->templ->inheritedNs[i]; 02757 02758 /* Note that the XSLT namespace was already excluded 02759 * in xsltGetInheritedNsList(). 02760 */ 02761 #if 0 02762 if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) 02763 continue; 02764 #endif 02765 style = ctxt->style; 02766 while (style != NULL) { 02767 if (style->nsAliases != NULL) 02768 URI = (const xmlChar *) 02769 xmlHashLookup(style->nsAliases, ns->href); 02770 if (URI != NULL) 02771 break; 02772 02773 style = xsltNextImport(style); 02774 } 02775 if (URI == UNDEFINED_DEFAULT_NS) 02776 continue; 02777 if (URI == NULL) 02778 URI = ns->href; 02779 /* 02780 * TODO: The following will still be buggy for the 02781 * non-refactored code. 02782 */ 02783 ret = xmlSearchNs(copy->doc, copy, ns->prefix); 02784 if ((ret == NULL) || (!xmlStrEqual(ret->href, URI))) 02785 { 02786 xmlNewNs(copy, URI, ns->prefix); 02787 } 02788 } 02789 if (copy->ns != NULL) { 02790 /* 02791 * Fix the node namespace if needed 02792 */ 02793 copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy); 02794 } 02795 } 02796 /* 02797 * all the attributes are directly inherited 02798 */ 02799 if (cur->properties != NULL) { 02800 xsltAttrListTemplateProcess(ctxt, copy, cur->properties); 02801 } 02802 ctxt->inst = oldCurInst; 02803 } 02804 #endif /* else of XSLT_REFACTORED */ 02805 02806 /* 02807 * Descend into content in document order. 02808 */ 02809 if (cur->children != NULL) { 02810 if (cur->children->type != XML_ENTITY_DECL) { 02811 cur = cur->children; 02812 level++; 02813 if (copy != NULL) 02814 insert = copy; 02815 continue; 02816 } 02817 } 02818 02819 skip_children: 02820 /* 02821 * If xslt:message was just processed, we might have hit a 02822 * terminate='yes'; if so, then break the loop and clean up. 02823 * TODO: Do we need to check this also before trying to descend 02824 * into the content? 02825 */ 02826 if (ctxt->state == XSLT_STATE_STOPPED) 02827 break; 02828 if (cur->next != NULL) { 02829 cur = cur->next; 02830 continue; 02831 } 02832 02833 do { 02834 cur = cur->parent; 02835 level--; 02836 /* 02837 * Pop variables/params (xsl:variable and xsl:param). 02838 */ 02839 if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) { 02840 xsltLocalVariablePop(ctxt, oldVarsNr, level); 02841 } 02842 02843 insert = insert->parent; 02844 if (cur == NULL) 02845 break; 02846 if (cur == list->parent) { 02847 cur = NULL; 02848 break; 02849 } 02850 if (cur->next != NULL) { 02851 cur = cur->next; 02852 break; 02853 } 02854 } while (cur != NULL); 02855 } 02856 02857 error: 02858 /* 02859 * In case of errors: pop remaining variables. 02860 */ 02861 if (ctxt->varsNr > oldVarsNr) 02862 xsltLocalVariablePop(ctxt, oldVarsNr, -1); 02863 02864 ctxt->node = oldContextNode; 02865 ctxt->inst = oldInst; 02866 ctxt->insert = oldInsert; 02867 02868 #ifdef WITH_DEBUGGER 02869 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { 02870 xslDropCall(); 02871 } 02872 #endif 02873 } 02874 02875 /* 02876 * xsltApplyXSLTTemplate: 02877 * @ctxt: a XSLT transformation context 02878 * @contextNode: the node in the source tree. 02879 * @list: the nodes of a sequence constructor; 02880 * (plus leading xsl:param elements) 02881 * @templ: the compiled xsl:template declaration; 02882 * NULL if a sequence constructor 02883 * @withParams: a set of caller-parameters (xsl:with-param) or NULL 02884 * 02885 * Called by: 02886 * - xsltApplyImports() 02887 * - xsltCallTemplate() 02888 * - xsltDefaultProcessOneNode() 02889 * - xsltProcessOneNode() 02890 */ 02891 static void 02892 xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, 02893 xmlNodePtr contextNode, 02894 xmlNodePtr list, 02895 xsltTemplatePtr templ, 02896 xsltStackElemPtr withParams) 02897 { 02898 int oldVarsBase = 0; 02899 long start = 0; 02900 xmlNodePtr cur; 02901 xsltStackElemPtr tmpParam = NULL; 02902 xmlDocPtr oldUserFragmentTop, oldLocalFragmentTop; 02903 02904 #ifdef XSLT_REFACTORED 02905 xsltStyleItemParamPtr iparam; 02906 #else 02907 xsltStylePreCompPtr iparam; 02908 #endif 02909 02910 #ifdef WITH_DEBUGGER 02911 int addCallResult = 0; 02912 #endif 02913 02914 if (ctxt == NULL) 02915 return; 02916 if (templ == NULL) { 02917 xsltTransformError(ctxt, NULL, list, 02918 "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n"); 02919 return; 02920 } 02921 02922 #ifdef WITH_DEBUGGER 02923 if (ctxt->debugStatus != XSLT_DEBUG_NONE) { 02924 if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode, 02925 list, templ, &addCallResult) == NULL) 02926 return; 02927 } 02928 #endif 02929 02930 if (list == NULL) 02931 return; 02932 CHECK_STOPPED; 02933 02934 /* 02935 * Check for infinite recursion: stop if the maximum of nested templates 02936 * is excceeded. Adjust xsltMaxDepth if you need more. 02937 */ 02938 if (((ctxt->templNr >= xsltMaxDepth) || 02939 (ctxt->varsNr >= 5 * xsltMaxDepth))) 02940 { 02941 xsltTransformError(ctxt, NULL, list, 02942 "xsltApplyXSLTTemplate: A potential infinite template recursion " 02943 "was detected.\n" 02944 "You can adjust xsltMaxDepth (--maxdepth) in order to " 02945 "raise the maximum number of nested template calls and " 02946 "variables/params (currently set to %d).\n", 02947 xsltMaxDepth); 02948 xsltDebug(ctxt, contextNode, list, NULL); 02949 return; 02950 } 02951 02952 oldUserFragmentTop = ctxt->tmpRVT; 02953 ctxt->tmpRVT = NULL; 02954 oldLocalFragmentTop = ctxt->localRVT; 02955 02956 /* 02957 * Initiate a distinct scope of local params/variables. 02958 */ 02959 oldVarsBase = ctxt->varsBase; 02960 ctxt->varsBase = ctxt->varsNr; 02961 02962 ctxt->node = contextNode; 02963 if (ctxt->profile) { 02964 templ->nbCalls++; 02965 start = xsltTimestamp(); 02966 profPush(ctxt, 0); 02967 } 02968 /* 02969 * Push the xsl:template declaration onto the stack. 02970 */ 02971 templPush(ctxt, templ); 02972 02973 #ifdef WITH_XSLT_DEBUG_PROCESS 02974 if (templ->name != NULL) 02975 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 02976 "applying xsl:template '%s'\n", templ->name)); 02977 #endif 02978 /* 02979 * Process xsl:param instructions and skip those elements for 02980 * further processing. 02981 */ 02982 cur = list; 02983 do { 02984 if (cur->type == XML_TEXT_NODE) { 02985 cur = cur->next; 02986 continue; 02987 } 02988 if ((cur->type != XML_ELEMENT_NODE) || 02989 (cur->name[0] != 'p') || 02990 (cur->psvi == NULL) || 02991 (! xmlStrEqual(cur->name, BAD_CAST "param")) || 02992 (! IS_XSLT_ELEM(cur))) 02993 { 02994 break; 02995 } 02996 02997 list = cur->next; 02998 02999 #ifdef XSLT_REFACTORED 03000 iparam = (xsltStyleItemParamPtr) cur->psvi; 03001 #else 03002 iparam = (xsltStylePreCompPtr) cur->psvi; 03003 #endif 03004 03005 /* 03006 * Substitute xsl:param for a given xsl:with-param. 03007 * Since the XPath expression will reference the params/vars 03008 * by index, we need to slot the xsl:with-params in the 03009 * order of encountered xsl:params to keep the sequence of 03010 * params/variables in the stack exactly as it was at 03011 * compile time, 03012 */ 03013 tmpParam = NULL; 03014 if (withParams) { 03015 tmpParam = withParams; 03016 do { 03017 if ((tmpParam->name == (iparam->name)) && 03018 (tmpParam->nameURI == (iparam->ns))) 03019 { 03020 /* 03021 * Push the caller-parameter. 03022 */ 03023 xsltLocalVariablePush(ctxt, tmpParam, -1); 03024 break; 03025 } 03026 tmpParam = tmpParam->next; 03027 } while (tmpParam != NULL); 03028 } 03029 /* 03030 * Push the xsl:param. 03031 */ 03032 if (tmpParam == NULL) { 03033 /* 03034 * Note that we must assume that the added parameter 03035 * has a @depth of 0. 03036 */ 03037 xsltParseStylesheetParam(ctxt, cur); 03038 } 03039 cur = cur->next; 03040 } while (cur != NULL); 03041 /* 03042 * Process the sequence constructor. 03043 */ 03044 xsltApplySequenceConstructor(ctxt, contextNode, list, templ); 03045 03046 /* 03047 * Remove remaining xsl:param and xsl:with-param items from 03048 * the stack. Don't free xsl:with-param items. 03049 */ 03050 if (ctxt->varsNr > ctxt->varsBase) 03051 xsltTemplateParamsCleanup(ctxt); 03052 ctxt->varsBase = oldVarsBase; 03053 03054 /* 03055 * Clean up remaining local tree fragments. 03056 * This also frees fragments which are the result of 03057 * extension instructions. Should normally not be hit; but 03058 * just for the case xsltExtensionInstructionResultFinalize() 03059 * was not called by the extension author. 03060 */ 03061 if (oldLocalFragmentTop != ctxt->localRVT) { 03062 xmlDocPtr curdoc = ctxt->localRVT, tmp; 03063 03064 do { 03065 tmp = curdoc; 03066 curdoc = (xmlDocPtr) curdoc->next; 03067 /* Need to housekeep localRVTBase */ 03068 if (tmp == ctxt->localRVTBase) 03069 ctxt->localRVTBase = curdoc; 03070 if (tmp->prev) 03071 tmp->prev->next = (xmlNodePtr) curdoc; 03072 if (curdoc) 03073 curdoc->prev = tmp->prev; 03074 xsltReleaseRVT(ctxt, tmp); 03075 } while (curdoc != oldLocalFragmentTop); 03076 } 03077 ctxt->localRVT = oldLocalFragmentTop; 03078 03079 /* 03080 * Release user-created fragments stored in the scope 03081 * of xsl:template. Note that this mechanism is deprecated: 03082 * user code should now use xsltRegisterLocalRVT() instead 03083 * of the obsolete xsltRegisterTmpRVT(). 03084 */ 03085 if (ctxt->tmpRVT) { 03086 xmlDocPtr curdoc = ctxt->tmpRVT, tmp; 03087 03088 while (curdoc != NULL) { 03089 tmp = curdoc; 03090 curdoc = (xmlDocPtr) curdoc->next; 03091 xsltReleaseRVT(ctxt, tmp); 03092 } 03093 } 03094 ctxt->tmpRVT = oldUserFragmentTop; 03095 03096 /* 03097 * Pop the xsl:template declaration from the stack. 03098 */ 03099 templPop(ctxt); 03100 if (ctxt->profile) { 03101 long spent, child, total, end; 03102 03103 end = xsltTimestamp(); 03104 child = profPop(ctxt); 03105 total = end - start; 03106 spent = total - child; 03107 if (spent <= 0) { 03108 /* 03109 * Not possible unless the original calibration failed 03110 * we can try to correct it on the fly. 03111 */ 03112 xsltCalibrateAdjust(spent); 03113 spent = 0; 03114 } 03115 03116 templ->time += spent; 03117 if (ctxt->profNr > 0) 03118 ctxt->profTab[ctxt->profNr - 1] += total; 03119 } 03120 03121 #ifdef WITH_DEBUGGER 03122 if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { 03123 xslDropCall(); 03124 } 03125 #endif 03126 } 03127 03128 03159 void 03160 xsltApplyOneTemplate(xsltTransformContextPtr ctxt, 03161 xmlNodePtr contextNode, 03162 xmlNodePtr list, 03163 xsltTemplatePtr templ ATTRIBUTE_UNUSED, 03164 xsltStackElemPtr params) 03165 { 03166 if ((ctxt == NULL) || (list == NULL)) 03167 return; 03168 CHECK_STOPPED; 03169 03170 if (params) { 03171 /* 03172 * This code should be obsolete - was previously used 03173 * by libexslt/functions.c, but due to bug 381319 the 03174 * logic there was changed. 03175 */ 03176 int oldVarsNr = ctxt->varsNr; 03177 03178 /* 03179 * Push the given xsl:param(s) onto the variable stack. 03180 */ 03181 while (params != NULL) { 03182 xsltLocalVariablePush(ctxt, params, -1); 03183 params = params->next; 03184 } 03185 xsltApplySequenceConstructor(ctxt, contextNode, list, templ); 03186 /* 03187 * Pop the given xsl:param(s) from the stack but don't free them. 03188 */ 03189 xsltLocalVariablePop(ctxt, oldVarsNr, -2); 03190 } else 03191 xsltApplySequenceConstructor(ctxt, contextNode, list, templ); 03192 } 03193 03194 /************************************************************************ 03195 * * 03196 * XSLT-1.1 extensions * 03197 * * 03198 ************************************************************************/ 03199 03209 void 03210 xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, 03211 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 03212 { 03213 #ifdef XSLT_REFACTORED 03214 xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp; 03215 #else 03216 xsltStylePreCompPtr comp = castedComp; 03217 #endif 03218 xsltStylesheetPtr style = NULL; 03219 int ret; 03220 xmlChar *filename = NULL, *prop, *elements; 03221 xmlChar *element, *end; 03222 xmlDocPtr res = NULL; 03223 xmlDocPtr oldOutput; 03224 xmlNodePtr oldInsert, root; 03225 const char *oldOutputFile; 03226 xsltOutputType oldType; 03227 xmlChar *URL = NULL; 03228 const xmlChar *method; 03229 const xmlChar *doctypePublic; 03230 const xmlChar *doctypeSystem; 03231 const xmlChar *version; 03232 const xmlChar *encoding; 03233 03234 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) 03235 return; 03236 03237 if (comp->filename == NULL) { 03238 03239 if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { 03240 /* 03241 * The element "output" is in the namespace XSLT_SAXON_NAMESPACE 03242 * (http://icl.com/saxon) 03243 * The @file is in no namespace. 03244 */ 03245 #ifdef WITH_XSLT_DEBUG_EXTRA 03246 xsltGenericDebug(xsltGenericDebugContext, 03247 "Found saxon:output extension\n"); 03248 #endif 03249 URL = xsltEvalAttrValueTemplate(ctxt, inst, 03250 (const xmlChar *) "file", 03251 XSLT_SAXON_NAMESPACE); 03252 03253 if (URL == NULL) 03254 URL = xsltEvalAttrValueTemplate(ctxt, inst, 03255 (const xmlChar *) "href", 03256 XSLT_SAXON_NAMESPACE); 03257 } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { 03258 #ifdef WITH_XSLT_DEBUG_EXTRA 03259 xsltGenericDebug(xsltGenericDebugContext, 03260 "Found xalan:write extension\n"); 03261 #endif 03262 URL = xsltEvalAttrValueTemplate(ctxt, inst, 03263 (const xmlChar *) 03264 "select", 03265 XSLT_XALAN_NAMESPACE); 03266 if (URL != NULL) { 03267 xmlXPathCompExprPtr cmp; 03268 xmlChar *val; 03269 03270 /* 03271 * Trying to handle bug #59212 03272 * The value of the "select" attribute is an 03273 * XPath expression. 03274 * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect) 03275 */ 03276 cmp = xmlXPathCompile(URL); 03277 val = xsltEvalXPathString(ctxt, cmp); 03278 xmlXPathFreeCompExpr(cmp); 03279 xmlFree(URL); 03280 URL = val; 03281 } 03282 if (URL == NULL) 03283 URL = xsltEvalAttrValueTemplate(ctxt, inst, 03284 (const xmlChar *) 03285 "file", 03286 XSLT_XALAN_NAMESPACE); 03287 if (URL == NULL) 03288 URL = xsltEvalAttrValueTemplate(ctxt, inst, 03289 (const xmlChar *) 03290 "href", 03291 XSLT_XALAN_NAMESPACE); 03292 } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { 03293 URL = xsltEvalAttrValueTemplate(ctxt, inst, 03294 (const xmlChar *) "href", 03295 NULL); 03296 } 03297 03298 } else { 03299 URL = xmlStrdup(comp->filename); 03300 } 03301 03302 if (URL == NULL) { 03303 xsltTransformError(ctxt, NULL, inst, 03304 "xsltDocumentElem: href/URI-Reference not found\n"); 03305 return; 03306 } 03307 03308 /* 03309 * If the computation failed, it's likely that the URL wasn't escaped 03310 */ 03311 filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile); 03312 if (filename == NULL) { 03313 xmlChar *escURL; 03314 03315 escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,"); 03316 if (escURL != NULL) { 03317 filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile); 03318 xmlFree(escURL); 03319 } 03320 } 03321 03322 if (filename == NULL) { 03323 xsltTransformError(ctxt, NULL, inst, 03324 "xsltDocumentElem: URL computation failed for %s\n", 03325 URL); 03326 xmlFree(URL); 03327 return; 03328 } 03329 03330 /* 03331 * Security checking: can we write to this resource 03332 */ 03333 if (ctxt->sec != NULL) { 03334 ret = xsltCheckWrite(ctxt->sec, ctxt, filename); 03335 if (ret == 0) { 03336 xsltTransformError(ctxt, NULL, inst, 03337 "xsltDocumentElem: write rights for %s denied\n", 03338 filename); 03339 xmlFree(URL); 03340 xmlFree(filename); 03341 return; 03342 } 03343 } 03344 03345 oldOutputFile = ctxt->outputFile; 03346 oldOutput = ctxt->output; 03347 oldInsert = ctxt->insert; 03348 oldType = ctxt->type; 03349 ctxt->outputFile = (const char *) filename; 03350 03351 style = xsltNewStylesheet(); 03352 if (style == NULL) { 03353 xsltTransformError(ctxt, NULL, inst, 03354 "xsltDocumentElem: out of memory\n"); 03355 goto error; 03356 } 03357 03358 /* 03359 * Version described in 1.1 draft allows full parameterization 03360 * of the output. 03361 */ 03362 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03363 (const xmlChar *) "version", 03364 NULL); 03365 if (prop != NULL) { 03366 if (style->version != NULL) 03367 xmlFree(style->version); 03368 style->version = prop; 03369 } 03370 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03371 (const xmlChar *) "encoding", 03372 NULL); 03373 if (prop != NULL) { 03374 if (style->encoding != NULL) 03375 xmlFree(style->encoding); 03376 style->encoding = prop; 03377 } 03378 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03379 (const xmlChar *) "method", 03380 NULL); 03381 if (prop != NULL) { 03382 const xmlChar *URI; 03383 03384 if (style->method != NULL) 03385 xmlFree(style->method); 03386 style->method = NULL; 03387 if (style->methodURI != NULL) 03388 xmlFree(style->methodURI); 03389 style->methodURI = NULL; 03390 03391 URI = xsltGetQNameURI(inst, &prop); 03392 if (prop == NULL) { 03393 if (style != NULL) style->errors++; 03394 } else if (URI == NULL) { 03395 if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || 03396 (xmlStrEqual(prop, (const xmlChar *) "html")) || 03397 (xmlStrEqual(prop, (const xmlChar *) "text"))) { 03398 style->method = prop; 03399 } else { 03400 xsltTransformError(ctxt, NULL, inst, 03401 "invalid value for method: %s\n", prop); 03402 if (style != NULL) style->warnings++; 03403 } 03404 } else { 03405 style->method = prop; 03406 style->methodURI = xmlStrdup(URI); 03407 } 03408 } 03409 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03410 (const xmlChar *) 03411 "doctype-system", NULL); 03412 if (prop != NULL) { 03413 if (style->doctypeSystem != NULL) 03414 xmlFree(style->doctypeSystem); 03415 style->doctypeSystem = prop; 03416 } 03417 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03418 (const xmlChar *) 03419 "doctype-public", NULL); 03420 if (prop != NULL) { 03421 if (style->doctypePublic != NULL) 03422 xmlFree(style->doctypePublic); 03423 style->doctypePublic = prop; 03424 } 03425 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03426 (const xmlChar *) "standalone", 03427 NULL); 03428 if (prop != NULL) { 03429 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 03430 style->standalone = 1; 03431 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 03432 style->standalone = 0; 03433 } else { 03434 xsltTransformError(ctxt, NULL, inst, 03435 "invalid value for standalone: %s\n", 03436 prop); 03437 if (style != NULL) style->warnings++; 03438 } 03439 xmlFree(prop); 03440 } 03441 03442 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03443 (const xmlChar *) "indent", 03444 NULL); 03445 if (prop != NULL) { 03446 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 03447 style->indent = 1; 03448 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 03449 style->indent = 0; 03450 } else { 03451 xsltTransformError(ctxt, NULL, inst, 03452 "invalid value for indent: %s\n", prop); 03453 if (style != NULL) style->warnings++; 03454 } 03455 xmlFree(prop); 03456 } 03457 03458 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03459 (const xmlChar *) 03460 "omit-xml-declaration", 03461 NULL); 03462 if (prop != NULL) { 03463 if (xmlStrEqual(prop, (const xmlChar *) "yes")) { 03464 style->omitXmlDeclaration = 1; 03465 } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { 03466 style->omitXmlDeclaration = 0; 03467 } else { 03468 xsltTransformError(ctxt, NULL, inst, 03469 "invalid value for omit-xml-declaration: %s\n", 03470 prop); 03471 if (style != NULL) style->warnings++; 03472 } 03473 xmlFree(prop); 03474 } 03475 03476 elements = xsltEvalAttrValueTemplate(ctxt, inst, 03477 (const xmlChar *) 03478 "cdata-section-elements", 03479 NULL); 03480 if (elements != NULL) { 03481 if (style->stripSpaces == NULL) 03482 style->stripSpaces = xmlHashCreate(10); 03483 if (style->stripSpaces == NULL) 03484 return; 03485 03486 element = elements; 03487 while (*element != 0) { 03488 while (IS_BLANK_CH(*element)) 03489 element++; 03490 if (*element == 0) 03491 break; 03492 end = element; 03493 while ((*end != 0) && (!IS_BLANK_CH(*end))) 03494 end++; 03495 element = xmlStrndup(element, end - element); 03496 if (element) { 03497 const xmlChar *URI; 03498 03499 #ifdef WITH_XSLT_DEBUG_PARSING 03500 xsltGenericDebug(xsltGenericDebugContext, 03501 "add cdata section output element %s\n", 03502 element); 03503 #endif 03504 URI = xsltGetQNameURI(inst, &element); 03505 03506 xmlHashAddEntry2(style->stripSpaces, element, URI, 03507 (xmlChar *) "cdata"); 03508 xmlFree(element); 03509 } 03510 element = end; 03511 } 03512 xmlFree(elements); 03513 } 03514 03515 /* 03516 * Create a new document tree and process the element template 03517 */ 03518 XSLT_GET_IMPORT_PTR(method, style, method) 03519 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 03520 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 03521 XSLT_GET_IMPORT_PTR(version, style, version) 03522 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 03523 03524 if ((method != NULL) && 03525 (!xmlStrEqual(method, (const xmlChar *) "xml"))) { 03526 if (xmlStrEqual(method, (const xmlChar *) "html")) { 03527 ctxt->type = XSLT_OUTPUT_HTML; 03528 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 03529 res = htmlNewDoc(doctypeSystem, doctypePublic); 03530 else { 03531 if (version != NULL) { 03532 #ifdef XSLT_GENERATE_HTML_DOCTYPE 03533 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); 03534 #endif 03535 } 03536 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); 03537 } 03538 if (res == NULL) 03539 goto error; 03540 res->dict = ctxt->dict; 03541 xmlDictReference(res->dict); 03542 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { 03543 xsltTransformError(ctxt, NULL, inst, 03544 "xsltDocumentElem: unsupported method xhtml\n", 03545 style->method); 03546 ctxt->type = XSLT_OUTPUT_HTML; 03547 res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); 03548 if (res == NULL) 03549 goto error; 03550 res->dict = ctxt->dict; 03551 xmlDictReference(res->dict); 03552 } else if (xmlStrEqual(method, (const xmlChar *) "text")) { 03553 ctxt->type = XSLT_OUTPUT_TEXT; 03554 res = xmlNewDoc(style->version); 03555 if (res == NULL) 03556 goto error; 03557 res->dict = ctxt->dict; 03558 xmlDictReference(res->dict); 03559 #ifdef WITH_XSLT_DEBUG 03560 xsltGenericDebug(xsltGenericDebugContext, 03561 "reusing transformation dict for output\n"); 03562 #endif 03563 } else { 03564 xsltTransformError(ctxt, NULL, inst, 03565 "xsltDocumentElem: unsupported method %s\n", 03566 style->method); 03567 goto error; 03568 } 03569 } else { 03570 ctxt->type = XSLT_OUTPUT_XML; 03571 res = xmlNewDoc(style->version); 03572 if (res == NULL) 03573 goto error; 03574 res->dict = ctxt->dict; 03575 xmlDictReference(res->dict); 03576 #ifdef WITH_XSLT_DEBUG 03577 xsltGenericDebug(xsltGenericDebugContext, 03578 "reusing transformation dict for output\n"); 03579 #endif 03580 } 03581 res->charset = XML_CHAR_ENCODING_UTF8; 03582 if (encoding != NULL) 03583 res->encoding = xmlStrdup(encoding); 03584 ctxt->output = res; 03585 ctxt->insert = (xmlNodePtr) res; 03586 xsltApplySequenceConstructor(ctxt, node, inst->children, NULL); 03587 03588 /* 03589 * Do some post processing work depending on the generated output 03590 */ 03591 root = xmlDocGetRootElement(res); 03592 if (root != NULL) { 03593 const xmlChar *doctype = NULL; 03594 03595 if ((root->ns != NULL) && (root->ns->prefix != NULL)) 03596 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); 03597 if (doctype == NULL) 03598 doctype = root->name; 03599 03600 /* 03601 * Apply the default selection of the method 03602 */ 03603 if ((method == NULL) && 03604 (root->ns == NULL) && 03605 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { 03606 xmlNodePtr tmp; 03607 03608 tmp = res->children; 03609 while ((tmp != NULL) && (tmp != root)) { 03610 if (tmp->type == XML_ELEMENT_NODE) 03611 break; 03612 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) 03613 break; 03614 tmp = tmp->next; 03615 } 03616 if (tmp == root) { 03617 ctxt->type = XSLT_OUTPUT_HTML; 03618 res->type = XML_HTML_DOCUMENT_NODE; 03619 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 03620 res->intSubset = xmlCreateIntSubset(res, doctype, 03621 doctypePublic, 03622 doctypeSystem); 03623 #ifdef XSLT_GENERATE_HTML_DOCTYPE 03624 } else if (version != NULL) { 03625 xsltGetHTMLIDs(version, &doctypePublic, 03626 &doctypeSystem); 03627 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 03628 res->intSubset = 03629 xmlCreateIntSubset(res, doctype, 03630 doctypePublic, 03631 doctypeSystem); 03632 #endif 03633 } 03634 } 03635 03636 } 03637 if (ctxt->type == XSLT_OUTPUT_XML) { 03638 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 03639 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 03640 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 03641 res->intSubset = xmlCreateIntSubset(res, doctype, 03642 doctypePublic, 03643 doctypeSystem); 03644 } 03645 } 03646 03647 /* 03648 * Save the result 03649 */ 03650 ret = xsltSaveResultToFilename((const char *) filename, 03651 res, style, 0); 03652 if (ret < 0) { 03653 xsltTransformError(ctxt, NULL, inst, 03654 "xsltDocumentElem: unable to save to %s\n", 03655 filename); 03656 ctxt->state = XSLT_STATE_ERROR; 03657 #ifdef WITH_XSLT_DEBUG_EXTRA 03658 } else { 03659 xsltGenericDebug(xsltGenericDebugContext, 03660 "Wrote %d bytes to %s\n", ret, filename); 03661 #endif 03662 } 03663 03664 error: 03665 ctxt->output = oldOutput; 03666 ctxt->insert = oldInsert; 03667 ctxt->type = oldType; 03668 ctxt->outputFile = oldOutputFile; 03669 if (URL != NULL) 03670 xmlFree(URL); 03671 if (filename != NULL) 03672 xmlFree(filename); 03673 if (style != NULL) 03674 xsltFreeStylesheet(style); 03675 if (res != NULL) 03676 xmlFreeDoc(res); 03677 } 03678 03679 /************************************************************************ 03680 * * 03681 * Most of the XSLT-1.0 transformations * 03682 * * 03683 ************************************************************************/ 03684 03695 void 03696 xsltSort(xsltTransformContextPtr ctxt, 03697 xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, 03698 xsltStylePreCompPtr comp) { 03699 if (comp == NULL) { 03700 xsltTransformError(ctxt, NULL, inst, 03701 "xsl:sort : compilation failed\n"); 03702 return; 03703 } 03704 xsltTransformError(ctxt, NULL, inst, 03705 "xsl:sort : improper use this should not be reached\n"); 03706 } 03707 03717 void 03718 xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node, 03719 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 03720 { 03721 #ifdef XSLT_REFACTORED 03722 xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp; 03723 #else 03724 xsltStylePreCompPtr comp = castedComp; 03725 #endif 03726 xmlNodePtr copy, oldInsert; 03727 03728 oldInsert = ctxt->insert; 03729 if (ctxt->insert != NULL) { 03730 switch (node->type) { 03731 case XML_TEXT_NODE: 03732 case XML_CDATA_SECTION_NODE: 03733 /* 03734 * This text comes from the stylesheet 03735 * For stylesheets, the set of whitespace-preserving 03736 * element names consists of just xsl:text. 03737 */ 03738 #ifdef WITH_XSLT_DEBUG_PROCESS 03739 if (node->type == XML_CDATA_SECTION_NODE) { 03740 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 03741 "xsltCopy: CDATA text %s\n", node->content)); 03742 } else { 03743 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 03744 "xsltCopy: text %s\n", node->content)); 03745 } 03746 #endif 03747 xsltCopyText(ctxt, ctxt->insert, node, 0); 03748 break; 03749 case XML_DOCUMENT_NODE: 03750 case XML_HTML_DOCUMENT_NODE: 03751 break; 03752 case XML_ELEMENT_NODE: 03753 /* 03754 * REVISIT NOTE: The "fake" is a doc-node, not an element node. 03755 * REMOVED: 03756 * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt")) 03757 * return; 03758 */ 03759 03760 #ifdef WITH_XSLT_DEBUG_PROCESS 03761 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 03762 "xsltCopy: node %s\n", node->name)); 03763 #endif 03764 copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0); 03765 ctxt->insert = copy; 03766 if (comp->use != NULL) { 03767 xsltApplyAttributeSet(ctxt, node, inst, comp->use); 03768 } 03769 break; 03770 case XML_ATTRIBUTE_NODE: { 03771 #ifdef WITH_XSLT_DEBUG_PROCESS 03772 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 03773 "xsltCopy: attribute %s\n", node->name)); 03774 #endif 03775 /* 03776 * REVISIT: We could also raise an error if the parent is not 03777 * an element node. 03778 * OPTIMIZE TODO: Can we set the value/children of the 03779 * attribute without an intermediate copy of the string value? 03780 */ 03781 xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node); 03782 break; 03783 } 03784 case XML_PI_NODE: 03785 #ifdef WITH_XSLT_DEBUG_PROCESS 03786 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 03787 "xsltCopy: PI %s\n", node->name)); 03788 #endif 03789 copy = xmlNewDocPI(ctxt->insert->doc, node->name, 03790 node->content); 03791 copy = xsltAddChild(ctxt->insert, copy); 03792 break; 03793 case XML_COMMENT_NODE: 03794 #ifdef WITH_XSLT_DEBUG_PROCESS 03795 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 03796 "xsltCopy: comment\n")); 03797 #endif 03798 copy = xmlNewComment(node->content); 03799 copy = xsltAddChild(ctxt->insert, copy); 03800 break; 03801 case XML_NAMESPACE_DECL: 03802 #ifdef WITH_XSLT_DEBUG_PROCESS 03803 XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, 03804 "xsltCopy: namespace declaration\n")); 03805 #endif 03806 xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node); 03807 break; 03808 default: 03809 break; 03810 03811 } 03812 } 03813 03814 switch (node->type) { 03815 case XML_DOCUMENT_NODE: 03816 case XML_HTML_DOCUMENT_NODE: 03817 case XML_ELEMENT_NODE: 03818 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, 03819 NULL); 03820 break; 03821 default: 03822 break; 03823 } 03824 ctxt->insert = oldInsert; 03825 } 03826 03836 void 03837 xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, 03838 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { 03839 if ((inst->children != NULL) && (comp != NULL)) { 03840 xmlNodePtr text = inst->children; 03841 xmlNodePtr copy; 03842 03843 while (text != NULL) { 03844 if ((text->type != XML_TEXT_NODE) && 03845 (text->type != XML_CDATA_SECTION_NODE)) { 03846 xsltTransformError(ctxt, NULL, inst, 03847 "xsl:text content problem\n"); 03848 break; 03849 } 03850 copy = xmlNewDocText(ctxt->output, text->content); 03851 if (text->type != XML_CDATA_SECTION_NODE) { 03852 #ifdef WITH_XSLT_DEBUG_PARSING 03853 xsltGenericDebug(xsltGenericDebugContext, 03854 "Disable escaping: %s\n", text->content); 03855 #endif 03856 copy->name = xmlStringTextNoenc; 03857 } 03858 copy = xsltAddChild(ctxt->insert, copy); 03859 text = text->next; 03860 } 03861 } 03862 } 03863 03873 void 03874 xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, 03875 xmlNodePtr inst, xsltStylePreCompPtr castedComp) { 03876 #ifdef XSLT_REFACTORED 03877 xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp; 03878 #else 03879 xsltStylePreCompPtr comp = castedComp; 03880 #endif 03881 xmlChar *prop = NULL; 03882 const xmlChar *name, *prefix = NULL, *nsName = NULL; 03883 xmlNodePtr copy; 03884 xmlNodePtr oldInsert; 03885 03886 if (ctxt->insert == NULL) 03887 return; 03888 03889 /* 03890 * A comp->has_name == 0 indicates that we need to skip this instruction, 03891 * since it was evaluated to be invalid already during compilation. 03892 */ 03893 if (!comp->has_name) 03894 return; 03895 03896 /* 03897 * stack and saves 03898 */ 03899 oldInsert = ctxt->insert; 03900 03901 if (comp->name == NULL) { 03902 /* TODO: fix attr acquisition wrt to the XSLT namespace */ 03903 prop = xsltEvalAttrValueTemplate(ctxt, inst, 03904 (const xmlChar *) "name", XSLT_NAMESPACE); 03905 if (prop == NULL) { 03906 xsltTransformError(ctxt, NULL, inst, 03907 "xsl:element: The attribute 'name' is missing.\n"); 03908 goto error; 03909 } 03910 if (xmlValidateQName(prop, 0)) { 03911 xsltTransformError(ctxt, NULL, inst, 03912 "xsl:element: The effective name '%s' is not a " 03913 "valid QName.\n", prop); 03914 /* we fall through to catch any further errors, if possible */ 03915 } 03916 name = xsltSplitQName(ctxt->dict, prop, &prefix); 03917 xmlFree(prop); 03918 if ((prefix != NULL) && 03919 (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3))) 03920 { 03921 /* 03922 * TODO: Should we really disallow an "xml" prefix? 03923 */ 03924 goto error; 03925 } 03926 } else { 03927 /* 03928 * The "name" value was static. 03929 */ 03930 #ifdef XSLT_REFACTORED 03931 prefix = comp->nsPrefix; 03932 name = comp->name; 03933 #else 03934 name = xsltSplitQName(ctxt->dict, comp->name, &prefix); 03935 #endif 03936 } 03937 03938 /* 03939 * Create the new element 03940 */ 03941 if (ctxt->output->dict == ctxt->dict) { 03942 copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL); 03943 } else { 03944 copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL); 03945 } 03946 if (copy == NULL) { 03947 xsltTransformError(ctxt, NULL, inst, 03948 "xsl:element : creation of %s failed\n", name); 03949 return; 03950 } 03951 copy = xsltAddChild(ctxt->insert, copy); 03952 03953 /* 03954 * Namespace 03955 * --------- 03956 */ 03957 if (comp->has_ns) { 03958 if (comp->ns != NULL) { 03959 /* 03960 * No AVT; just plain text for the namespace name. 03961 */ 03962 if (comp->ns[0] != 0) 03963 nsName = comp->ns; 03964 } else { 03965 xmlChar *tmpNsName; 03966 /* 03967 * Eval the AVT. 03968 */ 03969 /* TODO: check attr acquisition wrt to the XSLT namespace */ 03970 tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, 03971 (const xmlChar *) "namespace", XSLT_NAMESPACE); 03972 /* 03973 * SPEC XSLT 1.0: 03974 * "If the string is empty, then the expanded-name of the 03975 * attribute has a null namespace URI." 03976 */ 03977 if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) 03978 nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); 03979 xmlFree(tmpNsName); 03980 }; 03981 } else { 03982 xmlNsPtr ns; 03983 /* 03984 * SPEC XSLT 1.0: 03985 * "If the namespace attribute is not present, then the QName is 03986 * expanded into an expanded-name using the namespace declarations 03987 * in effect for the xsl:element element, including any default 03988 * namespace declaration. 03989 */ 03990 ns = xmlSearchNs(inst->doc, inst, prefix); 03991 if (ns == NULL) { 03992 /* 03993 * TODO: Check this in the compilation layer in case it's a 03994 * static value. 03995 */ 03996 if (prefix != NULL) { 03997 xsltTransformError(ctxt, NULL, inst, 03998 "xsl:element: The QName '%s:%s' has no " 03999 "namespace binding in scope in the stylesheet; " 04000 "this is an error, since the namespace was not " 04001 "specified by the instruction itself.\n", prefix, name); 04002 } 04003 } else 04004 nsName = ns->href; 04005 } 04006 /* 04007 * Find/create a matching ns-decl in the result tree. 04008 */ 04009 if (nsName != NULL) { 04010 copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, copy); 04011 } else if ((copy->parent != NULL) && 04012 (copy->parent->type == XML_ELEMENT_NODE) && 04013 (copy->parent->ns != NULL)) 04014 { 04015 /* 04016 * "Undeclare" the default namespace. 04017 */ 04018 xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy); 04019 } 04020 04021 ctxt->insert = copy; 04022 04023 if (comp->has_use) { 04024 if (comp->use != NULL) { 04025 xsltApplyAttributeSet(ctxt, node, inst, comp->use); 04026 } else { 04027 xmlChar *attrSets = NULL; 04028 /* 04029 * BUG TODO: use-attribute-sets is not a value template. 04030 * use-attribute-sets = qnames 04031 */ 04032 attrSets = xsltEvalAttrValueTemplate(ctxt, inst, 04033 (const xmlChar *)"use-attribute-sets", NULL); 04034 if (attrSets != NULL) { 04035 xsltApplyAttributeSet(ctxt, node, inst, attrSets); 04036 xmlFree(attrSets); 04037 } 04038 } 04039 } 04040 /* 04041 * Instantiate the sequence constructor. 04042 */ 04043 if (inst->children != NULL) 04044 xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, 04045 NULL); 04046 04047 error: 04048 ctxt->insert = oldInsert; 04049 return; 04050 } 04051 04052 04062 void 04063 xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node, 04064 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) { 04065 xmlChar *value = NULL; 04066 xmlNodePtr commentNode; 04067 int len; 04068 04069 value = xsltEvalTemplateString(ctxt, node, inst); 04070 /* TODO: use or generate the compiled form */ 04071 len = xmlStrlen(value); 04072 if (len > 0) { 04073 if ((value[len-1] == '-') || 04074 (xmlStrstr(value, BAD_CAST "--"))) { 04075 xsltTransformError(ctxt, NULL, inst, 04076 "xsl:comment : '--' or ending '-' not allowed in comment\n"); 04077 /* fall through to try to catch further errors */ 04078 } 04079 } 04080 #ifdef WITH_XSLT_DEBUG_PROCESS 04081 if (value == NULL) { 04082 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, 04083 "xsltComment: empty\n")); 04084 } else { 04085 XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, 04086 "xsltComment: content %s\n", value)); 04087 } 04088 #endif 04089 04090 commentNode = xmlNewComment(value); 04091 commentNode = xsltAddChild(ctxt->insert, commentNode); 04092 04093 if (value != NULL) 04094 xmlFree(value); 04095 } 04096 04106 void 04107 xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, 04108 xmlNodePtr inst, xsltStylePreCompPtr castedComp) { 04109 #ifdef XSLT_REFACTORED 04110 xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp; 04111 #else 04112 xsltStylePreCompPtr comp = castedComp; 04113 #endif 04114 const xmlChar *name; 04115 xmlChar *value = NULL; 04116 xmlNodePtr pi; 04117 04118 04119 if (ctxt->insert == NULL) 04120 return; 04121 if (comp->has_name == 0) 04122 return; 04123 if (comp->name == NULL) { 04124 name = xsltEvalAttrValueTemplate(ctxt, inst, 04125 (const xmlChar *)"name", NULL); 04126 if (name == NULL) { 04127 xsltTransformError(ctxt, NULL, inst, 04128 "xsl:processing-instruction : name is missing\n"); 04129 goto error; 04130 } 04131 } else { 04132 name = comp->name; 04133 } 04134 /* TODO: check that it's both an an NCName and a PITarget. */ 04135 04136 04137 value = xsltEvalTemplateString(ctxt, node, inst); 04138 if (xmlStrstr(value, BAD_CAST "?>") != NULL) { 04139 xsltTransformError(ctxt, NULL, inst, 04140 "xsl:processing-instruction: '?>' not allowed within PI content\n"); 04141 goto error; 04142 } 04143 #ifdef WITH_XSLT_DEBUG_PROCESS 04144 if (value == NULL) { 04145 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, 04146 "xsltProcessingInstruction: %s empty\n", name)); 04147 } else { 04148 XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, 04149 "xsltProcessingInstruction: %s content %s\n", name, value)); 04150 } 04151 #endif 04152 04153 pi = xmlNewDocPI(ctxt->insert->doc, name, value); 04154 pi = xsltAddChild(ctxt->insert, pi); 04155 04156 error: 04157 if ((name != NULL) && (name != comp->name)) 04158 xmlFree((xmlChar *) name); 04159 if (value != NULL) 04160 xmlFree(value); 04161 } 04162 04172 void 04173 xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node, 04174 xmlNodePtr inst, xsltStylePreCompPtr castedComp) { 04175 #ifdef XSLT_REFACTORED 04176 xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp; 04177 #else 04178 xsltStylePreCompPtr comp = castedComp; 04179 #endif 04180 xmlXPathObjectPtr res = NULL; 04181 xmlNodeSetPtr list = NULL; 04182 int i; 04183 xmlDocPtr oldXPContextDoc; 04184 xmlNsPtr *oldXPNamespaces; 04185 xmlNodePtr oldXPContextNode; 04186 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 04187 xmlXPathContextPtr xpctxt; 04188 04189 if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) 04190 return; 04191 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { 04192 xsltTransformError(ctxt, NULL, inst, 04193 "xsl:copy-of : compilation failed\n"); 04194 return; 04195 } 04196 04197 /* 04198 * SPEC XSLT 1.0: 04199 * "The xsl:copy-of element can be used to insert a result tree 04200 * fragment into the result tree, without first converting it to 04201 * a string as xsl:value-of does (see [7.6.1 Generating Text with 04202 * xsl:value-of]). The required select attribute contains an 04203 * expression. When the result of evaluating the expression is a 04204 * result tree fragment, the complete fragment is copied into the 04205 * result tree. When the result is a node-set, all the nodes in the 04206 * set are copied in document order into the result tree; copying 04207 * an element node copies the attribute nodes, namespace nodes and 04208 * children of the element node as well as the element node itself; 04209 * a root node is copied by copying its children. When the result 04210 * is neither a node-set nor a result tree fragment, the result is 04211 * converted to a string and then inserted into the result tree, 04212 * as with xsl:value-of. 04213 */ 04214 04215 #ifdef WITH_XSLT_DEBUG_PROCESS 04216 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 04217 "xsltCopyOf: select %s\n", comp->select)); 04218 #endif 04219 04220 /* 04221 * Evaluate the "select" expression. 04222 */ 04223 xpctxt = ctxt->xpathCtxt; 04224 oldXPContextDoc = xpctxt->doc; 04225 oldXPContextNode = xpctxt->node; 04226 oldXPProximityPosition = xpctxt->proximityPosition; 04227 oldXPContextSize = xpctxt->contextSize; 04228 oldXPNsNr = xpctxt->nsNr; 04229 oldXPNamespaces = xpctxt->namespaces; 04230 04231 xpctxt->node = node; 04232 if (comp != NULL) { 04233 04234 #ifdef XSLT_REFACTORED 04235 if (comp->inScopeNs != NULL) { 04236 xpctxt->namespaces = comp->inScopeNs->list; 04237 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 04238 } else { 04239 xpctxt->namespaces = NULL; 04240 xpctxt->nsNr = 0; 04241 } 04242 #else 04243 xpctxt->namespaces = comp->nsList; 04244 xpctxt->nsNr = comp->nsNr; 04245 #endif 04246 } else { 04247 xpctxt->namespaces = NULL; 04248 xpctxt->nsNr = 0; 04249 } 04250 04251 res = xmlXPathCompiledEval(comp->comp, xpctxt); 04252 04253 xpctxt->doc = oldXPContextDoc; 04254 xpctxt->node = oldXPContextNode; 04255 xpctxt->contextSize = oldXPContextSize; 04256 xpctxt->proximityPosition = oldXPProximityPosition; 04257 xpctxt->nsNr = oldXPNsNr; 04258 xpctxt->namespaces = oldXPNamespaces; 04259 04260 if (res != NULL) { 04261 if (res->type == XPATH_NODESET) { 04262 /* 04263 * Node-set 04264 * -------- 04265 */ 04266 #ifdef WITH_XSLT_DEBUG_PROCESS 04267 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 04268 "xsltCopyOf: result is a node set\n")); 04269 #endif 04270 list = res->nodesetval; 04271 if (list != NULL) { 04272 xmlNodePtr cur; 04273 /* 04274 * The list is already sorted in document order by XPath. 04275 * Append everything in this order under ctxt->insert. 04276 */ 04277 for (i = 0;i < list->nodeNr;i++) { 04278 cur = list->nodeTab[i]; 04279 if (cur == NULL) 04280 continue; 04281 if ((cur->type == XML_DOCUMENT_NODE) || 04282 (cur->type == XML_HTML_DOCUMENT_NODE)) 04283 { 04284 xsltCopyTreeList(ctxt, inst, 04285 cur->children, ctxt->insert, 0, 0); 04286 } else if (cur->type == XML_ATTRIBUTE_NODE) { 04287 xsltShallowCopyAttr(ctxt, inst, 04288 ctxt->insert, (xmlAttrPtr) cur); 04289 } else { 04290 xsltCopyTreeInternal(ctxt, inst, 04291 cur, ctxt->insert, 0, 0); 04292 } 04293 } 04294 } 04295 } else if (res->type == XPATH_XSLT_TREE) { 04296 /* 04297 * Result tree fragment 04298 * -------------------- 04299 * E.g. via <xsl:variable ...><foo/></xsl:variable> 04300 * Note that the root node of such trees is an xmlDocPtr in Libxslt. 04301 */ 04302 #ifdef WITH_XSLT_DEBUG_PROCESS 04303 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 04304 "xsltCopyOf: result is a result tree fragment\n")); 04305 #endif 04306 list = res->nodesetval; 04307 if ((list != NULL) && (list->nodeTab != NULL) && 04308 (list->nodeTab[0] != NULL) && 04309 (IS_XSLT_REAL_NODE(list->nodeTab[0]))) 04310 { 04311 xsltCopyTreeList(ctxt, inst, 04312 list->nodeTab[0]->children, ctxt->insert, 0, 0); 04313 } 04314 } else { 04315 xmlChar *value = NULL; 04316 /* 04317 * Convert to a string. 04318 */ 04319 value = xmlXPathCastToString(res); 04320 if (value == NULL) { 04321 xsltTransformError(ctxt, NULL, inst, 04322 "Internal error in xsltCopyOf(): " 04323 "failed to cast an XPath object to string.\n"); 04324 ctxt->state = XSLT_STATE_STOPPED; 04325 } else { 04326 if (value[0] != 0) { 04327 /* 04328 * Append content as text node. 04329 */ 04330 xsltCopyTextString(ctxt, ctxt->insert, value, 0); 04331 } 04332 xmlFree(value); 04333 04334 #ifdef WITH_XSLT_DEBUG_PROCESS 04335 XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, 04336 "xsltCopyOf: result %s\n", res->stringval)); 04337 #endif 04338 } 04339 } 04340 } else { 04341 ctxt->state = XSLT_STATE_STOPPED; 04342 } 04343 04344 if (res != NULL) 04345 xmlXPathFreeObject(res); 04346 } 04347 04357 void 04358 xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, 04359 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 04360 { 04361 #ifdef XSLT_REFACTORED 04362 xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp; 04363 #else 04364 xsltStylePreCompPtr comp = castedComp; 04365 #endif 04366 xmlXPathObjectPtr res = NULL; 04367 xmlNodePtr copy = NULL; 04368 xmlChar *value = NULL; 04369 xmlDocPtr oldXPContextDoc; 04370 xmlNsPtr *oldXPNamespaces; 04371 xmlNodePtr oldXPContextNode; 04372 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 04373 xmlXPathContextPtr xpctxt; 04374 04375 if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) 04376 return; 04377 04378 if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { 04379 xsltTransformError(ctxt, NULL, inst, 04380 "Internal error in xsltValueOf(): " 04381 "The XSLT 'value-of' instruction was not compiled.\n"); 04382 return; 04383 } 04384 04385 #ifdef WITH_XSLT_DEBUG_PROCESS 04386 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, 04387 "xsltValueOf: select %s\n", comp->select)); 04388 #endif 04389 04390 xpctxt = ctxt->xpathCtxt; 04391 oldXPContextDoc = xpctxt->doc; 04392 oldXPContextNode = xpctxt->node; 04393 oldXPProximityPosition = xpctxt->proximityPosition; 04394 oldXPContextSize = xpctxt->contextSize; 04395 oldXPNsNr = xpctxt->nsNr; 04396 oldXPNamespaces = xpctxt->namespaces; 04397 04398 xpctxt->node = node; 04399 if (comp != NULL) { 04400 04401 #ifdef XSLT_REFACTORED 04402 if (comp->inScopeNs != NULL) { 04403 xpctxt->namespaces = comp->inScopeNs->list; 04404 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 04405 } else { 04406 xpctxt->namespaces = NULL; 04407 xpctxt->nsNr = 0; 04408 } 04409 #else 04410 xpctxt->namespaces = comp->nsList; 04411 xpctxt->nsNr = comp->nsNr; 04412 #endif 04413 } else { 04414 xpctxt->namespaces = NULL; 04415 xpctxt->nsNr = 0; 04416 } 04417 04418 res = xmlXPathCompiledEval(comp->comp, xpctxt); 04419 04420 xpctxt->doc = oldXPContextDoc; 04421 xpctxt->node = oldXPContextNode; 04422 xpctxt->contextSize = oldXPContextSize; 04423 xpctxt->proximityPosition = oldXPProximityPosition; 04424 xpctxt->nsNr = oldXPNsNr; 04425 xpctxt->namespaces = oldXPNamespaces; 04426 04427 /* 04428 * Cast the XPath object to string. 04429 */ 04430 if (res != NULL) { 04431 value = xmlXPathCastToString(res); 04432 if (value == NULL) { 04433 xsltTransformError(ctxt, NULL, inst, 04434 "Internal error in xsltValueOf(): " 04435 "failed to cast an XPath object to string.\n"); 04436 ctxt->state = XSLT_STATE_STOPPED; 04437 goto error; 04438 } 04439 if (value[0] != 0) { 04440 copy = xsltCopyTextString(ctxt, 04441 ctxt->insert, value, comp->noescape); 04442 } 04443 } else { 04444 xsltTransformError(ctxt, NULL, inst, 04445 "XPath evaluation returned no result.\n"); 04446 ctxt->state = XSLT_STATE_STOPPED; 04447 goto error; 04448 } 04449 04450 #ifdef WITH_XSLT_DEBUG_PROCESS 04451 if (value) { 04452 XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, 04453 "xsltValueOf: result '%s'\n", value)); 04454 } 04455 #endif 04456 04457 error: 04458 if (value != NULL) 04459 xmlFree(value); 04460 if (res != NULL) 04461 xmlXPathFreeObject(res); 04462 } 04463 04473 void 04474 xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node, 04475 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 04476 { 04477 #ifdef XSLT_REFACTORED 04478 xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp; 04479 #else 04480 xsltStylePreCompPtr comp = castedComp; 04481 #endif 04482 if (comp == NULL) { 04483 xsltTransformError(ctxt, NULL, inst, 04484 "xsl:number : compilation failed\n"); 04485 return; 04486 } 04487 04488 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) 04489 return; 04490 04491 comp->numdata.doc = inst->doc; 04492 comp->numdata.node = inst; 04493 04494 xsltNumberFormat(ctxt, &comp->numdata, node); 04495 } 04496 04506 void 04507 xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 04508 xmlNodePtr inst, 04509 xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) 04510 { 04511 xsltTemplatePtr templ; 04512 04513 if ((ctxt == NULL) || (inst == NULL)) 04514 return; 04515 04516 if (comp == NULL) { 04517 xsltTransformError(ctxt, NULL, inst, 04518 "Internal error in xsltApplyImports(): " 04519 "The XSLT 'apply-imports' instruction was not compiled.\n"); 04520 return; 04521 } 04522 /* 04523 * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the 04524 * same; the former is the "Current Template Rule" as defined by the 04525 * XSLT spec, the latter is simply the template struct being 04526 * currently processed. 04527 */ 04528 if (ctxt->currentTemplateRule == NULL) { 04529 /* 04530 * SPEC XSLT 2.0: 04531 * "[ERR XTDE0560] It is a non-recoverable dynamic error if 04532 * xsl:apply-imports or xsl:next-match is evaluated when the 04533 * current template rule is null." 04534 */ 04535 xsltTransformError(ctxt, NULL, inst, 04536 "It is an error to call 'apply-imports' " 04537 "when there's no current template rule.\n"); 04538 return; 04539 } 04540 /* 04541 * TODO: Check if this is correct. 04542 */ 04543 templ = xsltGetTemplate(ctxt, contextNode, 04544 ctxt->currentTemplateRule->style); 04545 04546 if (templ != NULL) { 04547 xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule; 04548 /* 04549 * Set the current template rule. 04550 */ 04551 ctxt->currentTemplateRule = templ; 04552 /* 04553 * URGENT TODO: Need xsl:with-param be handled somehow here? 04554 */ 04555 xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, 04556 templ, NULL); 04557 04558 ctxt->currentTemplateRule = oldCurTemplRule; 04559 } 04560 } 04561 04571 void 04572 xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, 04573 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 04574 { 04575 #ifdef XSLT_REFACTORED 04576 xsltStyleItemCallTemplatePtr comp = 04577 (xsltStyleItemCallTemplatePtr) castedComp; 04578 #else 04579 xsltStylePreCompPtr comp = castedComp; 04580 #endif 04581 xsltStackElemPtr withParams = NULL; 04582 04583 if (ctxt->insert == NULL) 04584 return; 04585 if (comp == NULL) { 04586 xsltTransformError(ctxt, NULL, inst, 04587 "The XSLT 'call-template' instruction was not compiled.\n"); 04588 return; 04589 } 04590 04591 /* 04592 * The template must have been precomputed 04593 */ 04594 if (comp->templ == NULL) { 04595 comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns); 04596 if (comp->templ == NULL) { 04597 if (comp->ns != NULL) { 04598 xsltTransformError(ctxt, NULL, inst, 04599 "The called template '{%s}%s' was not found.\n", 04600 comp->ns, comp->name); 04601 } else { 04602 xsltTransformError(ctxt, NULL, inst, 04603 "The called template '%s' was not found.\n", 04604 comp->name); 04605 } 04606 return; 04607 } 04608 } 04609 04610 #ifdef WITH_XSLT_DEBUG_PROCESS 04611 if ((comp != NULL) && (comp->name != NULL)) 04612 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 04613 "call-template: name %s\n", comp->name)); 04614 #endif 04615 04616 if (inst->children) { 04617 xmlNodePtr cur; 04618 xsltStackElemPtr param; 04619 04620 cur = inst->children; 04621 while (cur != NULL) { 04622 #ifdef WITH_DEBUGGER 04623 if (ctxt->debugStatus != XSLT_DEBUG_NONE) 04624 xslHandleDebugger(cur, node, comp->templ, ctxt); 04625 #endif 04626 if (ctxt->state == XSLT_STATE_STOPPED) break; 04627 /* 04628 * TODO: The "with-param"s could be part of the "call-template" 04629 * structure. Avoid to "search" for params dynamically 04630 * in the XML tree every time. 04631 */ 04632 if (IS_XSLT_ELEM(cur)) { 04633 if (IS_XSLT_NAME(cur, "with-param")) { 04634 param = xsltParseStylesheetCallerParam(ctxt, cur); 04635 if (param != NULL) { 04636 param->next = withParams; 04637 withParams = param; 04638 } 04639 } else { 04640 xsltGenericError(xsltGenericErrorContext, 04641 "xsl:call-template: misplaced xsl:%s\n", cur->name); 04642 } 04643 } else { 04644 xsltGenericError(xsltGenericErrorContext, 04645 "xsl:call-template: misplaced %s element\n", cur->name); 04646 } 04647 cur = cur->next; 04648 } 04649 } 04650 /* 04651 * Create a new frame using the params first 04652 */ 04653 xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ, 04654 withParams); 04655 if (withParams != NULL) 04656 xsltFreeStackElemList(withParams); 04657 04658 #ifdef WITH_XSLT_DEBUG_PROCESS 04659 if ((comp != NULL) && (comp->name != NULL)) 04660 XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, 04661 "call-template returned: name %s\n", comp->name)); 04662 #endif 04663 } 04664 04674 void 04675 xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, 04676 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 04677 { 04678 #ifdef XSLT_REFACTORED 04679 xsltStyleItemApplyTemplatesPtr comp = 04680 (xsltStyleItemApplyTemplatesPtr) castedComp; 04681 #else 04682 xsltStylePreCompPtr comp = castedComp; 04683 #endif 04684 int i; 04685 xmlNodePtr cur, delNode = NULL, oldContextNode; 04686 xmlNodeSetPtr list = NULL, oldList; 04687 xsltStackElemPtr withParams = NULL; 04688 int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; 04689 const xmlChar *oldMode, *oldModeURI; 04690 xmlDocPtr oldXPDoc; 04691 xsltDocumentPtr oldDocInfo; 04692 xmlXPathContextPtr xpctxt; 04693 xmlNsPtr *oldXPNamespaces; 04694 04695 if (comp == NULL) { 04696 xsltTransformError(ctxt, NULL, inst, 04697 "xsl:apply-templates : compilation failed\n"); 04698 return; 04699 } 04700 if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) 04701 return; 04702 04703 #ifdef WITH_XSLT_DEBUG_PROCESS 04704 if ((node != NULL) && (node->name != NULL)) 04705 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 04706 "xsltApplyTemplates: node: '%s'\n", node->name)); 04707 #endif 04708 04709 xpctxt = ctxt->xpathCtxt; 04710 /* 04711 * Save context states. 04712 */ 04713 oldContextNode = ctxt->node; 04714 oldMode = ctxt->mode; 04715 oldModeURI = ctxt->modeURI; 04716 oldDocInfo = ctxt->document; 04717 oldList = ctxt->nodeList; 04718 04719 /* 04720 * The xpath context size and proximity position, as 04721 * well as the xpath and context documents, may be changed 04722 * so we save their initial state and will restore on exit 04723 */ 04724 oldXPContextSize = xpctxt->contextSize; 04725 oldXPProximityPosition = xpctxt->proximityPosition; 04726 oldXPDoc = xpctxt->doc; 04727 oldXPNsNr = xpctxt->nsNr; 04728 oldXPNamespaces = xpctxt->namespaces; 04729 04730 /* 04731 * Set up contexts. 04732 */ 04733 ctxt->mode = comp->mode; 04734 ctxt->modeURI = comp->modeURI; 04735 04736 if (comp->select != NULL) { 04737 xmlXPathObjectPtr res = NULL; 04738 04739 if (comp->comp == NULL) { 04740 xsltTransformError(ctxt, NULL, inst, 04741 "xsl:apply-templates : compilation failed\n"); 04742 goto error; 04743 } 04744 #ifdef WITH_XSLT_DEBUG_PROCESS 04745 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 04746 "xsltApplyTemplates: select %s\n", comp->select)); 04747 #endif 04748 04749 /* 04750 * Set up XPath. 04751 */ 04752 xpctxt->node = node; /* Set the "context node" */ 04753 #ifdef XSLT_REFACTORED 04754 if (comp->inScopeNs != NULL) { 04755 xpctxt->namespaces = comp->inScopeNs->list; 04756 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 04757 } else { 04758 xpctxt->namespaces = NULL; 04759 xpctxt->nsNr = 0; 04760 } 04761 #else 04762 xpctxt->namespaces = comp->nsList; 04763 xpctxt->nsNr = comp->nsNr; 04764 #endif 04765 res = xmlXPathCompiledEval(comp->comp, xpctxt); 04766 04767 xpctxt->contextSize = oldXPContextSize; 04768 xpctxt->proximityPosition = oldXPProximityPosition; 04769 if (res != NULL) { 04770 if (res->type == XPATH_NODESET) { 04771 list = res->nodesetval; /* consume the node set */ 04772 res->nodesetval = NULL; 04773 } else { 04774 xsltTransformError(ctxt, NULL, inst, 04775 "The 'select' expression did not evaluate to a " 04776 "node set.\n"); 04777 ctxt->state = XSLT_STATE_STOPPED; 04778 xmlXPathFreeObject(res); 04779 goto error; 04780 } 04781 xmlXPathFreeObject(res); 04782 /* 04783 * Note: An xsl:apply-templates with a 'select' attribute, 04784 * can change the current source doc. 04785 */ 04786 } else { 04787 xsltTransformError(ctxt, NULL, inst, 04788 "Failed to evaluate the 'select' expression.\n"); 04789 ctxt->state = XSLT_STATE_STOPPED; 04790 goto error; 04791 } 04792 if (list == NULL) { 04793 #ifdef WITH_XSLT_DEBUG_PROCESS 04794 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 04795 "xsltApplyTemplates: select didn't evaluate to a node list\n")); 04796 #endif 04797 goto exit; 04798 } 04799 /* 04800 * 04801 * NOTE: Previously a document info (xsltDocument) was 04802 * created and attached to the Result Tree Fragment. 04803 * But such a document info is created on demand in 04804 * xsltKeyFunction() (functions.c), so we need to create 04805 * it here beforehand. 04806 * In order to take care of potential keys we need to 04807 * do some extra work for the case when a Result Tree Fragment 04808 * is converted into a nodeset (e.g. exslt:node-set()) : 04809 * We attach a "pseudo-doc" (xsltDocument) to _private. 04810 * This xsltDocument, together with the keyset, will be freed 04811 * when the Result Tree Fragment is freed. 04812 * 04813 */ 04814 #if 0 04815 if ((ctxt->nbKeys > 0) && 04816 (list->nodeNr != 0) && 04817 (list->nodeTab[0]->doc != NULL) && 04818 XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc)) 04819 { 04820 /* 04821 * NOTE that it's also OK if @effectiveDocInfo will be 04822 * set to NULL. 04823 */ 04824 isRTF = 1; 04825 effectiveDocInfo = list->nodeTab[0]->doc->_private; 04826 } 04827 #endif 04828 } else { 04829 /* 04830 * Build an XPath node set with the children 04831 */ 04832 list = xmlXPathNodeSetCreate(NULL); 04833 if (list == NULL) 04834 goto error; 04835 cur = node->children; 04836 while (cur != NULL) { 04837 switch (cur->type) { 04838 case XML_TEXT_NODE: 04839 if ((IS_BLANK_NODE(cur)) && 04840 (cur->parent != NULL) && 04841 (cur->parent->type == XML_ELEMENT_NODE) && 04842 (ctxt->style->stripSpaces != NULL)) { 04843 const xmlChar *val; 04844 04845 if (cur->parent->ns != NULL) { 04846 val = (const xmlChar *) 04847 xmlHashLookup2(ctxt->style->stripSpaces, 04848 cur->parent->name, 04849 cur->parent->ns->href); 04850 if (val == NULL) { 04851 val = (const xmlChar *) 04852 xmlHashLookup2(ctxt->style->stripSpaces, 04853 BAD_CAST "*", 04854 cur->parent->ns->href); 04855 } 04856 } else { 04857 val = (const xmlChar *) 04858 xmlHashLookup2(ctxt->style->stripSpaces, 04859 cur->parent->name, NULL); 04860 } 04861 if ((val != NULL) && 04862 (xmlStrEqual(val, (xmlChar *) "strip"))) { 04863 delNode = cur; 04864 break; 04865 } 04866 } 04867 /* no break on purpose */ 04868 case XML_ELEMENT_NODE: 04869 case XML_DOCUMENT_NODE: 04870 case XML_HTML_DOCUMENT_NODE: 04871 case XML_CDATA_SECTION_NODE: 04872 case XML_PI_NODE: 04873 case XML_COMMENT_NODE: 04874 xmlXPathNodeSetAddUnique(list, cur); 04875 break; 04876 case XML_DTD_NODE: 04877 /* Unlink the DTD, it's still reachable 04878 * using doc->intSubset */ 04879 if (cur->next != NULL) 04880 cur->next->prev = cur->prev; 04881 if (cur->prev != NULL) 04882 cur->prev->next = cur->next; 04883 break; 04884 default: 04885 #ifdef WITH_XSLT_DEBUG_PROCESS 04886 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 04887 "xsltApplyTemplates: skipping cur type %d\n", 04888 cur->type)); 04889 #endif 04890 delNode = cur; 04891 } 04892 cur = cur->next; 04893 if (delNode != NULL) { 04894 #ifdef WITH_XSLT_DEBUG_PROCESS 04895 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 04896 "xsltApplyTemplates: removing ignorable blank cur\n")); 04897 #endif 04898 xmlUnlinkNode(delNode); 04899 xmlFreeNode(delNode); 04900 delNode = NULL; 04901 } 04902 } 04903 } 04904 04905 #ifdef WITH_XSLT_DEBUG_PROCESS 04906 if (list != NULL) 04907 XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, 04908 "xsltApplyTemplates: list of %d nodes\n", list->nodeNr)); 04909 #endif 04910 04911 if ((list == NULL) || (list->nodeNr == 0)) 04912 goto exit; 04913 04914 /* 04915 * Set the context's node set and size; this is also needed for 04916 * for xsltDoSortFunction(). 04917 */ 04918 ctxt->nodeList = list; 04919 /* 04920 * Process xsl:with-param and xsl:sort instructions. 04921 * (The code became so verbose just to avoid the 04922 * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort) 04923 * BUG TODO: We are not using namespaced potentially defined on the 04924 * xsl:sort or xsl:with-param elements; XPath expression might fail. 04925 */ 04926 if (inst->children) { 04927 xsltStackElemPtr param; 04928 04929 cur = inst->children; 04930 while (cur) { 04931 04932 #ifdef WITH_DEBUGGER 04933 if (ctxt->debugStatus != XSLT_DEBUG_NONE) 04934 xslHandleDebugger(cur, node, NULL, ctxt); 04935 #endif 04936 if (ctxt->state == XSLT_STATE_STOPPED) 04937 break; 04938 if (cur->type == XML_TEXT_NODE) { 04939 cur = cur->next; 04940 continue; 04941 } 04942 if (! IS_XSLT_ELEM(cur)) 04943 break; 04944 if (IS_XSLT_NAME(cur, "with-param")) { 04945 param = xsltParseStylesheetCallerParam(ctxt, cur); 04946 if (param != NULL) { 04947 param->next = withParams; 04948 withParams = param; 04949 } 04950 } 04951 if (IS_XSLT_NAME(cur, "sort")) { 04952 xsltTemplatePtr oldCurTempRule = 04953 ctxt->currentTemplateRule; 04954 int nbsorts = 0; 04955 xmlNodePtr sorts[XSLT_MAX_SORT]; 04956 04957 sorts[nbsorts++] = cur; 04958 04959 while (cur) { 04960 04961 #ifdef WITH_DEBUGGER 04962 if (ctxt->debugStatus != XSLT_DEBUG_NONE) 04963 xslHandleDebugger(cur, node, NULL, ctxt); 04964 #endif 04965 if (ctxt->state == XSLT_STATE_STOPPED) 04966 break; 04967 04968 if (cur->type == XML_TEXT_NODE) { 04969 cur = cur->next; 04970 continue; 04971 } 04972 04973 if (! IS_XSLT_ELEM(cur)) 04974 break; 04975 if (IS_XSLT_NAME(cur, "with-param")) { 04976 param = xsltParseStylesheetCallerParam(ctxt, cur); 04977 if (param != NULL) { 04978 param->next = withParams; 04979 withParams = param; 04980 } 04981 } 04982 if (IS_XSLT_NAME(cur, "sort")) { 04983 if (nbsorts >= XSLT_MAX_SORT) { 04984 xsltTransformError(ctxt, NULL, cur, 04985 "The number (%d) of xsl:sort instructions exceeds the " 04986 "maximum allowed by this processor's settings.\n", 04987 nbsorts); 04988 ctxt->state = XSLT_STATE_STOPPED; 04989 break; 04990 } else { 04991 sorts[nbsorts++] = cur; 04992 } 04993 } 04994 cur = cur->next; 04995 } 04996 /* 04997 * The "current template rule" is cleared for xsl:sort. 04998 */ 04999 ctxt->currentTemplateRule = NULL; 05000 /* 05001 * Sort. 05002 */ 05003 xsltDoSortFunction(ctxt, sorts, nbsorts); 05004 ctxt->currentTemplateRule = oldCurTempRule; 05005 break; 05006 } 05007 cur = cur->next; 05008 } 05009 } 05010 xpctxt->contextSize = list->nodeNr; 05011 /* 05012 * Apply templates for all selected source nodes. 05013 */ 05014 for (i = 0; i < list->nodeNr; i++) { 05015 cur = list->nodeTab[i]; 05016 /* 05017 * The node becomes the "current node". 05018 */ 05019 ctxt->node = cur; 05020 /* 05021 * An xsl:apply-templates can change the current context doc. 05022 * OPTIMIZE TODO: Get rid of the need to set the context doc. 05023 */ 05024 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) 05025 xpctxt->doc = cur->doc; 05026 05027 xpctxt->proximityPosition = i + 1; 05028 /* 05029 * Find and apply a template for this node. 05030 */ 05031 xsltProcessOneNode(ctxt, cur, withParams); 05032 } 05033 05034 exit: 05035 error: 05036 /* 05037 * Free the parameter list. 05038 */ 05039 if (withParams != NULL) 05040 xsltFreeStackElemList(withParams); 05041 if (list != NULL) 05042 xmlXPathFreeNodeSet(list); 05043 /* 05044 * Restore context states. 05045 */ 05046 xpctxt->nsNr = oldXPNsNr; 05047 xpctxt->namespaces = oldXPNamespaces; 05048 xpctxt->doc = oldXPDoc; 05049 xpctxt->contextSize = oldXPContextSize; 05050 xpctxt->proximityPosition = oldXPProximityPosition; 05051 05052 ctxt->document = oldDocInfo; 05053 ctxt->nodeList = oldList; 05054 ctxt->node = oldContextNode; 05055 ctxt->mode = oldMode; 05056 ctxt->modeURI = oldModeURI; 05057 } 05058 05059 05069 void 05070 xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 05071 xmlNodePtr inst, xsltStylePreCompPtr comp ATTRIBUTE_UNUSED) 05072 { 05073 xmlNodePtr cur; 05074 05075 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) 05076 return; 05077 05078 /* 05079 * TODO: Content model checks should be done only at compilation 05080 * time. 05081 */ 05082 cur = inst->children; 05083 if (cur == NULL) { 05084 xsltTransformError(ctxt, NULL, inst, 05085 "xsl:choose: The instruction has no content.\n"); 05086 return; 05087 } 05088 05089 #ifdef XSLT_REFACTORED 05090 /* 05091 * We don't check the content model during transformation. 05092 */ 05093 #else 05094 if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) { 05095 xsltTransformError(ctxt, NULL, inst, 05096 "xsl:choose: xsl:when expected first\n"); 05097 return; 05098 } 05099 #endif 05100 05101 { 05102 int testRes = 0, res = 0; 05103 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 05104 xmlDocPtr oldXPContextDoc = xpctxt->doc; 05105 int oldXPProximityPosition = xpctxt->proximityPosition; 05106 int oldXPContextSize = xpctxt->contextSize; 05107 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; 05108 int oldXPNsNr = xpctxt->nsNr; 05109 05110 #ifdef XSLT_REFACTORED 05111 xsltStyleItemWhenPtr wcomp = NULL; 05112 #else 05113 xsltStylePreCompPtr wcomp = NULL; 05114 #endif 05115 05116 /* 05117 * Process xsl:when --------------------------------------------------- 05118 */ 05119 while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) { 05120 wcomp = cur->psvi; 05121 05122 if ((wcomp == NULL) || (wcomp->test == NULL) || 05123 (wcomp->comp == NULL)) 05124 { 05125 xsltTransformError(ctxt, NULL, cur, 05126 "Internal error in xsltChoose(): " 05127 "The XSLT 'when' instruction was not compiled.\n"); 05128 goto error; 05129 } 05130 05131 05132 #ifdef WITH_DEBUGGER 05133 if (xslDebugStatus != XSLT_DEBUG_NONE) { 05134 /* 05135 * TODO: Isn't comp->templ always NULL for xsl:choose? 05136 */ 05137 xslHandleDebugger(cur, contextNode, NULL, ctxt); 05138 } 05139 #endif 05140 #ifdef WITH_XSLT_DEBUG_PROCESS 05141 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 05142 "xsltChoose: test %s\n", wcomp->test)); 05143 #endif 05144 05145 xpctxt->node = contextNode; 05146 xpctxt->doc = oldXPContextDoc; 05147 xpctxt->proximityPosition = oldXPProximityPosition; 05148 xpctxt->contextSize = oldXPContextSize; 05149 05150 #ifdef XSLT_REFACTORED 05151 if (wcomp->inScopeNs != NULL) { 05152 xpctxt->namespaces = wcomp->inScopeNs->list; 05153 xpctxt->nsNr = wcomp->inScopeNs->xpathNumber; 05154 } else { 05155 xpctxt->namespaces = NULL; 05156 xpctxt->nsNr = 0; 05157 } 05158 #else 05159 xpctxt->namespaces = wcomp->nsList; 05160 xpctxt->nsNr = wcomp->nsNr; 05161 #endif 05162 05163 05164 #ifdef XSLT_FAST_IF 05165 res = xmlXPathCompiledEvalToBoolean(wcomp->comp, xpctxt); 05166 05167 if (res == -1) { 05168 ctxt->state = XSLT_STATE_STOPPED; 05169 goto error; 05170 } 05171 testRes = (res == 1) ? 1 : 0; 05172 05173 #else /* XSLT_FAST_IF */ 05174 05175 res = xmlXPathCompiledEval(wcomp->comp, xpctxt); 05176 05177 if (res != NULL) { 05178 if (res->type != XPATH_BOOLEAN) 05179 res = xmlXPathConvertBoolean(res); 05180 if (res->type == XPATH_BOOLEAN) 05181 testRes = res->boolval; 05182 else { 05183 #ifdef WITH_XSLT_DEBUG_PROCESS 05184 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 05185 "xsltChoose: test didn't evaluate to a boolean\n")); 05186 #endif 05187 goto error; 05188 } 05189 xmlXPathFreeObject(res); 05190 res = NULL; 05191 } else { 05192 ctxt->state = XSLT_STATE_STOPPED; 05193 goto error; 05194 } 05195 05196 #endif /* else of XSLT_FAST_IF */ 05197 05198 #ifdef WITH_XSLT_DEBUG_PROCESS 05199 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 05200 "xsltChoose: test evaluate to %d\n", testRes)); 05201 #endif 05202 if (testRes) 05203 goto test_is_true; 05204 05205 cur = cur->next; 05206 } 05207 05208 /* 05209 * Process xsl:otherwise ---------------------------------------------- 05210 */ 05211 if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) { 05212 05213 #ifdef WITH_DEBUGGER 05214 if (xslDebugStatus != XSLT_DEBUG_NONE) 05215 xslHandleDebugger(cur, contextNode, NULL, ctxt); 05216 #endif 05217 05218 #ifdef WITH_XSLT_DEBUG_PROCESS 05219 XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, 05220 "evaluating xsl:otherwise\n")); 05221 #endif 05222 goto test_is_true; 05223 } 05224 xpctxt->node = contextNode; 05225 xpctxt->doc = oldXPContextDoc; 05226 xpctxt->proximityPosition = oldXPProximityPosition; 05227 xpctxt->contextSize = oldXPContextSize; 05228 xpctxt->namespaces = oldXPNamespaces; 05229 xpctxt->nsNr = oldXPNsNr; 05230 goto exit; 05231 05232 test_is_true: 05233 05234 xpctxt->node = contextNode; 05235 xpctxt->doc = oldXPContextDoc; 05236 xpctxt->proximityPosition = oldXPProximityPosition; 05237 xpctxt->contextSize = oldXPContextSize; 05238 xpctxt->namespaces = oldXPNamespaces; 05239 xpctxt->nsNr = oldXPNsNr; 05240 goto process_sequence; 05241 } 05242 05243 process_sequence: 05244 05245 /* 05246 * Instantiate the sequence constructor. 05247 */ 05248 xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children, 05249 NULL); 05250 05251 exit: 05252 error: 05253 return; 05254 } 05255 05265 void 05266 xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 05267 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 05268 { 05269 int res = 0; 05270 05271 #ifdef XSLT_REFACTORED 05272 xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp; 05273 #else 05274 xsltStylePreCompPtr comp = castedComp; 05275 #endif 05276 05277 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) 05278 return; 05279 if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) { 05280 xsltTransformError(ctxt, NULL, inst, 05281 "Internal error in xsltIf(): " 05282 "The XSLT 'if' instruction was not compiled.\n"); 05283 return; 05284 } 05285 05286 #ifdef WITH_XSLT_DEBUG_PROCESS 05287 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, 05288 "xsltIf: test %s\n", comp->test)); 05289 #endif 05290 05291 #ifdef XSLT_FAST_IF 05292 { 05293 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 05294 xmlDocPtr oldXPContextDoc = xpctxt->doc; 05295 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; 05296 xmlNodePtr oldXPContextNode = xpctxt->node; 05297 int oldXPProximityPosition = xpctxt->proximityPosition; 05298 int oldXPContextSize = xpctxt->contextSize; 05299 int oldXPNsNr = xpctxt->nsNr; 05300 xmlDocPtr oldLocalFragmentTop = ctxt->localRVT; 05301 05302 xpctxt->node = contextNode; 05303 if (comp != NULL) { 05304 05305 #ifdef XSLT_REFACTORED 05306 if (comp->inScopeNs != NULL) { 05307 xpctxt->namespaces = comp->inScopeNs->list; 05308 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 05309 } else { 05310 xpctxt->namespaces = NULL; 05311 xpctxt->nsNr = 0; 05312 } 05313 #else 05314 xpctxt->namespaces = comp->nsList; 05315 xpctxt->nsNr = comp->nsNr; 05316 #endif 05317 } else { 05318 xpctxt->namespaces = NULL; 05319 xpctxt->nsNr = 0; 05320 } 05321 /* 05322 * This XPath function is optimized for boolean results. 05323 */ 05324 res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt); 05325 05326 /* 05327 * Cleanup fragments created during evaluation of the 05328 * "select" expression. 05329 */ 05330 if (oldLocalFragmentTop != ctxt->localRVT) 05331 xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); 05332 05333 xpctxt->doc = oldXPContextDoc; 05334 xpctxt->node = oldXPContextNode; 05335 xpctxt->contextSize = oldXPContextSize; 05336 xpctxt->proximityPosition = oldXPProximityPosition; 05337 xpctxt->nsNr = oldXPNsNr; 05338 xpctxt->namespaces = oldXPNamespaces; 05339 } 05340 05341 #ifdef WITH_XSLT_DEBUG_PROCESS 05342 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, 05343 "xsltIf: test evaluate to %d\n", res)); 05344 #endif 05345 05346 if (res == -1) { 05347 ctxt->state = XSLT_STATE_STOPPED; 05348 goto error; 05349 } 05350 if (res == 1) { 05351 /* 05352 * Instantiate the sequence constructor of xsl:if. 05353 */ 05354 xsltApplySequenceConstructor(ctxt, 05355 contextNode, inst->children, NULL); 05356 } 05357 05358 #else /* XSLT_FAST_IF */ 05359 { 05360 xmlXPathObjectPtr xpobj = NULL; 05361 /* 05362 * OLD CODE: 05363 */ 05364 { 05365 xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; 05366 xmlDocPtr oldXPContextDoc = xpctxt->doc; 05367 xmlNsPtr *oldXPNamespaces = xpctxt->namespaces; 05368 xmlNodePtr oldXPContextNode = xpctxt->node; 05369 int oldXPProximityPosition = xpctxt->proximityPosition; 05370 int oldXPContextSize = xpctxt->contextSize; 05371 int oldXPNsNr = xpctxt->nsNr; 05372 05373 xpctxt->node = contextNode; 05374 if (comp != NULL) { 05375 05376 #ifdef XSLT_REFACTORED 05377 if (comp->inScopeNs != NULL) { 05378 xpctxt->namespaces = comp->inScopeNs->list; 05379 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 05380 } else { 05381 xpctxt->namespaces = NULL; 05382 xpctxt->nsNr = 0; 05383 } 05384 #else 05385 xpctxt->namespaces = comp->nsList; 05386 xpctxt->nsNr = comp->nsNr; 05387 #endif 05388 } else { 05389 xpctxt->namespaces = NULL; 05390 xpctxt->nsNr = 0; 05391 } 05392 05393 /* 05394 * This XPath function is optimized for boolean results. 05395 */ 05396 xpobj = xmlXPathCompiledEval(comp->comp, xpctxt); 05397 05398 xpctxt->doc = oldXPContextDoc; 05399 xpctxt->node = oldXPContextNode; 05400 xpctxt->contextSize = oldXPContextSize; 05401 xpctxt->proximityPosition = oldXPProximityPosition; 05402 xpctxt->nsNr = oldXPNsNr; 05403 xpctxt->namespaces = oldXPNamespaces; 05404 } 05405 if (xpobj != NULL) { 05406 if (xpobj->type != XPATH_BOOLEAN) 05407 xpobj = xmlXPathConvertBoolean(xpobj); 05408 if (xpobj->type == XPATH_BOOLEAN) { 05409 res = xpobj->boolval; 05410 05411 #ifdef WITH_XSLT_DEBUG_PROCESS 05412 XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, 05413 "xsltIf: test evaluate to %d\n", res)); 05414 #endif 05415 if (res) { 05416 xsltApplySequenceConstructor(ctxt, 05417 contextNode, inst->children, NULL); 05418 } 05419 } else { 05420 05421 #ifdef WITH_XSLT_DEBUG_PROCESS 05422 XSLT_TRACE(ctxt, XSLT_TRACE_IF, 05423 xsltGenericDebug(xsltGenericDebugContext, 05424 "xsltIf: test didn't evaluate to a boolean\n")); 05425 #endif 05426 ctxt->state = XSLT_STATE_STOPPED; 05427 } 05428 xmlXPathFreeObject(xpobj); 05429 } else { 05430 ctxt->state = XSLT_STATE_STOPPED; 05431 } 05432 } 05433 #endif /* else of XSLT_FAST_IF */ 05434 05435 error: 05436 return; 05437 } 05438 05448 void 05449 xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, 05450 xmlNodePtr inst, xsltStylePreCompPtr castedComp) 05451 { 05452 #ifdef XSLT_REFACTORED 05453 xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp; 05454 #else 05455 xsltStylePreCompPtr comp = castedComp; 05456 #endif 05457 int i; 05458 xmlXPathObjectPtr res = NULL; 05459 xmlNodePtr cur, curInst; 05460 xmlNodeSetPtr list = NULL; 05461 xmlNodeSetPtr oldList; 05462 int oldXPProximityPosition, oldXPContextSize; 05463 xmlNodePtr oldContextNode; 05464 xsltTemplatePtr oldCurTemplRule; 05465 xmlDocPtr oldXPDoc; 05466 xsltDocumentPtr oldDocInfo; 05467 xmlXPathContextPtr xpctxt; 05468 05469 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) { 05470 xsltGenericError(xsltGenericErrorContext, 05471 "xsltForEach(): Bad arguments.\n"); 05472 return; 05473 } 05474 05475 if (comp == NULL) { 05476 xsltTransformError(ctxt, NULL, inst, 05477 "Internal error in xsltForEach(): " 05478 "The XSLT 'for-each' instruction was not compiled.\n"); 05479 return; 05480 } 05481 if ((comp->select == NULL) || (comp->comp == NULL)) { 05482 xsltTransformError(ctxt, NULL, inst, 05483 "Internal error in xsltForEach(): " 05484 "The selecting expression of the XSLT 'for-each' " 05485 "instruction was not compiled correctly.\n"); 05486 return; 05487 } 05488 xpctxt = ctxt->xpathCtxt; 05489 05490 #ifdef WITH_XSLT_DEBUG_PROCESS 05491 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, 05492 "xsltForEach: select %s\n", comp->select)); 05493 #endif 05494 05495 /* 05496 * Save context states. 05497 */ 05498 oldDocInfo = ctxt->document; 05499 oldList = ctxt->nodeList; 05500 oldContextNode = ctxt->node; 05501 /* 05502 * The "current template rule" is cleared for the instantiation of 05503 * xsl:for-each. 05504 */ 05505 oldCurTemplRule = ctxt->currentTemplateRule; 05506 ctxt->currentTemplateRule = NULL; 05507 05508 oldXPDoc = xpctxt->doc; 05509 oldXPProximityPosition = xpctxt->proximityPosition; 05510 oldXPContextSize = xpctxt->contextSize; 05511 /* 05512 * Set up XPath. 05513 */ 05514 xpctxt->node = contextNode; 05515 #ifdef XSLT_REFACTORED 05516 if (comp->inScopeNs != NULL) { 05517 xpctxt->namespaces = comp->inScopeNs->list; 05518 xpctxt->nsNr = comp->inScopeNs->xpathNumber; 05519 } else { 05520 xpctxt->namespaces = NULL; 05521 xpctxt->nsNr = 0; 05522 } 05523 #else 05524 xpctxt->namespaces = comp->nsList; 05525 xpctxt->nsNr = comp->nsNr; 05526 #endif 05527 05528 /* 05529 * Evaluate the 'select' expression. 05530 */ 05531 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt); 05532 05533 if (res != NULL) { 05534 if (res->type == XPATH_NODESET) 05535 list = res->nodesetval; 05536 else { 05537 xsltTransformError(ctxt, NULL, inst, 05538 "The 'select' expression does not evaluate to a node set.\n"); 05539 05540 #ifdef WITH_XSLT_DEBUG_PROCESS 05541 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, 05542 "xsltForEach: select didn't evaluate to a node list\n")); 05543 #endif 05544 goto error; 05545 } 05546 } else { 05547 xsltTransformError(ctxt, NULL, inst, 05548 "Failed to evaluate the 'select' expression.\n"); 05549 ctxt->state = XSLT_STATE_STOPPED; 05550 goto error; 05551 } 05552 05553 if ((list == NULL) || (list->nodeNr <= 0)) 05554 goto exit; 05555 05556 #ifdef WITH_XSLT_DEBUG_PROCESS 05557 XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, 05558 "xsltForEach: select evaluates to %d nodes\n", list->nodeNr)); 05559 #endif 05560 05561 /* 05562 * Restore XPath states for the "current node". 05563 */ 05564 xpctxt->contextSize = oldXPContextSize; 05565 xpctxt->proximityPosition = oldXPProximityPosition; 05566 xpctxt->node = contextNode; 05567 05568 /* 05569 * Set the list; this has to be done already here for xsltDoSortFunction(). 05570 */ 05571 ctxt->nodeList = list; 05572 /* 05573 * Handle xsl:sort instructions and skip them for further processing. 05574 * BUG TODO: We are not using namespaced potentially defined on the 05575 * xsl:sort element; XPath expression might fail. 05576 */ 05577 curInst = inst->children; 05578 if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { 05579 int nbsorts = 0; 05580 xmlNodePtr sorts[XSLT_MAX_SORT]; 05581 05582 sorts[nbsorts++] = curInst; 05583 05584 #ifdef WITH_DEBUGGER 05585 if (xslDebugStatus != XSLT_DEBUG_NONE) 05586 xslHandleDebugger(curInst, contextNode, NULL, ctxt); 05587 #endif 05588 05589 curInst = curInst->next; 05590 while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { 05591 if (nbsorts >= XSLT_MAX_SORT) { 05592 xsltTransformError(ctxt, NULL, curInst, 05593 "The number of xsl:sort instructions exceeds the " 05594 "maximum (%d) allowed by this processor.\n", 05595 XSLT_MAX_SORT); 05596 goto error; 05597 } else { 05598 sorts[nbsorts++] = curInst; 05599 } 05600 05601 #ifdef WITH_DEBUGGER 05602 if (xslDebugStatus != XSLT_DEBUG_NONE) 05603 xslHandleDebugger(curInst, contextNode, NULL, ctxt); 05604 #endif 05605 curInst = curInst->next; 05606 } 05607 xsltDoSortFunction(ctxt, sorts, nbsorts); 05608 } 05609 xpctxt->contextSize = list->nodeNr; 05610 /* 05611 * Instantiate the sequence constructor for each selected node. 05612 */ 05613 for (i = 0; i < list->nodeNr; i++) { 05614 cur = list->nodeTab[i]; 05615 /* 05616 * The selected node becomes the "current node". 05617 */ 05618 ctxt->node = cur; 05619 /* 05620 * An xsl:for-each can change the current context doc. 05621 * OPTIMIZE TODO: Get rid of the need to set the context doc. 05622 */ 05623 if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) 05624 xpctxt->doc = cur->doc; 05625 05626 xpctxt->proximityPosition = i + 1; 05627 05628 xsltApplySequenceConstructor(ctxt, cur, curInst, NULL); 05629 } 05630 05631 exit: 05632 error: 05633 if (res != NULL) 05634 xmlXPathFreeObject(res); 05635 /* 05636 * Restore old states. 05637 */ 05638 ctxt->document = oldDocInfo; 05639 ctxt->nodeList = oldList; 05640 ctxt->node = oldContextNode; 05641 ctxt->currentTemplateRule = oldCurTemplRule; 05642 05643 xpctxt->doc = oldXPDoc; 05644 xpctxt->contextSize = oldXPContextSize; 05645 xpctxt->proximityPosition = oldXPProximityPosition; 05646 } 05647 05648 /************************************************************************ 05649 * * 05650 * Generic interface * 05651 * * 05652 ************************************************************************/ 05653 05654 #ifdef XSLT_GENERATE_HTML_DOCTYPE 05655 typedef struct xsltHTMLVersion { 05656 const char *version; 05657 const char *public; 05658 const char *system; 05659 } xsltHTMLVersion; 05660 05661 static xsltHTMLVersion xsltHTMLVersions[] = { 05662 { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN", 05663 "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"}, 05664 { "4.01strict", "-//W3C//DTD HTML 4.01//EN", 05665 "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"}, 05666 { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN", 05667 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, 05668 { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN", 05669 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, 05670 { "4.0strict", "-//W3C//DTD HTML 4.01//EN", 05671 "http://www.w3.org/TR/html4/strict.dtd"}, 05672 { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN", 05673 "http://www.w3.org/TR/html4/loose.dtd"}, 05674 { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN", 05675 "http://www.w3.org/TR/html4/frameset.dtd"}, 05676 { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN", 05677 "http://www.w3.org/TR/html4/loose.dtd"}, 05678 { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL } 05679 }; 05680 05690 static int 05691 xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, 05692 const xmlChar **systemID) { 05693 unsigned int i; 05694 if (version == NULL) 05695 return(-1); 05696 for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1])); 05697 i++) { 05698 if (!xmlStrcasecmp(version, 05699 (const xmlChar *) xsltHTMLVersions[i].version)) { 05700 if (publicID != NULL) 05701 *publicID = (const xmlChar *) xsltHTMLVersions[i].public; 05702 if (systemID != NULL) 05703 *systemID = (const xmlChar *) xsltHTMLVersions[i].system; 05704 return(0); 05705 } 05706 } 05707 return(-1); 05708 } 05709 #endif 05710 05718 void 05719 xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) { 05720 xmlNodePtr current; 05721 #ifdef WITH_XSLT_DEBUG_PROCESS 05722 int nb = 0; 05723 #endif 05724 05725 05726 current = node; 05727 while (current != NULL) { 05728 /* 05729 * Cleanup children empty nodes if asked for 05730 */ 05731 if ((IS_XSLT_REAL_NODE(current)) && 05732 (current->children != NULL) && 05733 (xsltFindElemSpaceHandling(ctxt, current))) { 05734 xmlNodePtr delete = NULL, cur = current->children; 05735 05736 while (cur != NULL) { 05737 if (IS_BLANK_NODE(cur)) 05738 delete = cur; 05739 05740 cur = cur->next; 05741 if (delete != NULL) { 05742 xmlUnlinkNode(delete); 05743 xmlFreeNode(delete); 05744 delete = NULL; 05745 #ifdef WITH_XSLT_DEBUG_PROCESS 05746 nb++; 05747 #endif 05748 } 05749 } 05750 } 05751 05752 /* 05753 * Skip to next node in document order. 05754 */ 05755 if (node->type == XML_ENTITY_REF_NODE) { 05756 /* process deep in entities */ 05757 xsltApplyStripSpaces(ctxt, node->children); 05758 } 05759 if ((current->children != NULL) && 05760 (current->type != XML_ENTITY_REF_NODE)) { 05761 current = current->children; 05762 } else if (current->next != NULL) { 05763 current = current->next; 05764 } else { 05765 do { 05766 current = current->parent; 05767 if (current == NULL) 05768 break; 05769 if (current == node) 05770 goto done; 05771 if (current->next != NULL) { 05772 current = current->next; 05773 break; 05774 } 05775 } while (current != NULL); 05776 } 05777 } 05778 05779 done: 05780 #ifdef WITH_XSLT_DEBUG_PROCESS 05781 XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext, 05782 "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb)); 05783 #endif 05784 return; 05785 } 05786 05787 static int 05788 xsltCountKeys(xsltTransformContextPtr ctxt) 05789 { 05790 xsltStylesheetPtr style; 05791 xsltKeyDefPtr keyd; 05792 05793 if (ctxt == NULL) 05794 return(-1); 05795 05796 /* 05797 * Do we have those nastly templates with a key() in the match pattern? 05798 */ 05799 ctxt->hasTemplKeyPatterns = 0; 05800 style = ctxt->style; 05801 while (style != NULL) { 05802 if (style->keyMatch != NULL) { 05803 ctxt->hasTemplKeyPatterns = 1; 05804 break; 05805 } 05806 style = xsltNextImport(style); 05807 } 05808 /* 05809 * Count number of key declarations. 05810 */ 05811 ctxt->nbKeys = 0; 05812 style = ctxt->style; 05813 while (style != NULL) { 05814 keyd = style->keys; 05815 while (keyd) { 05816 ctxt->nbKeys++; 05817 keyd = keyd->next; 05818 } 05819 style = xsltNextImport(style); 05820 } 05821 return(ctxt->nbKeys); 05822 } 05823 05838 static xmlDocPtr 05839 xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, 05840 const char **params, const char *output, 05841 FILE * profile, xsltTransformContextPtr userCtxt) 05842 { 05843 xmlDocPtr res = NULL; 05844 xsltTransformContextPtr ctxt = NULL; 05845 xmlNodePtr root, node; 05846 const xmlChar *method; 05847 const xmlChar *doctypePublic; 05848 const xmlChar *doctypeSystem; 05849 const xmlChar *version; 05850 const xmlChar *encoding; 05851 xsltStackElemPtr variables; 05852 xsltStackElemPtr vptr; 05853 05854 xsltInitGlobals(); 05855 05856 if ((style == NULL) || (doc == NULL)) 05857 return (NULL); 05858 05859 if (style->internalized == 0) { 05860 #ifdef WITH_XSLT_DEBUG 05861 xsltGenericDebug(xsltGenericDebugContext, 05862 "Stylesheet was not fully internalized !\n"); 05863 #endif 05864 } 05865 if (doc->intSubset != NULL) { 05866 /* 05867 * Avoid hitting the DTD when scanning nodes 05868 * but keep it linked as doc->intSubset 05869 */ 05870 xmlNodePtr cur = (xmlNodePtr) doc->intSubset; 05871 if (cur->next != NULL) 05872 cur->next->prev = cur->prev; 05873 if (cur->prev != NULL) 05874 cur->prev->next = cur->next; 05875 if (doc->children == cur) 05876 doc->children = cur->next; 05877 if (doc->last == cur) 05878 doc->last = cur->prev; 05879 cur->prev = cur->next = NULL; 05880 } 05881 05882 /* 05883 * Check for XPath document order availability 05884 */ 05885 root = xmlDocGetRootElement(doc); 05886 if (root != NULL) { 05887 if (((long) root->content) >= 0 && (xslDebugStatus == XSLT_DEBUG_NONE)) 05888 xmlXPathOrderDocElems(doc); 05889 } 05890 05891 if (userCtxt != NULL) 05892 ctxt = userCtxt; 05893 else 05894 ctxt = xsltNewTransformContext(style, doc); 05895 05896 if (ctxt == NULL) 05897 return (NULL); 05898 05899 ctxt->initialContextDoc = doc; 05900 ctxt->initialContextNode = (xmlNodePtr) doc; 05901 05902 if (profile != NULL) 05903 ctxt->profile = 1; 05904 05905 if (output != NULL) 05906 ctxt->outputFile = output; 05907 else 05908 ctxt->outputFile = NULL; 05909 05910 /* 05911 * internalize the modes if needed 05912 */ 05913 if (ctxt->dict != NULL) { 05914 if (ctxt->mode != NULL) 05915 ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1); 05916 if (ctxt->modeURI != NULL) 05917 ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1); 05918 } 05919 05920 XSLT_GET_IMPORT_PTR(method, style, method) 05921 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 05922 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 05923 XSLT_GET_IMPORT_PTR(version, style, version) 05924 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 05925 05926 if ((method != NULL) && 05927 (!xmlStrEqual(method, (const xmlChar *) "xml"))) 05928 { 05929 if (xmlStrEqual(method, (const xmlChar *) "html")) { 05930 ctxt->type = XSLT_OUTPUT_HTML; 05931 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 05932 res = htmlNewDoc(doctypeSystem, doctypePublic); 05933 } else { 05934 if (version == NULL) { 05935 xmlDtdPtr dtd; 05936 05937 res = htmlNewDoc(NULL, NULL); 05938 /* 05939 * Make sure no DTD node is generated in this case 05940 */ 05941 if (res != NULL) { 05942 dtd = xmlGetIntSubset(res); 05943 if (dtd != NULL) { 05944 xmlUnlinkNode((xmlNodePtr) dtd); 05945 xmlFreeDtd(dtd); 05946 } 05947 res->intSubset = NULL; 05948 res->extSubset = NULL; 05949 } 05950 } else { 05951 05952 #ifdef XSLT_GENERATE_HTML_DOCTYPE 05953 xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); 05954 #endif 05955 res = htmlNewDoc(doctypeSystem, doctypePublic); 05956 } 05957 } 05958 if (res == NULL) 05959 goto error; 05960 res->dict = ctxt->dict; 05961 xmlDictReference(res->dict); 05962 05963 #ifdef WITH_XSLT_DEBUG 05964 xsltGenericDebug(xsltGenericDebugContext, 05965 "reusing transformation dict for output\n"); 05966 #endif 05967 } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { 05968 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, 05969 "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n", 05970 style->method); 05971 ctxt->type = XSLT_OUTPUT_HTML; 05972 res = htmlNewDoc(doctypeSystem, doctypePublic); 05973 if (res == NULL) 05974 goto error; 05975 res->dict = ctxt->dict; 05976 xmlDictReference(res->dict); 05977 05978 #ifdef WITH_XSLT_DEBUG 05979 xsltGenericDebug(xsltGenericDebugContext, 05980 "reusing transformation dict for output\n"); 05981 #endif 05982 } else if (xmlStrEqual(method, (const xmlChar *) "text")) { 05983 ctxt->type = XSLT_OUTPUT_TEXT; 05984 res = xmlNewDoc(style->version); 05985 if (res == NULL) 05986 goto error; 05987 res->dict = ctxt->dict; 05988 xmlDictReference(res->dict); 05989 05990 #ifdef WITH_XSLT_DEBUG 05991 xsltGenericDebug(xsltGenericDebugContext, 05992 "reusing transformation dict for output\n"); 05993 #endif 05994 } else { 05995 xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, 05996 "xsltApplyStylesheetInternal: unsupported method %s\n", 05997 style->method); 05998 goto error; 05999 } 06000 } else { 06001 ctxt->type = XSLT_OUTPUT_XML; 06002 res = xmlNewDoc(style->version); 06003 if (res == NULL) 06004 goto error; 06005 res->dict = ctxt->dict; 06006 xmlDictReference(ctxt->dict); 06007 #ifdef WITH_XSLT_DEBUG 06008 xsltGenericDebug(xsltGenericDebugContext, 06009 "reusing transformation dict for output\n"); 06010 #endif 06011 } 06012 res->charset = XML_CHAR_ENCODING_UTF8; 06013 if (encoding != NULL) 06014 res->encoding = xmlStrdup(encoding); 06015 variables = style->variables; 06016 06017 /* 06018 * Start the evaluation, evaluate the params, the stylesheets globals 06019 * and start by processing the top node. 06020 */ 06021 if (xsltNeedElemSpaceHandling(ctxt)) 06022 xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); 06023 /* 06024 * Evaluate global params and user-provided params. 06025 */ 06026 ctxt->node = (xmlNodePtr) doc; 06027 if (ctxt->globalVars == NULL) 06028 ctxt->globalVars = xmlHashCreate(20); 06029 if (params != NULL) { 06030 xsltEvalUserParams(ctxt, params); 06031 } 06032 06033 /* need to be called before evaluating global variables */ 06034 xsltCountKeys(ctxt); 06035 06036 xsltEvalGlobalVariables(ctxt); 06037 06038 ctxt->node = (xmlNodePtr) doc; 06039 ctxt->output = res; 06040 ctxt->insert = (xmlNodePtr) res; 06041 ctxt->varsBase = ctxt->varsNr - 1; 06042 06043 ctxt->xpathCtxt->contextSize = 1; 06044 ctxt->xpathCtxt->proximityPosition = 1; 06045 ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */ 06046 /* 06047 * Start processing the source tree ----------------------------------- 06048 */ 06049 xsltProcessOneNode(ctxt, ctxt->node, NULL); 06050 /* 06051 * Remove all remaining vars from the stack. 06052 */ 06053 xsltLocalVariablePop(ctxt, 0, -2); 06054 xsltShutdownCtxtExts(ctxt); 06055 06056 xsltCleanupTemplates(style); /* TODO: <- style should be read only */ 06057 06058 /* 06059 * Now cleanup our variables so stylesheet can be re-used 06060 * 06061 * TODO: this is not needed anymore global variables are copied 06062 * and not evaluated directly anymore, keep this as a check 06063 */ 06064 if (style->variables != variables) { 06065 vptr = style->variables; 06066 while (vptr->next != variables) 06067 vptr = vptr->next; 06068 vptr->next = NULL; 06069 xsltFreeStackElemList(style->variables); 06070 style->variables = variables; 06071 } 06072 vptr = style->variables; 06073 while (vptr != NULL) { 06074 if (vptr->computed) { 06075 if (vptr->value != NULL) { 06076 xmlXPathFreeObject(vptr->value); 06077 vptr->value = NULL; 06078 vptr->computed = 0; 06079 } 06080 } 06081 vptr = vptr->next; 06082 } 06083 #if 0 06084 /* 06085 * code disabled by wmb; awaiting kb's review 06086 * problem is that global variable(s) may contain xpath objects 06087 * from doc associated with RVT, so can't be freed at this point. 06088 * xsltFreeTransformContext includes a call to xsltFreeRVTs, so 06089 * I assume this shouldn't be required at this point. 06090 */ 06091 /* 06092 * Free all remaining tree fragments. 06093 */ 06094 xsltFreeRVTs(ctxt); 06095 #endif 06096 /* 06097 * Do some post processing work depending on the generated output 06098 */ 06099 root = xmlDocGetRootElement(res); 06100 if (root != NULL) { 06101 const xmlChar *doctype = NULL; 06102 06103 if ((root->ns != NULL) && (root->ns->prefix != NULL)) 06104 doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); 06105 if (doctype == NULL) 06106 doctype = root->name; 06107 06108 /* 06109 * Apply the default selection of the method 06110 */ 06111 if ((method == NULL) && 06112 (root->ns == NULL) && 06113 (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { 06114 xmlNodePtr tmp; 06115 06116 tmp = res->children; 06117 while ((tmp != NULL) && (tmp != root)) { 06118 if (tmp->type == XML_ELEMENT_NODE) 06119 break; 06120 if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) 06121 break; 06122 tmp = tmp->next; 06123 } 06124 if (tmp == root) { 06125 ctxt->type = XSLT_OUTPUT_HTML; 06126 /* 06127 * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the 06128 * transformation on the doc, but functions like 06129 */ 06130 res->type = XML_HTML_DOCUMENT_NODE; 06131 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 06132 res->intSubset = xmlCreateIntSubset(res, doctype, 06133 doctypePublic, 06134 doctypeSystem); 06135 #ifdef XSLT_GENERATE_HTML_DOCTYPE 06136 } else if (version != NULL) { 06137 xsltGetHTMLIDs(version, &doctypePublic, 06138 &doctypeSystem); 06139 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) 06140 res->intSubset = 06141 xmlCreateIntSubset(res, doctype, 06142 doctypePublic, 06143 doctypeSystem); 06144 #endif 06145 } 06146 } 06147 06148 } 06149 if (ctxt->type == XSLT_OUTPUT_XML) { 06150 XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) 06151 XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) 06152 if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { 06153 xmlNodePtr last; 06154 /* Need a small "hack" here to assure DTD comes before 06155 possible comment nodes */ 06156 node = res->children; 06157 last = res->last; 06158 res->children = NULL; 06159 res->last = NULL; 06160 res->intSubset = xmlCreateIntSubset(res, doctype, 06161 doctypePublic, 06162 doctypeSystem); 06163 if (res->children != NULL) { 06164 res->children->next = node; 06165 node->prev = res->children; 06166 res->last = last; 06167 } else { 06168 res->children = node; 06169 res->last = last; 06170 } 06171 } 06172 } 06173 } 06174 xmlXPathFreeNodeSet(ctxt->nodeList); 06175 if (profile != NULL) { 06176 xsltSaveProfiling(ctxt, profile); 06177 } 06178 06179 /* 06180 * Be pedantic. 06181 */ 06182 if ((ctxt != NULL) && (ctxt->state == XSLT_STATE_ERROR)) { 06183 xmlFreeDoc(res); 06184 res = NULL; 06185 } 06186 if ((res != NULL) && (ctxt != NULL) && (output != NULL)) { 06187 int ret; 06188 06189 ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output); 06190 if (ret == 0) { 06191 xsltTransformError(ctxt, NULL, NULL, 06192 "xsltApplyStylesheet: forbidden to save to %s\n", 06193 output); 06194 } else if (ret < 0) { 06195 xsltTransformError(ctxt, NULL, NULL, 06196 "xsltApplyStylesheet: saving to %s may not be possible\n", 06197 output); 06198 } 06199 } 06200 06201 #ifdef XSLT_DEBUG_PROFILE_CACHE 06202 printf("# Cache:\n"); 06203 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); 06204 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); 06205 #endif 06206 06207 if ((ctxt != NULL) && (userCtxt == NULL)) 06208 xsltFreeTransformContext(ctxt); 06209 06210 return (res); 06211 06212 error: 06213 if (res != NULL) 06214 xmlFreeDoc(res); 06215 06216 #ifdef XSLT_DEBUG_PROFILE_CACHE 06217 printf("# Cache:\n"); 06218 printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); 06219 printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); 06220 #endif 06221 06222 if ((ctxt != NULL) && (userCtxt == NULL)) 06223 xsltFreeTransformContext(ctxt); 06224 return (NULL); 06225 } 06226 06238 xmlDocPtr 06239 xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, 06240 const char **params) 06241 { 06242 return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL)); 06243 } 06244 06257 xmlDocPtr 06258 xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, 06259 const char **params, FILE * output) 06260 { 06261 xmlDocPtr res; 06262 06263 res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL); 06264 return (res); 06265 } 06266 06281 xmlDocPtr 06282 xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, 06283 const char **params, const char *output, 06284 FILE * profile, xsltTransformContextPtr userCtxt) 06285 { 06286 xmlDocPtr res; 06287 06288 res = xsltApplyStylesheetInternal(style, doc, params, output, 06289 profile, userCtxt); 06290 return (res); 06291 } 06292 06319 int 06320 xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, 06321 const char **params, const char *output, 06322 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf, 06323 FILE * profile, xsltTransformContextPtr userCtxt) 06324 { 06325 xmlDocPtr tmp; 06326 int ret; 06327 06328 if ((output == NULL) && (SAX == NULL) && (IObuf == NULL)) 06329 return (-1); 06330 if ((SAX != NULL) && (IObuf != NULL)) 06331 return (-1); 06332 06333 /* unsupported yet */ 06334 if (SAX != NULL) { 06335 XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */ 06336 return (-1); 06337 } 06338 06339 tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile, 06340 userCtxt); 06341 if (tmp == NULL) { 06342 xsltTransformError(NULL, NULL, (xmlNodePtr) doc, 06343 "xsltRunStylesheet : run failed\n"); 06344 return (-1); 06345 } 06346 if (IObuf != NULL) { 06347 /* TODO: incomplete, IObuf output not progressive */ 06348 ret = xsltSaveResultTo(IObuf, tmp, style); 06349 } else { 06350 ret = xsltSaveResultToFilename(output, tmp, style, 0); 06351 } 06352 xmlFreeDoc(tmp); 06353 return (ret); 06354 } 06355 06380 int 06381 xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, 06382 const char **params, const char *output, 06383 xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf) 06384 { 06385 return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf, 06386 NULL, NULL)); 06387 } 06388 06395 void 06396 xsltRegisterAllElement(xsltTransformContextPtr ctxt) 06397 { 06398 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates", 06399 XSLT_NAMESPACE, 06400 (xsltTransformFunction) xsltApplyTemplates); 06401 xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports", 06402 XSLT_NAMESPACE, 06403 (xsltTransformFunction) xsltApplyImports); 06404 xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template", 06405 XSLT_NAMESPACE, 06406 (xsltTransformFunction) xsltCallTemplate); 06407 xsltRegisterExtElement(ctxt, (const xmlChar *) "element", 06408 XSLT_NAMESPACE, 06409 (xsltTransformFunction) xsltElement); 06410 xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute", 06411 XSLT_NAMESPACE, 06412 (xsltTransformFunction) xsltAttribute); 06413 xsltRegisterExtElement(ctxt, (const xmlChar *) "text", 06414 XSLT_NAMESPACE, 06415 (xsltTransformFunction) xsltText); 06416 xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction", 06417 XSLT_NAMESPACE, 06418 (xsltTransformFunction) xsltProcessingInstruction); 06419 xsltRegisterExtElement(ctxt, (const xmlChar *) "comment", 06420 XSLT_NAMESPACE, 06421 (xsltTransformFunction) xsltComment); 06422 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy", 06423 XSLT_NAMESPACE, 06424 (xsltTransformFunction) xsltCopy); 06425 xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of", 06426 XSLT_NAMESPACE, 06427 (xsltTransformFunction) xsltValueOf); 06428 xsltRegisterExtElement(ctxt, (const xmlChar *) "number", 06429 XSLT_NAMESPACE, 06430 (xsltTransformFunction) xsltNumber); 06431 xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each", 06432 XSLT_NAMESPACE, 06433 (xsltTransformFunction) xsltForEach); 06434 xsltRegisterExtElement(ctxt, (const xmlChar *) "if", 06435 XSLT_NAMESPACE, 06436 (xsltTransformFunction) xsltIf); 06437 xsltRegisterExtElement(ctxt, (const xmlChar *) "choose", 06438 XSLT_NAMESPACE, 06439 (xsltTransformFunction) xsltChoose); 06440 xsltRegisterExtElement(ctxt, (const xmlChar *) "sort", 06441 XSLT_NAMESPACE, 06442 (xsltTransformFunction) xsltSort); 06443 xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of", 06444 XSLT_NAMESPACE, 06445 (xsltTransformFunction) xsltCopyOf); 06446 xsltRegisterExtElement(ctxt, (const xmlChar *) "message", 06447 XSLT_NAMESPACE, 06448 (xsltTransformFunction) xsltMessage); 06449 06450 /* 06451 * Those don't have callable entry points but are registered anyway 06452 */ 06453 xsltRegisterExtElement(ctxt, (const xmlChar *) "variable", 06454 XSLT_NAMESPACE, 06455 (xsltTransformFunction) xsltDebug); 06456 xsltRegisterExtElement(ctxt, (const xmlChar *) "param", 06457 XSLT_NAMESPACE, 06458 (xsltTransformFunction) xsltDebug); 06459 xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param", 06460 XSLT_NAMESPACE, 06461 (xsltTransformFunction) xsltDebug); 06462 xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format", 06463 XSLT_NAMESPACE, 06464 (xsltTransformFunction) xsltDebug); 06465 xsltRegisterExtElement(ctxt, (const xmlChar *) "when", 06466 XSLT_NAMESPACE, 06467 (xsltTransformFunction) xsltDebug); 06468 xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise", 06469 XSLT_NAMESPACE, 06470 (xsltTransformFunction) xsltDebug); 06471 xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback", 06472 XSLT_NAMESPACE, 06473 (xsltTransformFunction) xsltDebug); 06474 06475 } Generated on Fri May 25 2012 04:17:47 for ReactOS by
1.7.6.1
|