ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

transform.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.