Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenxsltutils.c
Go to the documentation of this file.
00001 /* 00002 * xsltutils.c: Utilities for the XSL Transformation 1.0 engine 00003 * 00004 * Reference: 00005 * http://www.w3.org/TR/1999/REC-xslt-19991116 00006 * 00007 * See Copyright for the status of this software. 00008 * 00009 * daniel@veillard.com 00010 */ 00011 00012 #define IN_LIBXSLT 00013 #include "libxslt.h" 00014 00015 #ifndef XSLT_NEED_TRIO 00016 #include <stdio.h> 00017 #else 00018 #include <trio.h> 00019 #endif 00020 00021 #include <string.h> 00022 #ifdef HAVE_SYS_TIME_H 00023 #include <sys/time.h> 00024 #endif 00025 #ifdef HAVE_UNISTD_H 00026 #include <unistd.h> 00027 #endif 00028 #ifdef HAVE_STDLIB_H 00029 #include <stdlib.h> 00030 #endif 00031 #include <stdarg.h> 00032 00033 #include <libxml/xmlmemory.h> 00034 #include <libxml/tree.h> 00035 #include <libxml/HTMLtree.h> 00036 #include <libxml/xmlerror.h> 00037 #include <libxml/xmlIO.h> 00038 #include "xsltutils.h" 00039 #include "templates.h" 00040 #include "xsltInternals.h" 00041 #include "imports.h" 00042 #include "transform.h" 00043 00044 /* gettimeofday on Windows ??? */ 00045 #if defined(WIN32) && !defined(__CYGWIN__) 00046 #ifdef _MSC_VER 00047 #include <winsock2.h> 00048 #pragma comment(lib, "ws2_32.lib") 00049 #define gettimeofday(p1,p2) 00050 #define HAVE_GETTIMEOFDAY 00051 #define XSLT_WIN32_PERFORMANCE_COUNTER 00052 #endif /* _MS_VER */ 00053 #endif /* WIN32 */ 00054 00055 /************************************************************************ 00056 * * 00057 * Convenience function * 00058 * * 00059 ************************************************************************/ 00060 00081 const xmlChar * 00082 xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node, 00083 const xmlChar *name, const xmlChar *nameSpace) { 00084 xmlAttrPtr prop; 00085 xmlDocPtr doc; 00086 xmlNsPtr ns; 00087 xmlChar *tmp; 00088 const xmlChar *ret; 00089 00090 if ((node == NULL) || (style == NULL) || (style->dict == NULL)) 00091 return(NULL); 00092 00093 prop = node->properties; 00094 if (nameSpace == NULL) { 00095 return xmlGetProp(node, name); 00096 } 00097 while (prop != NULL) { 00098 /* 00099 * One need to have 00100 * - same attribute names 00101 * - and the attribute carrying that namespace 00102 */ 00103 if ((xmlStrEqual(prop->name, name)) && 00104 (((prop->ns == NULL) && (node->ns != NULL) && 00105 (xmlStrEqual(node->ns->href, nameSpace))) || 00106 ((prop->ns != NULL) && 00107 (xmlStrEqual(prop->ns->href, nameSpace))))) { 00108 00109 tmp = xmlNodeListGetString(node->doc, prop->children, 1); 00110 if (tmp == NULL) 00111 ret = xmlDictLookup(style->dict, BAD_CAST "", 0); 00112 else { 00113 ret = xmlDictLookup(style->dict, tmp, -1); 00114 xmlFree(tmp); 00115 } 00116 return ret; 00117 } 00118 prop = prop->next; 00119 } 00120 tmp = NULL; 00121 /* 00122 * Check if there is a default declaration in the internal 00123 * or external subsets 00124 */ 00125 doc = node->doc; 00126 if (doc != NULL) { 00127 if (doc->intSubset != NULL) { 00128 xmlAttributePtr attrDecl; 00129 00130 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); 00131 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 00132 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); 00133 00134 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) { 00135 /* 00136 * The DTD declaration only allows a prefix search 00137 */ 00138 ns = xmlSearchNs(doc, node, attrDecl->prefix); 00139 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace))) 00140 return(xmlDictLookup(style->dict, 00141 attrDecl->defaultValue, -1)); 00142 } 00143 } 00144 } 00145 return(NULL); 00146 } 00166 xmlChar * 00167 xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { 00168 xmlAttrPtr prop; 00169 xmlDocPtr doc; 00170 xmlNsPtr ns; 00171 00172 if (node == NULL) 00173 return(NULL); 00174 00175 prop = node->properties; 00176 /* 00177 * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former 00178 * is not namespace-aware and will return an attribute with equal 00179 * name regardless of its namespace. 00180 * Example: 00181 * <xsl:element foo:name="myName"/> 00182 * So this would return "myName" even if an attribute @name 00183 * in the XSLT was requested. 00184 */ 00185 if (nameSpace == NULL) 00186 return(xmlGetProp(node, name)); 00187 while (prop != NULL) { 00188 /* 00189 * One need to have 00190 * - same attribute names 00191 * - and the attribute carrying that namespace 00192 */ 00193 if ((xmlStrEqual(prop->name, name)) && 00194 (((prop->ns == NULL) && (node->ns != NULL) && 00195 (xmlStrEqual(node->ns->href, nameSpace))) || 00196 ((prop->ns != NULL) && 00197 (xmlStrEqual(prop->ns->href, nameSpace))))) { 00198 xmlChar *ret; 00199 00200 ret = xmlNodeListGetString(node->doc, prop->children, 1); 00201 if (ret == NULL) return(xmlStrdup((xmlChar *)"")); 00202 return(ret); 00203 } 00204 prop = prop->next; 00205 } 00206 00207 /* 00208 * Check if there is a default declaration in the internal 00209 * or external subsets 00210 */ 00211 doc = node->doc; 00212 if (doc != NULL) { 00213 if (doc->intSubset != NULL) { 00214 xmlAttributePtr attrDecl; 00215 00216 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); 00217 if ((attrDecl == NULL) && (doc->extSubset != NULL)) 00218 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); 00219 00220 if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) { 00221 /* 00222 * The DTD declaration only allows a prefix search 00223 */ 00224 ns = xmlSearchNs(doc, node, attrDecl->prefix); 00225 if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace))) 00226 return(xmlStrdup(attrDecl->defaultValue)); 00227 } 00228 } 00229 } 00230 return(NULL); 00231 } 00232 00245 int 00246 xsltGetUTF8Char(const unsigned char *utf, int *len) { 00247 unsigned int c; 00248 00249 if (utf == NULL) 00250 goto error; 00251 if (len == NULL) 00252 goto error; 00253 if (*len < 1) 00254 goto error; 00255 00256 c = utf[0]; 00257 if (c & 0x80) { 00258 if (*len < 2) 00259 goto error; 00260 if ((utf[1] & 0xc0) != 0x80) 00261 goto error; 00262 if ((c & 0xe0) == 0xe0) { 00263 if (*len < 3) 00264 goto error; 00265 if ((utf[2] & 0xc0) != 0x80) 00266 goto error; 00267 if ((c & 0xf0) == 0xf0) { 00268 if (*len < 4) 00269 goto error; 00270 if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) 00271 goto error; 00272 *len = 4; 00273 /* 4-byte code */ 00274 c = (utf[0] & 0x7) << 18; 00275 c |= (utf[1] & 0x3f) << 12; 00276 c |= (utf[2] & 0x3f) << 6; 00277 c |= utf[3] & 0x3f; 00278 } else { 00279 /* 3-byte code */ 00280 *len = 3; 00281 c = (utf[0] & 0xf) << 12; 00282 c |= (utf[1] & 0x3f) << 6; 00283 c |= utf[2] & 0x3f; 00284 } 00285 } else { 00286 /* 2-byte code */ 00287 *len = 2; 00288 c = (utf[0] & 0x1f) << 6; 00289 c |= utf[1] & 0x3f; 00290 } 00291 } else { 00292 /* 1-byte code */ 00293 *len = 1; 00294 } 00295 return(c); 00296 00297 error: 00298 if (len != NULL) 00299 *len = 0; 00300 return(-1); 00301 } 00302 00303 #ifdef XSLT_REFACTORED 00304 00316 int 00317 xsltPointerListAddSize(xsltPointerListPtr list, 00318 void *item, 00319 int initialSize) 00320 { 00321 if (list->items == NULL) { 00322 if (initialSize <= 0) 00323 initialSize = 1; 00324 list->items = (void **) xmlMalloc( 00325 initialSize * sizeof(void *)); 00326 if (list->items == NULL) { 00327 xsltGenericError(xsltGenericErrorContext, 00328 "xsltPointerListAddSize: memory allocation failure.\n"); 00329 return(-1); 00330 } 00331 list->number = 0; 00332 list->size = initialSize; 00333 } else if (list->size <= list->number) { 00334 list->size *= 2; 00335 list->items = (void **) xmlRealloc(list->items, 00336 list->size * sizeof(void *)); 00337 if (list->items == NULL) { 00338 xsltGenericError(xsltGenericErrorContext, 00339 "xsltPointerListAddSize: memory re-allocation failure.\n"); 00340 list->size = 0; 00341 return(-1); 00342 } 00343 } 00344 list->items[list->number++] = item; 00345 return(0); 00346 } 00347 00356 xsltPointerListPtr 00357 xsltPointerListCreate(int initialSize) 00358 { 00359 xsltPointerListPtr ret; 00360 00361 ret = xmlMalloc(sizeof(xsltPointerList)); 00362 if (ret == NULL) { 00363 xsltGenericError(xsltGenericErrorContext, 00364 "xsltPointerListCreate: memory allocation failure.\n"); 00365 return (NULL); 00366 } 00367 memset(ret, 0, sizeof(xsltPointerList)); 00368 if (initialSize > 0) { 00369 xsltPointerListAddSize(ret, NULL, initialSize); 00370 ret->number = 0; 00371 } 00372 return (ret); 00373 } 00374 00382 void 00383 xsltPointerListFree(xsltPointerListPtr list) 00384 { 00385 if (list == NULL) 00386 return; 00387 if (list->items != NULL) 00388 xmlFree(list->items); 00389 xmlFree(list); 00390 } 00391 00399 void 00400 xsltPointerListClear(xsltPointerListPtr list) 00401 { 00402 if (list->items != NULL) { 00403 xmlFree(list->items); 00404 list->items = NULL; 00405 } 00406 list->number = 0; 00407 list->size = 0; 00408 } 00409 00410 #endif /* XSLT_REFACTORED */ 00411 00412 /************************************************************************ 00413 * * 00414 * Handling of XSLT stylesheets messages * 00415 * * 00416 ************************************************************************/ 00417 00426 void 00427 xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) { 00428 xmlGenericErrorFunc error = xsltGenericError; 00429 void *errctx = xsltGenericErrorContext; 00430 xmlChar *prop, *message; 00431 int terminate = 0; 00432 00433 if ((ctxt == NULL) || (inst == NULL)) 00434 return; 00435 00436 if (ctxt->error != NULL) { 00437 error = ctxt->error; 00438 errctx = ctxt->errctx; 00439 } 00440 00441 prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL); 00442 if (prop != NULL) { 00443 if (xmlStrEqual(prop, (const xmlChar *)"yes")) { 00444 terminate = 1; 00445 } else if (xmlStrEqual(prop, (const xmlChar *)"no")) { 00446 terminate = 0; 00447 } else { 00448 error(errctx, 00449 "xsl:message : terminate expecting 'yes' or 'no'\n"); 00450 ctxt->state = XSLT_STATE_ERROR; 00451 } 00452 xmlFree(prop); 00453 } 00454 message = xsltEvalTemplateString(ctxt, node, inst); 00455 if (message != NULL) { 00456 int len = xmlStrlen(message); 00457 00458 error(errctx, "%s", (const char *)message); 00459 if ((len > 0) && (message[len - 1] != '\n')) 00460 error(errctx, "\n"); 00461 xmlFree(message); 00462 } 00463 if (terminate) 00464 ctxt->state = XSLT_STATE_STOPPED; 00465 } 00466 00467 /************************************************************************ 00468 * * 00469 * Handling of out of context errors * 00470 * * 00471 ************************************************************************/ 00472 00473 #define XSLT_GET_VAR_STR(msg, str) { \ 00474 int size; \ 00475 int chars; \ 00476 char *larger; \ 00477 va_list ap; \ 00478 \ 00479 str = (char *) xmlMalloc(150); \ 00480 if (str == NULL) \ 00481 return; \ 00482 \ 00483 size = 150; \ 00484 \ 00485 while (size < 64000) { \ 00486 va_start(ap, msg); \ 00487 chars = vsnprintf(str, size, msg, ap); \ 00488 va_end(ap); \ 00489 if ((chars > -1) && (chars < size)) \ 00490 break; \ 00491 if (chars > -1) \ 00492 size += chars + 1; \ 00493 else \ 00494 size += 100; \ 00495 if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\ 00496 xmlFree(str); \ 00497 return; \ 00498 } \ 00499 str = larger; \ 00500 } \ 00501 } 00502 00510 static void 00511 xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { 00512 va_list args; 00513 00514 if (xsltGenericErrorContext == NULL) 00515 xsltGenericErrorContext = (void *) stderr; 00516 00517 va_start(args, msg); 00518 vfprintf((FILE *)xsltGenericErrorContext, msg, args); 00519 va_end(args); 00520 } 00521 00522 xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc; 00523 void *xsltGenericErrorContext = NULL; 00524 00525 00539 void 00540 xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { 00541 xsltGenericErrorContext = ctx; 00542 if (handler != NULL) 00543 xsltGenericError = handler; 00544 else 00545 xsltGenericError = xsltGenericErrorDefaultFunc; 00546 } 00547 00556 static void 00557 xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { 00558 va_list args; 00559 00560 if (xsltGenericDebugContext == NULL) 00561 return; 00562 00563 va_start(args, msg); 00564 vfprintf((FILE *)xsltGenericDebugContext, msg, args); 00565 va_end(args); 00566 } 00567 00568 xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc; 00569 void *xsltGenericDebugContext = NULL; 00570 00571 00585 void 00586 xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) { 00587 xsltGenericDebugContext = ctx; 00588 if (handler != NULL) 00589 xsltGenericDebug = handler; 00590 else 00591 xsltGenericDebug = xsltGenericDebugDefaultFunc; 00592 } 00593 00602 void 00603 xsltPrintErrorContext(xsltTransformContextPtr ctxt, 00604 xsltStylesheetPtr style, xmlNodePtr node) { 00605 int line = 0; 00606 const xmlChar *file = NULL; 00607 const xmlChar *name = NULL; 00608 const char *type = "error"; 00609 xmlGenericErrorFunc error = xsltGenericError; 00610 void *errctx = xsltGenericErrorContext; 00611 00612 if (ctxt != NULL) { 00613 ctxt->state = XSLT_STATE_ERROR; 00614 if (ctxt->error != NULL) { 00615 error = ctxt->error; 00616 errctx = ctxt->errctx; 00617 } 00618 } 00619 if ((node == NULL) && (ctxt != NULL)) 00620 node = ctxt->inst; 00621 00622 if (node != NULL) { 00623 if ((node->type == XML_DOCUMENT_NODE) || 00624 (node->type == XML_HTML_DOCUMENT_NODE)) { 00625 xmlDocPtr doc = (xmlDocPtr) node; 00626 00627 file = doc->URL; 00628 } else { 00629 line = xmlGetLineNo(node); 00630 if ((node->doc != NULL) && (node->doc->URL != NULL)) 00631 file = node->doc->URL; 00632 if (node->name != NULL) 00633 name = node->name; 00634 } 00635 } 00636 00637 if (ctxt != NULL) 00638 type = "runtime error"; 00639 else if (style != NULL) { 00640 #ifdef XSLT_REFACTORED 00641 if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING) 00642 type = "compilation warning"; 00643 else 00644 type = "compilation error"; 00645 #else 00646 type = "compilation error"; 00647 #endif 00648 } 00649 00650 if ((file != NULL) && (line != 0) && (name != NULL)) 00651 error(errctx, "%s: file %s line %d element %s\n", 00652 type, file, line, name); 00653 else if ((file != NULL) && (name != NULL)) 00654 error(errctx, "%s: file %s element %s\n", type, file, name); 00655 else if ((file != NULL) && (line != 0)) 00656 error(errctx, "%s: file %s line %d\n", type, file, line); 00657 else if (file != NULL) 00658 error(errctx, "%s: file %s\n", type, file); 00659 else if (name != NULL) 00660 error(errctx, "%s: element %s\n", type, name); 00661 else 00662 error(errctx, "%s\n", type); 00663 } 00664 00677 void 00678 xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt, 00679 void *ctx, xmlGenericErrorFunc handler) 00680 { 00681 ctxt->error = handler; 00682 ctxt->errctx = ctx; 00683 } 00684 00696 void 00697 xsltTransformError(xsltTransformContextPtr ctxt, 00698 xsltStylesheetPtr style, 00699 xmlNodePtr node, 00700 const char *msg, ...) { 00701 xmlGenericErrorFunc error = xsltGenericError; 00702 void *errctx = xsltGenericErrorContext; 00703 char * str; 00704 00705 if (ctxt != NULL) { 00706 ctxt->state = XSLT_STATE_ERROR; 00707 if (ctxt->error != NULL) { 00708 error = ctxt->error; 00709 errctx = ctxt->errctx; 00710 } 00711 } 00712 if ((node == NULL) && (ctxt != NULL)) 00713 node = ctxt->inst; 00714 xsltPrintErrorContext(ctxt, style, node); 00715 XSLT_GET_VAR_STR(msg, str); 00716 error(errctx, "%s", str); 00717 if (str != NULL) 00718 xmlFree(str); 00719 } 00720 00721 /************************************************************************ 00722 * * 00723 * QNames * 00724 * * 00725 ************************************************************************/ 00726 00737 const xmlChar * 00738 xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) { 00739 int len = 0; 00740 const xmlChar *ret = NULL; 00741 00742 *prefix = NULL; 00743 if ((name == NULL) || (dict == NULL)) return(NULL); 00744 if (name[0] == ':') 00745 return(xmlDictLookup(dict, name, -1)); 00746 while ((name[len] != 0) && (name[len] != ':')) len++; 00747 if (name[len] == 0) return(xmlDictLookup(dict, name, -1)); 00748 *prefix = xmlDictLookup(dict, name, len); 00749 ret = xmlDictLookup(dict, &name[len + 1], -1); 00750 return(ret); 00751 } 00752 00770 const xmlChar * 00771 xsltGetQNameURI(xmlNodePtr node, xmlChar ** name) 00772 { 00773 int len = 0; 00774 xmlChar *qname; 00775 xmlNsPtr ns; 00776 00777 if (name == NULL) 00778 return(NULL); 00779 qname = *name; 00780 if ((qname == NULL) || (*qname == 0)) 00781 return(NULL); 00782 if (node == NULL) { 00783 xsltGenericError(xsltGenericErrorContext, 00784 "QName: no element for namespace lookup %s\n", 00785 qname); 00786 xmlFree(qname); 00787 *name = NULL; 00788 return(NULL); 00789 } 00790 00791 /* nasty but valid */ 00792 if (qname[0] == ':') 00793 return(NULL); 00794 00795 /* 00796 * we are not trying to validate but just to cut, and yes it will 00797 * work even if this is a set of UTF-8 encoded chars 00798 */ 00799 while ((qname[len] != 0) && (qname[len] != ':')) 00800 len++; 00801 00802 if (qname[len] == 0) 00803 return(NULL); 00804 00805 /* 00806 * handle xml: separately, this one is magical 00807 */ 00808 if ((qname[0] == 'x') && (qname[1] == 'm') && 00809 (qname[2] == 'l') && (qname[3] == ':')) { 00810 if (qname[4] == 0) 00811 return(NULL); 00812 *name = xmlStrdup(&qname[4]); 00813 xmlFree(qname); 00814 return(XML_XML_NAMESPACE); 00815 } 00816 00817 qname[len] = 0; 00818 ns = xmlSearchNs(node->doc, node, qname); 00819 if (ns == NULL) { 00820 xsltGenericError(xsltGenericErrorContext, 00821 "%s:%s : no namespace bound to prefix %s\n", 00822 qname, &qname[len + 1], qname); 00823 *name = NULL; 00824 xmlFree(qname); 00825 return(NULL); 00826 } 00827 *name = xmlStrdup(&qname[len + 1]); 00828 xmlFree(qname); 00829 return(ns->href); 00830 } 00831 00844 const xmlChar * 00845 xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node, 00846 const xmlChar **name) { 00847 int len = 0; 00848 xmlChar *qname; 00849 xmlNsPtr ns; 00850 00851 if (name == NULL) 00852 return(NULL); 00853 qname = (xmlChar *)*name; 00854 if ((qname == NULL) || (*qname == 0)) 00855 return(NULL); 00856 if (node == NULL) { 00857 xsltGenericError(xsltGenericErrorContext, 00858 "QName: no element for namespace lookup %s\n", 00859 qname); 00860 *name = NULL; 00861 return(NULL); 00862 } 00863 00864 /* 00865 * we are not trying to validate but just to cut, and yes it will 00866 * work even if this is a set of UTF-8 encoded chars 00867 */ 00868 while ((qname[len] != 0) && (qname[len] != ':')) 00869 len++; 00870 00871 if (qname[len] == 0) 00872 return(NULL); 00873 00874 /* 00875 * handle xml: separately, this one is magical 00876 */ 00877 if ((qname[0] == 'x') && (qname[1] == 'm') && 00878 (qname[2] == 'l') && (qname[3] == ':')) { 00879 if (qname[4] == 0) 00880 return(NULL); 00881 *name = xmlDictLookup(style->dict, &qname[4], -1); 00882 return(XML_XML_NAMESPACE); 00883 } 00884 00885 qname = xmlStrndup(*name, len); 00886 ns = xmlSearchNs(node->doc, node, qname); 00887 if (ns == NULL) { 00888 if (style) { 00889 xsltTransformError(NULL, style, node, 00890 "No namespace bound to prefix '%s'.\n", 00891 qname); 00892 style->errors++; 00893 } else { 00894 xsltGenericError(xsltGenericErrorContext, 00895 "%s : no namespace bound to prefix %s\n", 00896 *name, qname); 00897 } 00898 *name = NULL; 00899 xmlFree(qname); 00900 return(NULL); 00901 } 00902 *name = xmlDictLookup(style->dict, (*name)+len+1, -1); 00903 xmlFree(qname); 00904 return(ns->href); 00905 } 00906 00907 /************************************************************************ 00908 * * 00909 * Sorting * 00910 * * 00911 ************************************************************************/ 00912 00920 void 00921 xsltDocumentSortFunction(xmlNodeSetPtr list) { 00922 int i, j; 00923 int len, tst; 00924 xmlNodePtr node; 00925 00926 if (list == NULL) 00927 return; 00928 len = list->nodeNr; 00929 if (len <= 1) 00930 return; 00931 /* TODO: sort is really not optimized, does it needs to ? */ 00932 for (i = 0;i < len -1;i++) { 00933 for (j = i + 1; j < len; j++) { 00934 tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]); 00935 if (tst == -1) { 00936 node = list->nodeTab[i]; 00937 list->nodeTab[i] = list->nodeTab[j]; 00938 list->nodeTab[j] = node; 00939 } 00940 } 00941 } 00942 } 00943 00954 xmlXPathObjectPtr * 00955 xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) { 00956 #ifdef XSLT_REFACTORED 00957 xsltStyleItemSortPtr comp; 00958 #else 00959 xsltStylePreCompPtr comp; 00960 #endif 00961 xmlXPathObjectPtr *results = NULL; 00962 xmlNodeSetPtr list = NULL; 00963 xmlXPathObjectPtr res; 00964 int len = 0; 00965 int i; 00966 xmlNodePtr oldNode; 00967 xmlNodePtr oldInst; 00968 int oldPos, oldSize ; 00969 int oldNsNr; 00970 xmlNsPtr *oldNamespaces; 00971 00972 comp = sort->psvi; 00973 if (comp == NULL) { 00974 xsltGenericError(xsltGenericErrorContext, 00975 "xsl:sort : compilation failed\n"); 00976 return(NULL); 00977 } 00978 00979 if ((comp->select == NULL) || (comp->comp == NULL)) 00980 return(NULL); 00981 00982 list = ctxt->nodeList; 00983 if ((list == NULL) || (list->nodeNr <= 1)) 00984 return(NULL); 00985 00986 len = list->nodeNr; 00987 00988 /* TODO: xsl:sort lang attribute */ 00989 /* TODO: xsl:sort case-order attribute */ 00990 00991 00992 results = xmlMalloc(len * sizeof(xmlXPathObjectPtr)); 00993 if (results == NULL) { 00994 xsltGenericError(xsltGenericErrorContext, 00995 "xsltComputeSortResult: memory allocation failure\n"); 00996 return(NULL); 00997 } 00998 00999 oldNode = ctxt->node; 01000 oldInst = ctxt->inst; 01001 oldPos = ctxt->xpathCtxt->proximityPosition; 01002 oldSize = ctxt->xpathCtxt->contextSize; 01003 oldNsNr = ctxt->xpathCtxt->nsNr; 01004 oldNamespaces = ctxt->xpathCtxt->namespaces; 01005 for (i = 0;i < len;i++) { 01006 ctxt->inst = sort; 01007 ctxt->xpathCtxt->contextSize = len; 01008 ctxt->xpathCtxt->proximityPosition = i + 1; 01009 ctxt->node = list->nodeTab[i]; 01010 ctxt->xpathCtxt->node = ctxt->node; 01011 #ifdef XSLT_REFACTORED 01012 if (comp->inScopeNs != NULL) { 01013 ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; 01014 ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber; 01015 } else { 01016 ctxt->xpathCtxt->namespaces = NULL; 01017 ctxt->xpathCtxt->nsNr = 0; 01018 } 01019 #else 01020 ctxt->xpathCtxt->namespaces = comp->nsList; 01021 ctxt->xpathCtxt->nsNr = comp->nsNr; 01022 #endif 01023 res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt); 01024 if (res != NULL) { 01025 if (res->type != XPATH_STRING) 01026 res = xmlXPathConvertString(res); 01027 if (comp->number) 01028 res = xmlXPathConvertNumber(res); 01029 res->index = i; /* Save original pos for dupl resolv */ 01030 if (comp->number) { 01031 if (res->type == XPATH_NUMBER) { 01032 results[i] = res; 01033 } else { 01034 #ifdef WITH_XSLT_DEBUG_PROCESS 01035 xsltGenericDebug(xsltGenericDebugContext, 01036 "xsltComputeSortResult: select didn't evaluate to a number\n"); 01037 #endif 01038 results[i] = NULL; 01039 } 01040 } else { 01041 if (res->type == XPATH_STRING) { 01042 if (comp->locale != (xsltLocale)0) { 01043 xmlChar *str = res->stringval; 01044 res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str); 01045 xmlFree(str); 01046 } 01047 01048 results[i] = res; 01049 } else { 01050 #ifdef WITH_XSLT_DEBUG_PROCESS 01051 xsltGenericDebug(xsltGenericDebugContext, 01052 "xsltComputeSortResult: select didn't evaluate to a string\n"); 01053 #endif 01054 results[i] = NULL; 01055 } 01056 } 01057 } else { 01058 ctxt->state = XSLT_STATE_STOPPED; 01059 results[i] = NULL; 01060 } 01061 } 01062 ctxt->node = oldNode; 01063 ctxt->inst = oldInst; 01064 ctxt->xpathCtxt->contextSize = oldSize; 01065 ctxt->xpathCtxt->proximityPosition = oldPos; 01066 ctxt->xpathCtxt->nsNr = oldNsNr; 01067 ctxt->xpathCtxt->namespaces = oldNamespaces; 01068 01069 return(results); 01070 } 01071 01081 void 01082 xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, 01083 int nbsorts) { 01084 #ifdef XSLT_REFACTORED 01085 xsltStyleItemSortPtr comp; 01086 #else 01087 xsltStylePreCompPtr comp; 01088 #endif 01089 xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT]; 01090 xmlXPathObjectPtr *results = NULL, *res; 01091 xmlNodeSetPtr list = NULL; 01092 int descending, number, desc, numb; 01093 int len = 0; 01094 int i, j, incr; 01095 int tst; 01096 int depth; 01097 xmlNodePtr node; 01098 xmlXPathObjectPtr tmp; 01099 int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT]; 01100 01101 if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) || 01102 (nbsorts >= XSLT_MAX_SORT)) 01103 return; 01104 if (sorts[0] == NULL) 01105 return; 01106 comp = sorts[0]->psvi; 01107 if (comp == NULL) 01108 return; 01109 01110 list = ctxt->nodeList; 01111 if ((list == NULL) || (list->nodeNr <= 1)) 01112 return; /* nothing to do */ 01113 01114 for (j = 0; j < nbsorts; j++) { 01115 comp = sorts[j]->psvi; 01116 tempstype[j] = 0; 01117 if ((comp->stype == NULL) && (comp->has_stype != 0)) { 01118 comp->stype = 01119 xsltEvalAttrValueTemplate(ctxt, sorts[j], 01120 (const xmlChar *) "data-type", 01121 XSLT_NAMESPACE); 01122 if (comp->stype != NULL) { 01123 tempstype[j] = 1; 01124 if (xmlStrEqual(comp->stype, (const xmlChar *) "text")) 01125 comp->number = 0; 01126 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number")) 01127 comp->number = 1; 01128 else { 01129 xsltTransformError(ctxt, NULL, sorts[j], 01130 "xsltDoSortFunction: no support for data-type = %s\n", 01131 comp->stype); 01132 comp->number = 0; /* use default */ 01133 } 01134 } 01135 } 01136 temporder[j] = 0; 01137 if ((comp->order == NULL) && (comp->has_order != 0)) { 01138 comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j], 01139 (const xmlChar *) "order", 01140 XSLT_NAMESPACE); 01141 if (comp->order != NULL) { 01142 temporder[j] = 1; 01143 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending")) 01144 comp->descending = 0; 01145 else if (xmlStrEqual(comp->order, 01146 (const xmlChar *) "descending")) 01147 comp->descending = 1; 01148 else { 01149 xsltTransformError(ctxt, NULL, sorts[j], 01150 "xsltDoSortFunction: invalid value %s for order\n", 01151 comp->order); 01152 comp->descending = 0; /* use default */ 01153 } 01154 } 01155 } 01156 } 01157 01158 len = list->nodeNr; 01159 01160 resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]); 01161 for (i = 1;i < XSLT_MAX_SORT;i++) 01162 resultsTab[i] = NULL; 01163 01164 results = resultsTab[0]; 01165 01166 comp = sorts[0]->psvi; 01167 descending = comp->descending; 01168 number = comp->number; 01169 if (results == NULL) 01170 return; 01171 01172 /* Shell's sort of node-set */ 01173 for (incr = len / 2; incr > 0; incr /= 2) { 01174 for (i = incr; i < len; i++) { 01175 j = i - incr; 01176 if (results[i] == NULL) 01177 continue; 01178 01179 while (j >= 0) { 01180 if (results[j] == NULL) 01181 tst = 1; 01182 else { 01183 if (number) { 01184 /* We make NaN smaller than number in accordance 01185 with XSLT spec */ 01186 if (xmlXPathIsNaN(results[j]->floatval)) { 01187 if (xmlXPathIsNaN(results[j + incr]->floatval)) 01188 tst = 0; 01189 else 01190 tst = -1; 01191 } else if (xmlXPathIsNaN(results[j + incr]->floatval)) 01192 tst = 1; 01193 else if (results[j]->floatval == 01194 results[j + incr]->floatval) 01195 tst = 0; 01196 else if (results[j]->floatval > 01197 results[j + incr]->floatval) 01198 tst = 1; 01199 else tst = -1; 01200 } else if(comp->locale != (xsltLocale)0) { 01201 tst = xsltLocaleStrcmp( 01202 comp->locale, 01203 (xsltLocaleChar *) results[j]->stringval, 01204 (xsltLocaleChar *) results[j + incr]->stringval); 01205 } else { 01206 tst = xmlStrcmp(results[j]->stringval, 01207 results[j + incr]->stringval); 01208 } 01209 if (descending) 01210 tst = -tst; 01211 } 01212 if (tst == 0) { 01213 /* 01214 * Okay we need to use multi level sorts 01215 */ 01216 depth = 1; 01217 while (depth < nbsorts) { 01218 if (sorts[depth] == NULL) 01219 break; 01220 comp = sorts[depth]->psvi; 01221 if (comp == NULL) 01222 break; 01223 desc = comp->descending; 01224 numb = comp->number; 01225 01226 /* 01227 * Compute the result of the next level for the 01228 * full set, this might be optimized ... or not 01229 */ 01230 if (resultsTab[depth] == NULL) 01231 resultsTab[depth] = xsltComputeSortResult(ctxt, 01232 sorts[depth]); 01233 res = resultsTab[depth]; 01234 if (res == NULL) 01235 break; 01236 if (res[j] == NULL) { 01237 if (res[j+incr] != NULL) 01238 tst = 1; 01239 } else { 01240 if (numb) { 01241 /* We make NaN smaller than number in 01242 accordance with XSLT spec */ 01243 if (xmlXPathIsNaN(res[j]->floatval)) { 01244 if (xmlXPathIsNaN(res[j + 01245 incr]->floatval)) 01246 tst = 0; 01247 else 01248 tst = -1; 01249 } else if (xmlXPathIsNaN(res[j + incr]-> 01250 floatval)) 01251 tst = 1; 01252 else if (res[j]->floatval == res[j + incr]-> 01253 floatval) 01254 tst = 0; 01255 else if (res[j]->floatval > 01256 res[j + incr]->floatval) 01257 tst = 1; 01258 else tst = -1; 01259 } else if(comp->locale != (xsltLocale)0) { 01260 tst = xsltLocaleStrcmp( 01261 comp->locale, 01262 (xsltLocaleChar *) res[j]->stringval, 01263 (xsltLocaleChar *) res[j + incr]->stringval); 01264 } else { 01265 tst = xmlStrcmp(res[j]->stringval, 01266 res[j + incr]->stringval); 01267 } 01268 if (desc) 01269 tst = -tst; 01270 } 01271 01272 /* 01273 * if we still can't differenciate at this level 01274 * try one level deeper. 01275 */ 01276 if (tst != 0) 01277 break; 01278 depth++; 01279 } 01280 } 01281 if (tst == 0) { 01282 tst = results[j]->index > results[j + incr]->index; 01283 } 01284 if (tst > 0) { 01285 tmp = results[j]; 01286 results[j] = results[j + incr]; 01287 results[j + incr] = tmp; 01288 node = list->nodeTab[j]; 01289 list->nodeTab[j] = list->nodeTab[j + incr]; 01290 list->nodeTab[j + incr] = node; 01291 depth = 1; 01292 while (depth < nbsorts) { 01293 if (sorts[depth] == NULL) 01294 break; 01295 if (resultsTab[depth] == NULL) 01296 break; 01297 res = resultsTab[depth]; 01298 tmp = res[j]; 01299 res[j] = res[j + incr]; 01300 res[j + incr] = tmp; 01301 depth++; 01302 } 01303 j -= incr; 01304 } else 01305 break; 01306 } 01307 } 01308 } 01309 01310 for (j = 0; j < nbsorts; j++) { 01311 comp = sorts[j]->psvi; 01312 if (tempstype[j] == 1) { 01313 /* The data-type needs to be recomputed each time */ 01314 xmlFree((void *)(comp->stype)); 01315 comp->stype = NULL; 01316 } 01317 if (temporder[j] == 1) { 01318 /* The order needs to be recomputed each time */ 01319 xmlFree((void *)(comp->order)); 01320 comp->order = NULL; 01321 } 01322 if (resultsTab[j] != NULL) { 01323 for (i = 0;i < len;i++) 01324 xmlXPathFreeObject(resultsTab[j][i]); 01325 xmlFree(resultsTab[j]); 01326 } 01327 } 01328 } 01329 01330 01331 static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction; 01332 01347 void 01348 xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts, 01349 int nbsorts) 01350 { 01351 if (ctxt->sortfunc != NULL) 01352 (ctxt->sortfunc)(ctxt, sorts, nbsorts); 01353 else if (xsltSortFunction != NULL) 01354 xsltSortFunction(ctxt, sorts, nbsorts); 01355 } 01356 01364 void 01365 xsltSetSortFunc(xsltSortFunc handler) { 01366 if (handler != NULL) 01367 xsltSortFunction = handler; 01368 else 01369 xsltSortFunction = xsltDefaultSortFunction; 01370 } 01371 01382 void 01383 xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) { 01384 ctxt->sortfunc = handler; 01385 } 01386 01387 /************************************************************************ 01388 * * 01389 * Parsing options * 01390 * * 01391 ************************************************************************/ 01392 01403 int 01404 xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options) 01405 { 01406 int oldopts; 01407 01408 if (ctxt == NULL) 01409 return(-1); 01410 oldopts = ctxt->parserOptions; 01411 if (ctxt->xinclude) 01412 oldopts |= XML_PARSE_XINCLUDE; 01413 ctxt->parserOptions = options; 01414 if (options & XML_PARSE_XINCLUDE) 01415 ctxt->xinclude = 1; 01416 else 01417 ctxt->xinclude = 0; 01418 return(oldopts); 01419 } 01420 01421 /************************************************************************ 01422 * * 01423 * Output * 01424 * * 01425 ************************************************************************/ 01426 01438 int 01439 xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result, 01440 xsltStylesheetPtr style) { 01441 const xmlChar *encoding; 01442 int base; 01443 const xmlChar *method; 01444 int indent; 01445 01446 if ((buf == NULL) || (result == NULL) || (style == NULL)) 01447 return(-1); 01448 if ((result->children == NULL) || 01449 ((result->children->type == XML_DTD_NODE) && 01450 (result->children->next == NULL))) 01451 return(0); 01452 01453 if ((style->methodURI != NULL) && 01454 ((style->method == NULL) || 01455 (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) { 01456 xsltGenericError(xsltGenericErrorContext, 01457 "xsltSaveResultTo : unknown ouput method\n"); 01458 return(-1); 01459 } 01460 01461 base = buf->written; 01462 01463 XSLT_GET_IMPORT_PTR(method, style, method) 01464 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 01465 XSLT_GET_IMPORT_INT(indent, style, indent); 01466 01467 if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE)) 01468 method = (const xmlChar *) "html"; 01469 01470 if ((method != NULL) && 01471 (xmlStrEqual(method, (const xmlChar *) "html"))) { 01472 if (encoding != NULL) { 01473 htmlSetMetaEncoding(result, (const xmlChar *) encoding); 01474 } else { 01475 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8"); 01476 } 01477 if (indent == -1) 01478 indent = 1; 01479 htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding, 01480 indent); 01481 xmlOutputBufferFlush(buf); 01482 } else if ((method != NULL) && 01483 (xmlStrEqual(method, (const xmlChar *) "xhtml"))) { 01484 if (encoding != NULL) { 01485 htmlSetMetaEncoding(result, (const xmlChar *) encoding); 01486 } else { 01487 htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8"); 01488 } 01489 htmlDocContentDumpOutput(buf, result, (const char *) encoding); 01490 xmlOutputBufferFlush(buf); 01491 } else if ((method != NULL) && 01492 (xmlStrEqual(method, (const xmlChar *) "text"))) { 01493 xmlNodePtr cur; 01494 01495 cur = result->children; 01496 while (cur != NULL) { 01497 if (cur->type == XML_TEXT_NODE) 01498 xmlOutputBufferWriteString(buf, (const char *) cur->content); 01499 01500 /* 01501 * Skip to next node 01502 */ 01503 if (cur->children != NULL) { 01504 if ((cur->children->type != XML_ENTITY_DECL) && 01505 (cur->children->type != XML_ENTITY_REF_NODE) && 01506 (cur->children->type != XML_ENTITY_NODE)) { 01507 cur = cur->children; 01508 continue; 01509 } 01510 } 01511 if (cur->next != NULL) { 01512 cur = cur->next; 01513 continue; 01514 } 01515 01516 do { 01517 cur = cur->parent; 01518 if (cur == NULL) 01519 break; 01520 if (cur == (xmlNodePtr) style->doc) { 01521 cur = NULL; 01522 break; 01523 } 01524 if (cur->next != NULL) { 01525 cur = cur->next; 01526 break; 01527 } 01528 } while (cur != NULL); 01529 } 01530 xmlOutputBufferFlush(buf); 01531 } else { 01532 int omitXmlDecl; 01533 int standalone; 01534 01535 XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration); 01536 XSLT_GET_IMPORT_INT(standalone, style, standalone); 01537 01538 if (omitXmlDecl != 1) { 01539 xmlOutputBufferWriteString(buf, "<?xml version="); 01540 if (result->version != NULL) 01541 xmlBufferWriteQuotedString(buf->buffer, result->version); 01542 else 01543 xmlOutputBufferWriteString(buf, "\"1.0\""); 01544 if (encoding == NULL) { 01545 if (result->encoding != NULL) 01546 encoding = result->encoding; 01547 else if (result->charset != XML_CHAR_ENCODING_UTF8) 01548 encoding = (const xmlChar *) 01549 xmlGetCharEncodingName((xmlCharEncoding) 01550 result->charset); 01551 } 01552 if (encoding != NULL) { 01553 xmlOutputBufferWriteString(buf, " encoding="); 01554 xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding); 01555 } 01556 switch (standalone) { 01557 case 0: 01558 xmlOutputBufferWriteString(buf, " standalone=\"no\""); 01559 break; 01560 case 1: 01561 xmlOutputBufferWriteString(buf, " standalone=\"yes\""); 01562 break; 01563 default: 01564 break; 01565 } 01566 xmlOutputBufferWriteString(buf, "?>\n"); 01567 } 01568 if (result->children != NULL) { 01569 xmlNodePtr child = result->children; 01570 01571 while (child != NULL) { 01572 xmlNodeDumpOutput(buf, result, child, 0, (indent == 1), 01573 (const char *) encoding); 01574 if ((child->type == XML_DTD_NODE) || 01575 ((child->type == XML_COMMENT_NODE) && 01576 (child->next != NULL))) 01577 xmlOutputBufferWriteString(buf, "\n"); 01578 child = child->next; 01579 } 01580 xmlOutputBufferWriteString(buf, "\n"); 01581 } 01582 xmlOutputBufferFlush(buf); 01583 } 01584 return(buf->written - base); 01585 } 01586 01599 int 01600 xsltSaveResultToFilename(const char *URL, xmlDocPtr result, 01601 xsltStylesheetPtr style, int compression) { 01602 xmlOutputBufferPtr buf; 01603 const xmlChar *encoding; 01604 int ret; 01605 01606 if ((URL == NULL) || (result == NULL) || (style == NULL)) 01607 return(-1); 01608 if (result->children == NULL) 01609 return(0); 01610 01611 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 01612 if (encoding != NULL) { 01613 xmlCharEncodingHandlerPtr encoder; 01614 01615 encoder = xmlFindCharEncodingHandler((char *)encoding); 01616 if ((encoder != NULL) && 01617 (xmlStrEqual((const xmlChar *)encoder->name, 01618 (const xmlChar *) "UTF-8"))) 01619 encoder = NULL; 01620 buf = xmlOutputBufferCreateFilename(URL, encoder, compression); 01621 } else { 01622 buf = xmlOutputBufferCreateFilename(URL, NULL, compression); 01623 } 01624 if (buf == NULL) 01625 return(-1); 01626 xsltSaveResultTo(buf, result, style); 01627 ret = xmlOutputBufferClose(buf); 01628 return(ret); 01629 } 01630 01643 int 01644 xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) { 01645 xmlOutputBufferPtr buf; 01646 const xmlChar *encoding; 01647 int ret; 01648 01649 if ((file == NULL) || (result == NULL) || (style == NULL)) 01650 return(-1); 01651 if (result->children == NULL) 01652 return(0); 01653 01654 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 01655 if (encoding != NULL) { 01656 xmlCharEncodingHandlerPtr encoder; 01657 01658 encoder = xmlFindCharEncodingHandler((char *)encoding); 01659 if ((encoder != NULL) && 01660 (xmlStrEqual((const xmlChar *)encoder->name, 01661 (const xmlChar *) "UTF-8"))) 01662 encoder = NULL; 01663 buf = xmlOutputBufferCreateFile(file, encoder); 01664 } else { 01665 buf = xmlOutputBufferCreateFile(file, NULL); 01666 } 01667 01668 if (buf == NULL) 01669 return(-1); 01670 xsltSaveResultTo(buf, result, style); 01671 ret = xmlOutputBufferClose(buf); 01672 return(ret); 01673 } 01674 01687 int 01688 xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) { 01689 xmlOutputBufferPtr buf; 01690 const xmlChar *encoding; 01691 int ret; 01692 01693 if ((fd < 0) || (result == NULL) || (style == NULL)) 01694 return(-1); 01695 if (result->children == NULL) 01696 return(0); 01697 01698 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 01699 if (encoding != NULL) { 01700 xmlCharEncodingHandlerPtr encoder; 01701 01702 encoder = xmlFindCharEncodingHandler((char *)encoding); 01703 if ((encoder != NULL) && 01704 (xmlStrEqual((const xmlChar *)encoder->name, 01705 (const xmlChar *) "UTF-8"))) 01706 encoder = NULL; 01707 buf = xmlOutputBufferCreateFd(fd, encoder); 01708 } else { 01709 buf = xmlOutputBufferCreateFd(fd, NULL); 01710 } 01711 if (buf == NULL) 01712 return(-1); 01713 xsltSaveResultTo(buf, result, style); 01714 ret = xmlOutputBufferClose(buf); 01715 return(ret); 01716 } 01717 01730 int 01731 xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, 01732 xmlDocPtr result, xsltStylesheetPtr style) { 01733 xmlOutputBufferPtr buf; 01734 const xmlChar *encoding; 01735 01736 *doc_txt_ptr = NULL; 01737 *doc_txt_len = 0; 01738 if (result->children == NULL) 01739 return(0); 01740 01741 XSLT_GET_IMPORT_PTR(encoding, style, encoding) 01742 if (encoding != NULL) { 01743 xmlCharEncodingHandlerPtr encoder; 01744 01745 encoder = xmlFindCharEncodingHandler((char *)encoding); 01746 if ((encoder != NULL) && 01747 (xmlStrEqual((const xmlChar *)encoder->name, 01748 (const xmlChar *) "UTF-8"))) 01749 encoder = NULL; 01750 buf = xmlAllocOutputBuffer(encoder); 01751 } else { 01752 buf = xmlAllocOutputBuffer(NULL); 01753 } 01754 if (buf == NULL) 01755 return(-1); 01756 xsltSaveResultTo(buf, result, style); 01757 if (buf->conv != NULL) { 01758 *doc_txt_len = buf->conv->use; 01759 *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len); 01760 } else { 01761 *doc_txt_len = buf->buffer->use; 01762 *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len); 01763 } 01764 (void)xmlOutputBufferClose(buf); 01765 return 0; 01766 } 01767 01768 /************************************************************************ 01769 * * 01770 * Generating profiling informations * 01771 * * 01772 ************************************************************************/ 01773 01774 static long calibration = -1; 01775 01784 static long 01785 xsltCalibrateTimestamps(void) { 01786 register int i; 01787 01788 for (i = 0;i < 999;i++) 01789 xsltTimestamp(); 01790 return(xsltTimestamp() / 1000); 01791 } 01792 01799 void 01800 xsltCalibrateAdjust(long delta) { 01801 calibration += delta; 01802 } 01803 01812 long 01813 xsltTimestamp(void) 01814 { 01815 #ifdef XSLT_WIN32_PERFORMANCE_COUNTER 01816 BOOL ok; 01817 LARGE_INTEGER performanceCount; 01818 LARGE_INTEGER performanceFrequency; 01819 LONGLONG quadCount; 01820 double seconds; 01821 static LONGLONG startupQuadCount = 0; 01822 static LONGLONG startupQuadFreq = 0; 01823 01824 ok = QueryPerformanceCounter(&performanceCount); 01825 if (!ok) 01826 return 0; 01827 quadCount = performanceCount.QuadPart; 01828 if (calibration < 0) { 01829 calibration = 0; 01830 ok = QueryPerformanceFrequency(&performanceFrequency); 01831 if (!ok) 01832 return 0; 01833 startupQuadFreq = performanceFrequency.QuadPart; 01834 startupQuadCount = quadCount; 01835 return (0); 01836 } 01837 if (startupQuadFreq == 0) 01838 return 0; 01839 seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq; 01840 return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC); 01841 01842 #else /* XSLT_WIN32_PERFORMANCE_COUNTER */ 01843 #ifdef HAVE_GETTIMEOFDAY 01844 static struct timeval startup; 01845 struct timeval cur; 01846 long tics; 01847 01848 if (calibration < 0) { 01849 gettimeofday(&startup, NULL); 01850 calibration = 0; 01851 calibration = xsltCalibrateTimestamps(); 01852 gettimeofday(&startup, NULL); 01853 return (0); 01854 } 01855 01856 gettimeofday(&cur, NULL); 01857 tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC; 01858 tics += (cur.tv_usec - startup.tv_usec) / 01859 (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC); 01860 01861 tics -= calibration; 01862 return(tics); 01863 #else 01864 01865 /* Neither gettimeofday() nor Win32 performance counter available */ 01866 01867 return (0); 01868 01869 #endif /* HAVE_GETTIMEOFDAY */ 01870 #endif /* XSLT_WIN32_PERFORMANCE_COUNTER */ 01871 } 01872 01873 #define MAX_TEMPLATES 10000 01874 01882 void 01883 xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { 01884 int nb, i,j; 01885 int max; 01886 int total; 01887 long totalt; 01888 xsltTemplatePtr *templates; 01889 xsltStylesheetPtr style; 01890 xsltTemplatePtr template; 01891 01892 if ((output == NULL) || (ctxt == NULL)) 01893 return; 01894 if (ctxt->profile == 0) 01895 return; 01896 01897 nb = 0; 01898 max = MAX_TEMPLATES; 01899 templates = xmlMalloc(max * sizeof(xsltTemplatePtr)); 01900 if (templates == NULL) 01901 return; 01902 01903 style = ctxt->style; 01904 while (style != NULL) { 01905 template = style->templates; 01906 while (template != NULL) { 01907 if (nb >= max) 01908 break; 01909 01910 if (template->nbCalls > 0) 01911 templates[nb++] = template; 01912 template = template->next; 01913 } 01914 01915 style = xsltNextImport(style); 01916 } 01917 01918 for (i = 0;i < nb -1;i++) { 01919 for (j = i + 1; j < nb; j++) { 01920 if ((templates[i]->time <= templates[j]->time) || 01921 ((templates[i]->time == templates[j]->time) && 01922 (templates[i]->nbCalls <= templates[j]->nbCalls))) { 01923 template = templates[j]; 01924 templates[j] = templates[i]; 01925 templates[i] = template; 01926 } 01927 } 01928 } 01929 01930 fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n", 01931 "number", "match", "name", "mode"); 01932 total = 0; 01933 totalt = 0; 01934 for (i = 0;i < nb;i++) { 01935 fprintf(output, "%5d ", i); 01936 if (templates[i]->match != NULL) { 01937 if (xmlStrlen(templates[i]->match) > 20) 01938 fprintf(output, "%s\n%26s", templates[i]->match, ""); 01939 else 01940 fprintf(output, "%20s", templates[i]->match); 01941 } else { 01942 fprintf(output, "%20s", ""); 01943 } 01944 if (templates[i]->name != NULL) { 01945 if (xmlStrlen(templates[i]->name) > 20) 01946 fprintf(output, "%s\n%46s", templates[i]->name, ""); 01947 else 01948 fprintf(output, "%20s", templates[i]->name); 01949 } else { 01950 fprintf(output, "%20s", ""); 01951 } 01952 if (templates[i]->mode != NULL) { 01953 if (xmlStrlen(templates[i]->mode) > 10) 01954 fprintf(output, "%s\n%56s", templates[i]->mode, ""); 01955 else 01956 fprintf(output, "%10s", templates[i]->mode); 01957 } else { 01958 fprintf(output, "%10s", ""); 01959 } 01960 fprintf(output, " %6d", templates[i]->nbCalls); 01961 fprintf(output, " %6ld %6ld\n", templates[i]->time, 01962 templates[i]->time / templates[i]->nbCalls); 01963 total += templates[i]->nbCalls; 01964 totalt += templates[i]->time; 01965 } 01966 fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt); 01967 01968 xmlFree(templates); 01969 } 01970 01971 /************************************************************************ 01972 * * 01973 * Fetching profiling informations * 01974 * * 01975 ************************************************************************/ 01976 01998 xmlDocPtr 01999 xsltGetProfileInformation(xsltTransformContextPtr ctxt) 02000 { 02001 xmlDocPtr ret = NULL; 02002 xmlNodePtr root, child; 02003 char buf[100]; 02004 02005 xsltStylesheetPtr style; 02006 xsltTemplatePtr *templates; 02007 xsltTemplatePtr templ; 02008 int nb = 0, max = 0, i, j; 02009 02010 if (!ctxt) 02011 return NULL; 02012 02013 if (!ctxt->profile) 02014 return NULL; 02015 02016 nb = 0; 02017 max = 10000; 02018 templates = 02019 (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr)); 02020 if (templates == NULL) 02021 return NULL; 02022 02023 /* 02024 * collect all the templates in an array 02025 */ 02026 style = ctxt->style; 02027 while (style != NULL) { 02028 templ = style->templates; 02029 while (templ != NULL) { 02030 if (nb >= max) 02031 break; 02032 02033 if (templ->nbCalls > 0) 02034 templates[nb++] = templ; 02035 templ = templ->next; 02036 } 02037 02038 style = (xsltStylesheetPtr) xsltNextImport(style); 02039 } 02040 02041 /* 02042 * Sort the array by time spent 02043 */ 02044 for (i = 0; i < nb - 1; i++) { 02045 for (j = i + 1; j < nb; j++) { 02046 if ((templates[i]->time <= templates[j]->time) || 02047 ((templates[i]->time == templates[j]->time) && 02048 (templates[i]->nbCalls <= templates[j]->nbCalls))) { 02049 templ = templates[j]; 02050 templates[j] = templates[i]; 02051 templates[i] = templ; 02052 } 02053 } 02054 } 02055 02056 /* 02057 * Generate a document corresponding to the results. 02058 */ 02059 ret = xmlNewDoc(BAD_CAST "1.0"); 02060 root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL); 02061 xmlDocSetRootElement(ret, root); 02062 02063 for (i = 0; i < nb; i++) { 02064 child = xmlNewChild(root, NULL, BAD_CAST "template", NULL); 02065 sprintf(buf, "%d", i + 1); 02066 xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf); 02067 xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match); 02068 xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name); 02069 xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode); 02070 02071 sprintf(buf, "%d", templates[i]->nbCalls); 02072 xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf); 02073 02074 sprintf(buf, "%ld", templates[i]->time); 02075 xmlSetProp(child, BAD_CAST "time", BAD_CAST buf); 02076 02077 sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls); 02078 xmlSetProp(child, BAD_CAST "average", BAD_CAST buf); 02079 }; 02080 02081 xmlFree(templates); 02082 02083 return ret; 02084 } 02085 02086 /************************************************************************ 02087 * * 02088 * Hooks for libxml2 XPath * 02089 * * 02090 ************************************************************************/ 02091 02102 xmlXPathCompExprPtr 02103 xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) { 02104 xmlXPathContextPtr xpathCtxt; 02105 xmlXPathCompExprPtr ret; 02106 02107 if (style != NULL) { 02108 #ifdef XSLT_REFACTORED_XPATHCOMP 02109 if (XSLT_CCTXT(style)) { 02110 /* 02111 * Proposed by Jerome Pesenti 02112 * -------------------------- 02113 * For better efficiency we'll reuse the compilation 02114 * context's XPath context. For the common stylesheet using 02115 * XPath expressions this will reduce compilation time to 02116 * about 50%. 02117 * 02118 * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html 02119 */ 02120 xpathCtxt = XSLT_CCTXT(style)->xpathCtxt; 02121 xpathCtxt->doc = style->doc; 02122 } else 02123 xpathCtxt = xmlXPathNewContext(style->doc); 02124 #else 02125 xpathCtxt = xmlXPathNewContext(style->doc); 02126 #endif 02127 if (xpathCtxt == NULL) 02128 return NULL; 02129 xpathCtxt->dict = style->dict; 02130 } else { 02131 xpathCtxt = xmlXPathNewContext(NULL); 02132 if (xpathCtxt == NULL) 02133 return NULL; 02134 } 02135 /* 02136 * Compile the expression. 02137 */ 02138 ret = xmlXPathCtxtCompile(xpathCtxt, str); 02139 02140 #ifdef XSLT_REFACTORED_XPATHCOMP 02141 if ((style == NULL) || (! XSLT_CCTXT(style))) { 02142 xmlXPathFreeContext(xpathCtxt); 02143 } 02144 #else 02145 xmlXPathFreeContext(xpathCtxt); 02146 #endif 02147 /* 02148 * TODO: there is a lot of optimizations which should be possible 02149 * like variable slot precomputations, function precomputations, etc. 02150 */ 02151 02152 return(ret); 02153 } 02154 02155 /************************************************************************ 02156 * * 02157 * Hooks for the debugger * 02158 * * 02159 ************************************************************************/ 02160 02161 /* 02162 * There is currently only 3 debugging callback defined 02163 * Debugger callbacks are disabled by default 02164 */ 02165 #define XSLT_CALLBACK_NUMBER 3 02166 02167 typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks; 02168 typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr; 02169 struct _xsltDebuggerCallbacks { 02170 xsltHandleDebuggerCallback handler; 02171 xsltAddCallCallback add; 02172 xsltDropCallCallback drop; 02173 }; 02174 02175 static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = { 02176 NULL, /* handler */ 02177 NULL, /* add */ 02178 NULL /* drop */ 02179 }; 02180 02181 int xslDebugStatus; 02182 02189 void 02190 xsltSetDebuggerStatus(int value) 02191 { 02192 xslDebugStatus = value; 02193 } 02194 02202 int 02203 xsltGetDebuggerStatus(void) 02204 { 02205 return(xslDebugStatus); 02206 } 02207 02219 int 02220 xsltSetDebuggerCallbacks(int no, void *block) 02221 { 02222 xsltDebuggerCallbacksPtr callbacks; 02223 02224 if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER)) 02225 return(-1); 02226 02227 callbacks = (xsltDebuggerCallbacksPtr) block; 02228 xsltDebuggerCurrentCallbacks.handler = callbacks->handler; 02229 xsltDebuggerCurrentCallbacks.add = callbacks->add; 02230 xsltDebuggerCurrentCallbacks.drop = callbacks->drop; 02231 return(0); 02232 } 02233 02245 void 02246 xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ, 02247 xsltTransformContextPtr ctxt) 02248 { 02249 if (xsltDebuggerCurrentCallbacks.handler != NULL) 02250 xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt); 02251 } 02252 02262 int 02263 xslAddCall(xsltTemplatePtr templ, xmlNodePtr source) 02264 { 02265 if (xsltDebuggerCurrentCallbacks.add != NULL) 02266 return(xsltDebuggerCurrentCallbacks.add(templ, source)); 02267 return(0); 02268 } 02269 02275 void 02276 xslDropCall(void) 02277 { 02278 if (xsltDebuggerCurrentCallbacks.drop != NULL) 02279 xsltDebuggerCurrentCallbacks.drop(); 02280 } 02281 Generated on Sun May 27 2012 04:19:43 for ReactOS by
1.7.6.1
|