Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenattributes.c
Go to the documentation of this file.
00001 /* 00002 * attributes.c: Implementation of the XSLT attributes handling 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 #include <string.h> 00016 00017 #ifdef HAVE_SYS_TYPES_H 00018 #include <sys/types.h> 00019 #endif 00020 #ifdef HAVE_MATH_H 00021 #include <math.h> 00022 #endif 00023 #ifdef HAVE_FLOAT_H 00024 #include <float.h> 00025 #endif 00026 #ifdef HAVE_IEEEFP_H 00027 #include <ieeefp.h> 00028 #endif 00029 #ifdef HAVE_NAN_H 00030 #include <nan.h> 00031 #endif 00032 #ifdef HAVE_CTYPE_H 00033 #include <ctype.h> 00034 #endif 00035 00036 #include <libxml/xmlmemory.h> 00037 #include <libxml/tree.h> 00038 #include <libxml/hash.h> 00039 #include <libxml/xmlerror.h> 00040 #include <libxml/uri.h> 00041 #include <libxml/parserInternals.h> 00042 #include "xslt.h" 00043 #include "xsltInternals.h" 00044 #include "xsltutils.h" 00045 #include "attributes.h" 00046 #include "namespaces.h" 00047 #include "templates.h" 00048 #include "imports.h" 00049 #include "transform.h" 00050 #include "preproc.h" 00051 00052 #define WITH_XSLT_DEBUG_ATTRIBUTES 00053 #ifdef WITH_XSLT_DEBUG 00054 #define WITH_XSLT_DEBUG_ATTRIBUTES 00055 #endif 00056 00057 /* 00058 * TODO: merge attribute sets from different import precedence. 00059 * all this should be precomputed just before the transformation 00060 * starts or at first hit with a cache in the context. 00061 * The simple way for now would be to not allow redefinition of 00062 * attributes once generated in the output tree, possibly costlier. 00063 */ 00064 00065 /* 00066 * Useful macros 00067 */ 00068 #ifdef IS_BLANK 00069 #undef IS_BLANK 00070 #endif 00071 00072 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ 00073 ((c) == 0x0D)) 00074 00075 #define IS_BLANK_NODE(n) \ 00076 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) 00077 00078 00079 /* 00080 * The in-memory structure corresponding to an XSLT Attribute in 00081 * an attribute set 00082 */ 00083 00084 00085 typedef struct _xsltAttrElem xsltAttrElem; 00086 typedef xsltAttrElem *xsltAttrElemPtr; 00087 struct _xsltAttrElem { 00088 struct _xsltAttrElem *next;/* chained list */ 00089 xmlNodePtr attr; /* the xsl:attribute definition */ 00090 const xmlChar *set; /* or the attribute set */ 00091 const xmlChar *ns; /* and its namespace */ 00092 }; 00093 00094 /************************************************************************ 00095 * * 00096 * XSLT Attribute handling * 00097 * * 00098 ************************************************************************/ 00099 00108 static xsltAttrElemPtr 00109 xsltNewAttrElem(xmlNodePtr attr) { 00110 xsltAttrElemPtr cur; 00111 00112 cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem)); 00113 if (cur == NULL) { 00114 xsltGenericError(xsltGenericErrorContext, 00115 "xsltNewAttrElem : malloc failed\n"); 00116 return(NULL); 00117 } 00118 memset(cur, 0, sizeof(xsltAttrElem)); 00119 cur->attr = attr; 00120 return(cur); 00121 } 00122 00129 static void 00130 xsltFreeAttrElem(xsltAttrElemPtr attr) { 00131 xmlFree(attr); 00132 } 00133 00140 static void 00141 xsltFreeAttrElemList(xsltAttrElemPtr list) { 00142 xsltAttrElemPtr next; 00143 00144 while (list != NULL) { 00145 next = list->next; 00146 xsltFreeAttrElem(list); 00147 list = next; 00148 } 00149 } 00150 00151 #ifdef XSLT_REFACTORED 00152 /* 00153 * This was moved to xsltParseStylesheetAttributeSet(). 00154 */ 00155 #else 00156 00165 static xsltAttrElemPtr 00166 xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) { 00167 xsltAttrElemPtr next, cur; 00168 00169 if (attr == NULL) 00170 return(list); 00171 if (list == NULL) 00172 return(xsltNewAttrElem(attr)); 00173 cur = list; 00174 while (cur != NULL) { 00175 next = cur->next; 00176 if (cur->attr == attr) 00177 return(cur); 00178 if (cur->next == NULL) { 00179 cur->next = xsltNewAttrElem(attr); 00180 return(list); 00181 } 00182 cur = next; 00183 } 00184 return(list); 00185 } 00186 #endif /* XSLT_REFACTORED */ 00187 00198 static xsltAttrElemPtr 00199 xsltMergeAttrElemList(xsltStylesheetPtr style, 00200 xsltAttrElemPtr list, xsltAttrElemPtr old) { 00201 xsltAttrElemPtr cur; 00202 int add; 00203 00204 while (old != NULL) { 00205 if ((old->attr == NULL) && (old->set == NULL)) { 00206 old = old->next; 00207 continue; 00208 } 00209 /* 00210 * Check that the attribute is not yet in the list 00211 */ 00212 cur = list; 00213 add = 1; 00214 while (cur != NULL) { 00215 if ((cur->attr == NULL) && (cur->set == NULL)) { 00216 if (cur->next == NULL) 00217 break; 00218 cur = cur->next; 00219 continue; 00220 } 00221 if ((cur->set != NULL) && (cur->set == old->set)) { 00222 add = 0; 00223 break; 00224 } 00225 if (cur->set != NULL) { 00226 if (cur->next == NULL) 00227 break; 00228 cur = cur->next; 00229 continue; 00230 } 00231 if (old->set != NULL) { 00232 if (cur->next == NULL) 00233 break; 00234 cur = cur->next; 00235 continue; 00236 } 00237 if (cur->attr == old->attr) { 00238 xsltGenericError(xsltGenericErrorContext, 00239 "xsl:attribute-set : use-attribute-sets recursion detected\n"); 00240 return(list); 00241 } 00242 if (cur->next == NULL) 00243 break; 00244 cur = cur->next; 00245 } 00246 00247 if (add == 1) { 00248 /* 00249 * Changed to use the string-dict, rather than duplicating 00250 * @set and @ns; this fixes bug #340400. 00251 */ 00252 if (cur == NULL) { 00253 list = xsltNewAttrElem(old->attr); 00254 if (old->set != NULL) { 00255 list->set = xmlDictLookup(style->dict, old->set, -1); 00256 if (old->ns != NULL) 00257 list->ns = xmlDictLookup(style->dict, old->ns, -1); 00258 } 00259 } else if (add) { 00260 cur->next = xsltNewAttrElem(old->attr); 00261 if (old->set != NULL) { 00262 cur->next->set = xmlDictLookup(style->dict, old->set, -1); 00263 if (old->ns != NULL) 00264 cur->next->ns = xmlDictLookup(style->dict, old->ns, -1); 00265 } 00266 } 00267 } 00268 00269 old = old->next; 00270 } 00271 return(list); 00272 } 00273 00274 /************************************************************************ 00275 * * 00276 * Module interfaces * 00277 * * 00278 ************************************************************************/ 00279 00288 void 00289 xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { 00290 const xmlChar *ncname; 00291 const xmlChar *prefix; 00292 xmlChar *value; 00293 xmlNodePtr child; 00294 xsltAttrElemPtr attrItems; 00295 00296 if ((cur == NULL) || (style == NULL)) 00297 return; 00298 00299 value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL); 00300 if (value == NULL) { 00301 xsltGenericError(xsltGenericErrorContext, 00302 "xsl:attribute-set : name is missing\n"); 00303 return; 00304 } 00305 00306 ncname = xsltSplitQName(style->dict, value, &prefix); 00307 xmlFree(value); 00308 value = NULL; 00309 00310 if (style->attributeSets == NULL) { 00311 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00312 xsltGenericDebug(xsltGenericDebugContext, 00313 "creating attribute set table\n"); 00314 #endif 00315 style->attributeSets = xmlHashCreate(10); 00316 } 00317 if (style->attributeSets == NULL) 00318 return; 00319 00320 attrItems = xmlHashLookup2(style->attributeSets, ncname, prefix); 00321 00322 /* 00323 * Parse the content. Only xsl:attribute elements are allowed. 00324 */ 00325 child = cur->children; 00326 while (child != NULL) { 00327 /* 00328 * Report invalid nodes. 00329 */ 00330 if ((child->type != XML_ELEMENT_NODE) || 00331 (child->ns == NULL) || 00332 (! IS_XSLT_ELEM(child))) 00333 { 00334 if (child->type == XML_ELEMENT_NODE) 00335 xsltTransformError(NULL, style, child, 00336 "xsl:attribute-set : unexpected child %s\n", 00337 child->name); 00338 else 00339 xsltTransformError(NULL, style, child, 00340 "xsl:attribute-set : child of unexpected type\n"); 00341 } else if (!IS_XSLT_NAME(child, "attribute")) { 00342 xsltTransformError(NULL, style, child, 00343 "xsl:attribute-set : unexpected child xsl:%s\n", 00344 child->name); 00345 } else { 00346 #ifdef XSLT_REFACTORED 00347 xsltAttrElemPtr nextAttr, curAttr; 00348 00349 /* 00350 * Process xsl:attribute 00351 * --------------------- 00352 */ 00353 00354 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00355 xsltGenericDebug(xsltGenericDebugContext, 00356 "add attribute to list %s\n", ncname); 00357 #endif 00358 /* 00359 * The following was taken over from 00360 * xsltAddAttrElemList(). 00361 */ 00362 if (attrItems == NULL) { 00363 attrItems = xsltNewAttrElem(child); 00364 } else { 00365 curAttr = attrItems; 00366 while (curAttr != NULL) { 00367 nextAttr = curAttr->next; 00368 if (curAttr->attr == child) { 00369 /* 00370 * URGENT TODO: Can somebody explain 00371 * why attrItems is set to curAttr 00372 * here? Is this somehow related to 00373 * avoidance of recursions? 00374 */ 00375 attrItems = curAttr; 00376 goto next_child; 00377 } 00378 if (curAttr->next == NULL) 00379 curAttr->next = xsltNewAttrElem(child); 00380 curAttr = nextAttr; 00381 } 00382 } 00383 /* 00384 * Parse the xsl:attribute and its content. 00385 */ 00386 xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); 00387 #else 00388 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00389 xsltGenericDebug(xsltGenericDebugContext, 00390 "add attribute to list %s\n", ncname); 00391 #endif 00392 /* 00393 * OLD behaviour: 00394 */ 00395 attrItems = xsltAddAttrElemList(attrItems, child); 00396 #endif 00397 } 00398 00399 #ifdef XSLT_REFACTORED 00400 next_child: 00401 #endif 00402 child = child->next; 00403 } 00404 00405 /* 00406 * Process attribue "use-attribute-sets". 00407 */ 00408 /* TODO check recursion */ 00409 value = xmlGetNsProp(cur, (const xmlChar *)"use-attribute-sets", 00410 NULL); 00411 if (value != NULL) { 00412 const xmlChar *curval, *endval; 00413 curval = value; 00414 while (*curval != 0) { 00415 while (IS_BLANK(*curval)) curval++; 00416 if (*curval == 0) 00417 break; 00418 endval = curval; 00419 while ((*endval != 0) && (!IS_BLANK(*endval))) endval++; 00420 curval = xmlDictLookup(style->dict, curval, endval - curval); 00421 if (curval) { 00422 const xmlChar *ncname2 = NULL; 00423 const xmlChar *prefix2 = NULL; 00424 xsltAttrElemPtr refAttrItems; 00425 00426 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00427 xsltGenericDebug(xsltGenericDebugContext, 00428 "xsl:attribute-set : %s adds use %s\n", ncname, curval); 00429 #endif 00430 ncname2 = xsltSplitQName(style->dict, curval, &prefix2); 00431 refAttrItems = xsltNewAttrElem(NULL); 00432 if (refAttrItems != NULL) { 00433 refAttrItems->set = ncname2; 00434 refAttrItems->ns = prefix2; 00435 attrItems = xsltMergeAttrElemList(style, 00436 attrItems, refAttrItems); 00437 xsltFreeAttrElem(refAttrItems); 00438 } 00439 } 00440 curval = endval; 00441 } 00442 xmlFree(value); 00443 value = NULL; 00444 } 00445 00446 /* 00447 * Update the value 00448 */ 00449 /* 00450 * TODO: Why is this dummy entry needed.? 00451 */ 00452 if (attrItems == NULL) 00453 attrItems = xsltNewAttrElem(NULL); 00454 xmlHashUpdateEntry2(style->attributeSets, ncname, prefix, attrItems, NULL); 00455 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00456 xsltGenericDebug(xsltGenericDebugContext, 00457 "updated attribute list %s\n", ncname); 00458 #endif 00459 } 00460 00471 static xsltAttrElemPtr 00472 xsltGetSAS(xsltStylesheetPtr style, const xmlChar *name, const xmlChar *ns) { 00473 xsltAttrElemPtr values; 00474 00475 while (style != NULL) { 00476 values = xmlHashLookup2(style->attributeSets, name, ns); 00477 if (values != NULL) 00478 return(values); 00479 style = xsltNextImport(style); 00480 } 00481 return(NULL); 00482 } 00483 00490 static void 00491 xsltResolveSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style, 00492 const xmlChar *name, const xmlChar *ns, 00493 ATTRIBUTE_UNUSED const xmlChar *ignored) { 00494 xsltAttrElemPtr tmp; 00495 xsltAttrElemPtr refs; 00496 00497 tmp = values; 00498 while (tmp != NULL) { 00499 if (tmp->set != NULL) { 00500 /* 00501 * Check against cycles ! 00502 */ 00503 if ((xmlStrEqual(name, tmp->set)) && (xmlStrEqual(ns, tmp->ns))) { 00504 xsltGenericError(xsltGenericErrorContext, 00505 "xsl:attribute-set : use-attribute-sets recursion detected on %s\n", 00506 name); 00507 } else { 00508 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00509 xsltGenericDebug(xsltGenericDebugContext, 00510 "Importing attribute list %s\n", tmp->set); 00511 #endif 00512 00513 refs = xsltGetSAS(style, tmp->set, tmp->ns); 00514 if (refs == NULL) { 00515 xsltGenericError(xsltGenericErrorContext, 00516 "xsl:attribute-set : use-attribute-sets %s reference missing %s\n", 00517 name, tmp->set); 00518 } else { 00519 /* 00520 * recurse first for cleanup 00521 */ 00522 xsltResolveSASCallback(refs, style, name, ns, NULL); 00523 /* 00524 * Then merge 00525 */ 00526 xsltMergeAttrElemList(style, values, refs); 00527 /* 00528 * Then suppress the reference 00529 */ 00530 tmp->set = NULL; 00531 tmp->ns = NULL; 00532 } 00533 } 00534 } 00535 tmp = tmp->next; 00536 } 00537 } 00538 00545 static void 00546 xsltMergeSASCallback(xsltAttrElemPtr values, xsltStylesheetPtr style, 00547 const xmlChar *name, const xmlChar *ns, 00548 ATTRIBUTE_UNUSED const xmlChar *ignored) { 00549 int ret; 00550 xsltAttrElemPtr topSet; 00551 00552 ret = xmlHashAddEntry2(style->attributeSets, name, ns, values); 00553 if (ret < 0) { 00554 /* 00555 * Add failed, this attribute set can be removed. 00556 */ 00557 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00558 xsltGenericDebug(xsltGenericDebugContext, 00559 "attribute set %s present already in top stylesheet" 00560 " - merging\n", name); 00561 #endif 00562 topSet = xmlHashLookup2(style->attributeSets, name, ns); 00563 if (topSet==NULL) { 00564 xsltGenericError(xsltGenericErrorContext, 00565 "xsl:attribute-set : logic error merging from imports for" 00566 " attribute-set %s\n", name); 00567 } else { 00568 topSet = xsltMergeAttrElemList(style, topSet, values); 00569 xmlHashUpdateEntry2(style->attributeSets, name, ns, topSet, NULL); 00570 } 00571 xsltFreeAttrElemList(values); 00572 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00573 } else { 00574 xsltGenericDebug(xsltGenericDebugContext, 00575 "attribute set %s moved to top stylesheet\n", 00576 name); 00577 #endif 00578 } 00579 } 00580 00587 void 00588 xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) { 00589 xsltStylesheetPtr cur; 00590 00591 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00592 xsltGenericDebug(xsltGenericDebugContext, 00593 "Resolving attribute sets references\n"); 00594 #endif 00595 /* 00596 * First aggregate all the attribute sets definitions from the imports 00597 */ 00598 cur = xsltNextImport(style); 00599 while (cur != NULL) { 00600 if (cur->attributeSets != NULL) { 00601 if (style->attributeSets == NULL) { 00602 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES 00603 xsltGenericDebug(xsltGenericDebugContext, 00604 "creating attribute set table\n"); 00605 #endif 00606 style->attributeSets = xmlHashCreate(10); 00607 } 00608 xmlHashScanFull(cur->attributeSets, 00609 (xmlHashScannerFull) xsltMergeSASCallback, style); 00610 /* 00611 * the attribute lists have either been migrated to style 00612 * or freed directly in xsltMergeSASCallback() 00613 */ 00614 xmlHashFree(cur->attributeSets, NULL); 00615 cur->attributeSets = NULL; 00616 } 00617 cur = xsltNextImport(cur); 00618 } 00619 00620 /* 00621 * Then resolve all the references and computes the resulting sets 00622 */ 00623 if (style->attributeSets != NULL) { 00624 xmlHashScanFull(style->attributeSets, 00625 (xmlHashScannerFull) xsltResolveSASCallback, style); 00626 } 00627 } 00628 00639 static void 00640 xsltAttributeInternal(xsltTransformContextPtr ctxt, 00641 xmlNodePtr contextNode, 00642 xmlNodePtr inst, 00643 xsltStylePreCompPtr castedComp, 00644 int fromAttributeSet) 00645 { 00646 #ifdef XSLT_REFACTORED 00647 xsltStyleItemAttributePtr comp = 00648 (xsltStyleItemAttributePtr) castedComp; 00649 #else 00650 xsltStylePreCompPtr comp = castedComp; 00651 #endif 00652 xmlNodePtr targetElem; 00653 xmlChar *prop = NULL; 00654 const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL; 00655 xmlChar *value = NULL; 00656 xmlNsPtr ns = NULL; 00657 xmlAttrPtr attr; 00658 00659 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) 00660 return; 00661 00662 /* 00663 * A comp->has_name == 0 indicates that we need to skip this instruction, 00664 * since it was evaluated to be invalid already during compilation. 00665 */ 00666 if (!comp->has_name) 00667 return; 00668 /* 00669 * BIG NOTE: This previously used xsltGetSpecialNamespace() and 00670 * xsltGetNamespace(), but since both are not appropriate, we 00671 * will process namespace lookup here to avoid adding yet another 00672 * ns-lookup function to namespaces.c. 00673 */ 00674 /* 00675 * SPEC XSLT 1.0: Error cases: 00676 * - Creating nodes other than text nodes during the instantiation of 00677 * the content of the xsl:attribute element; implementations may 00678 * either signal the error or ignore the offending nodes." 00679 */ 00680 00681 if (comp == NULL) { 00682 xsltTransformError(ctxt, NULL, inst, 00683 "Internal error in xsltAttributeInternal(): " 00684 "The XSLT 'attribute' instruction was not compiled.\n"); 00685 return; 00686 } 00687 /* 00688 * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error? 00689 * So report an internal error? 00690 */ 00691 if (ctxt->insert == NULL) 00692 return; 00693 /* 00694 * SPEC XSLT 1.0: 00695 * "Adding an attribute to a node that is not an element; 00696 * implementations may either signal the error or ignore the attribute." 00697 * 00698 * TODO: I think we should signal such errors in the future, and maybe 00699 * provide an option to ignore such errors. 00700 */ 00701 targetElem = ctxt->insert; 00702 if (targetElem->type != XML_ELEMENT_NODE) 00703 return; 00704 00705 /* 00706 * SPEC XSLT 1.0: 00707 * "Adding an attribute to an element after children have been added 00708 * to it; implementations may either signal the error or ignore the 00709 * attribute." 00710 * 00711 * TODO: We should decide whether not to report such errors or 00712 * to ignore them; note that we *ignore* if the parent is not an 00713 * element, but here we report an error. 00714 */ 00715 if (targetElem->children != NULL) { 00716 /* 00717 * NOTE: Ah! This seems to be intended to support streamed 00718 * result generation!. 00719 */ 00720 xsltTransformError(ctxt, NULL, inst, 00721 "xsl:attribute: Cannot add attributes to an " 00722 "element if children have been already added " 00723 "to the element.\n"); 00724 return; 00725 } 00726 00727 /* 00728 * Process the name 00729 * ---------------- 00730 */ 00731 00732 #ifdef WITH_DEBUGGER 00733 if (ctxt->debugStatus != XSLT_DEBUG_NONE) 00734 xslHandleDebugger(inst, contextNode, NULL, ctxt); 00735 #endif 00736 00737 if (comp->name == NULL) { 00738 /* TODO: fix attr acquisition wrt to the XSLT namespace */ 00739 prop = xsltEvalAttrValueTemplate(ctxt, inst, 00740 (const xmlChar *) "name", XSLT_NAMESPACE); 00741 if (prop == NULL) { 00742 xsltTransformError(ctxt, NULL, inst, 00743 "xsl:attribute: The attribute 'name' is missing.\n"); 00744 goto error; 00745 } 00746 if (xmlValidateQName(prop, 0)) { 00747 xsltTransformError(ctxt, NULL, inst, 00748 "xsl:attribute: The effective name '%s' is not a " 00749 "valid QName.\n", prop); 00750 /* we fall through to catch any further errors, if possible */ 00751 } 00752 name = xsltSplitQName(ctxt->dict, prop, &prefix); 00753 xmlFree(prop); 00754 00755 /* 00756 * Reject a prefix of "xmlns". 00757 */ 00758 if ((prefix != NULL) && 00759 (!xmlStrncasecmp(prefix, (xmlChar *) "xmlns", 5))) 00760 { 00761 #ifdef WITH_XSLT_DEBUG_PARSING 00762 xsltGenericDebug(xsltGenericDebugContext, 00763 "xsltAttribute: xmlns prefix forbidden\n"); 00764 #endif 00765 /* 00766 * SPEC XSLT 1.0: 00767 * "It is an error if the string that results from instantiating 00768 * the attribute value template is not a QName or is the string 00769 * xmlns. An XSLT processor may signal the error; if it does not 00770 * signal the error, it must recover by not adding the attribute 00771 * to the result tree." 00772 * TODO: Decide which way to go here. 00773 */ 00774 goto error; 00775 } 00776 00777 } else { 00778 /* 00779 * The "name" value was static. 00780 */ 00781 #ifdef XSLT_REFACTORED 00782 prefix = comp->nsPrefix; 00783 name = comp->name; 00784 #else 00785 name = xsltSplitQName(ctxt->dict, comp->name, &prefix); 00786 #endif 00787 } 00788 00789 /* 00790 * Process namespace semantics 00791 * --------------------------- 00792 * 00793 * Evaluate the namespace name. 00794 */ 00795 if (comp->has_ns) { 00796 /* 00797 * The "namespace" attribute was existent. 00798 */ 00799 if (comp->ns != NULL) { 00800 /* 00801 * No AVT; just plain text for the namespace name. 00802 */ 00803 if (comp->ns[0] != 0) 00804 nsName = comp->ns; 00805 } else { 00806 xmlChar *tmpNsName; 00807 /* 00808 * Eval the AVT. 00809 */ 00810 /* TODO: check attr acquisition wrt to the XSLT namespace */ 00811 tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, 00812 (const xmlChar *) "namespace", XSLT_NAMESPACE); 00813 /* 00814 * This fixes bug #302020: The AVT might also evaluate to the 00815 * empty string; this means that the empty string also indicates 00816 * "no namespace". 00817 * SPEC XSLT 1.0: 00818 * "If the string is empty, then the expanded-name of the 00819 * attribute has a null namespace URI." 00820 */ 00821 if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) 00822 nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); 00823 xmlFree(tmpNsName); 00824 }; 00825 } else if (prefix != NULL) { 00826 /* 00827 * SPEC XSLT 1.0: 00828 * "If the namespace attribute is not present, then the QName is 00829 * expanded into an expanded-name using the namespace declarations 00830 * in effect for the xsl:attribute element, *not* including any 00831 * default namespace declaration." 00832 */ 00833 ns = xmlSearchNs(inst->doc, inst, prefix); 00834 if (ns == NULL) { 00835 /* 00836 * Note that this is treated as an error now (checked with 00837 * Saxon, Xalan-J and MSXML). 00838 */ 00839 xsltTransformError(ctxt, NULL, inst, 00840 "xsl:attribute: The QName '%s:%s' has no " 00841 "namespace binding in scope in the stylesheet; " 00842 "this is an error, since the namespace was not " 00843 "specified by the instruction itself.\n", prefix, name); 00844 } else 00845 nsName = ns->href; 00846 } 00847 00848 if (fromAttributeSet) { 00849 /* 00850 * This tries to ensure that xsl:attribute(s) coming 00851 * from an xsl:attribute-set won't override attribute of 00852 * literal result elements or of explicit xsl:attribute(s). 00853 * URGENT TODO: This might be buggy, since it will miss to 00854 * overwrite two equal attributes both from attribute sets. 00855 */ 00856 attr = xmlHasNsProp(targetElem, name, nsName); 00857 if (attr != NULL) 00858 return; 00859 } 00860 00861 /* 00862 * Find/create a matching ns-decl in the result tree. 00863 */ 00864 ns = NULL; 00865 00866 #if 0 00867 if (0) { 00868 /* 00869 * OPTIMIZE TODO: How do we know if we are adding to a 00870 * fragment or to the result tree? 00871 * 00872 * If we are adding to a result tree fragment (i.e., not to the 00873 * actual result tree), we'll don't bother searching for the 00874 * ns-decl, but just store it in the dummy-doc of the result 00875 * tree fragment. 00876 */ 00877 if (nsName != NULL) { 00878 /* 00879 * TODO: Get the doc of @targetElem. 00880 */ 00881 ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix); 00882 } 00883 } 00884 #endif 00885 00886 if (nsName != NULL) { 00887 /* 00888 * Something about ns-prefixes: 00889 * SPEC XSLT 1.0: 00890 * "XSLT processors may make use of the prefix of the QName specified 00891 * in the name attribute when selecting the prefix used for outputting 00892 * the created attribute as XML; however, they are not required to do 00893 * so and, if the prefix is xmlns, they must not do so" 00894 */ 00895 /* 00896 * xsl:attribute can produce a scenario where the prefix is NULL, 00897 * so generate a prefix. 00898 */ 00899 if (prefix == NULL) { 00900 xmlChar *pref = xmlStrdup(BAD_CAST "ns_1"); 00901 00902 ns = xsltGetSpecialNamespace(ctxt, inst, nsName, BAD_CAST pref, 00903 targetElem); 00904 00905 xmlFree(pref); 00906 } else { 00907 ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, 00908 targetElem); 00909 } 00910 if (ns == NULL) { 00911 xsltTransformError(ctxt, NULL, inst, 00912 "Namespace fixup error: Failed to acquire an in-scope " 00913 "namespace binding for the generated attribute '{%s}%s'.\n", 00914 nsName, name); 00915 goto error; 00916 } 00917 } 00918 /* 00919 * Construction of the value 00920 * ------------------------- 00921 */ 00922 if (inst->children == NULL) { 00923 /* 00924 * No content. 00925 * TODO: Do we need to put the empty string in ? 00926 */ 00927 attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) ""); 00928 } else if ((inst->children->next == NULL) && 00929 ((inst->children->type == XML_TEXT_NODE) || 00930 (inst->children->type == XML_CDATA_SECTION_NODE))) 00931 { 00932 xmlNodePtr copyTxt; 00933 00934 /* 00935 * xmlSetNsProp() will take care of duplicates. 00936 */ 00937 attr = xmlSetNsProp(ctxt->insert, ns, name, NULL); 00938 if (attr == NULL) /* TODO: report error ? */ 00939 goto error; 00940 /* 00941 * This was taken over from xsltCopyText() (transform.c). 00942 */ 00943 if (ctxt->internalized && 00944 (ctxt->insert->doc != NULL) && 00945 (ctxt->insert->doc->dict == ctxt->dict)) 00946 { 00947 copyTxt = xmlNewText(NULL); 00948 if (copyTxt == NULL) /* TODO: report error */ 00949 goto error; 00950 /* 00951 * This is a safe scenario where we don't need to lookup 00952 * the dict. 00953 */ 00954 copyTxt->content = inst->children->content; 00955 /* 00956 * Copy "disable-output-escaping" information. 00957 * TODO: Does this have any effect for attribute values 00958 * anyway? 00959 */ 00960 if (inst->children->name == xmlStringTextNoenc) 00961 copyTxt->name = xmlStringTextNoenc; 00962 } else { 00963 /* 00964 * Copy the value. 00965 */ 00966 copyTxt = xmlNewText(inst->children->content); 00967 if (copyTxt == NULL) /* TODO: report error */ 00968 goto error; 00969 } 00970 attr->children = attr->last = copyTxt; 00971 copyTxt->parent = (xmlNodePtr) attr; 00972 copyTxt->doc = attr->doc; 00973 /* 00974 * Copy "disable-output-escaping" information. 00975 * TODO: Does this have any effect for attribute values 00976 * anyway? 00977 */ 00978 if (inst->children->name == xmlStringTextNoenc) 00979 copyTxt->name = xmlStringTextNoenc; 00980 00981 /* 00982 * since we create the attribute without content IDness must be 00983 * asserted as a second step 00984 */ 00985 if ((copyTxt->content != NULL) && 00986 (xmlIsID(attr->doc, attr->parent, attr))) 00987 xmlAddID(NULL, attr->doc, copyTxt->content, attr); 00988 } else { 00989 /* 00990 * The sequence constructor might be complex, so instantiate it. 00991 */ 00992 value = xsltEvalTemplateString(ctxt, contextNode, inst); 00993 if (value != NULL) { 00994 attr = xmlSetNsProp(ctxt->insert, ns, name, value); 00995 xmlFree(value); 00996 } else { 00997 /* 00998 * TODO: Do we have to add the empty string to the attr? 00999 * TODO: Does a value of NULL indicate an 01000 * error in xsltEvalTemplateString() ? 01001 */ 01002 attr = xmlSetNsProp(ctxt->insert, ns, name, 01003 (const xmlChar *) ""); 01004 } 01005 } 01006 01007 error: 01008 return; 01009 } 01010 01020 void 01021 xsltAttribute(xsltTransformContextPtr ctxt, xmlNodePtr node, 01022 xmlNodePtr inst, xsltStylePreCompPtr comp) { 01023 xsltAttributeInternal(ctxt, node, inst, comp, 0); 01024 } 01025 01038 void 01039 xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node, 01040 xmlNodePtr inst, 01041 const xmlChar *attrSets) 01042 { 01043 const xmlChar *ncname = NULL; 01044 const xmlChar *prefix = NULL; 01045 const xmlChar *curstr, *endstr; 01046 xsltAttrElemPtr attrs; 01047 xsltStylesheetPtr style; 01048 01049 if (attrSets == NULL) { 01050 if (inst == NULL) 01051 return; 01052 else { 01053 /* 01054 * Extract the value from @inst. 01055 */ 01056 if (inst->type == XML_ATTRIBUTE_NODE) { 01057 if ( ((xmlAttrPtr) inst)->children != NULL) 01058 attrSets = ((xmlAttrPtr) inst)->children->content; 01059 01060 } 01061 if (attrSets == NULL) { 01062 /* 01063 * TODO: Return an error? 01064 */ 01065 return; 01066 } 01067 } 01068 } 01069 /* 01070 * Parse/apply the list of QNames. 01071 */ 01072 curstr = attrSets; 01073 while (*curstr != 0) { 01074 while (IS_BLANK(*curstr)) 01075 curstr++; 01076 if (*curstr == 0) 01077 break; 01078 endstr = curstr; 01079 while ((*endstr != 0) && (!IS_BLANK(*endstr))) 01080 endstr++; 01081 curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr); 01082 if (curstr) { 01083 /* 01084 * TODO: Validate the QName. 01085 */ 01086 01087 #ifdef WITH_XSLT_DEBUG_curstrUTES 01088 xsltGenericDebug(xsltGenericDebugContext, 01089 "apply curstrute set %s\n", curstr); 01090 #endif 01091 ncname = xsltSplitQName(ctxt->dict, curstr, &prefix); 01092 01093 style = ctxt->style; 01094 01095 #ifdef WITH_DEBUGGER 01096 if ((style != NULL) && 01097 (style->attributeSets != NULL) && 01098 (ctxt->debugStatus != XSLT_DEBUG_NONE)) 01099 { 01100 attrs = 01101 xmlHashLookup2(style->attributeSets, ncname, prefix); 01102 if ((attrs != NULL) && (attrs->attr != NULL)) 01103 xslHandleDebugger(attrs->attr->parent, node, NULL, 01104 ctxt); 01105 } 01106 #endif 01107 /* 01108 * Lookup the referenced curstrute-set. 01109 */ 01110 while (style != NULL) { 01111 attrs = 01112 xmlHashLookup2(style->attributeSets, ncname, prefix); 01113 while (attrs != NULL) { 01114 if (attrs->attr != NULL) { 01115 xsltAttributeInternal(ctxt, node, attrs->attr, 01116 attrs->attr->psvi, 1); 01117 } 01118 attrs = attrs->next; 01119 } 01120 style = xsltNextImport(style); 01121 } 01122 } 01123 curstr = endstr; 01124 } 01125 } 01126 01133 void 01134 xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) { 01135 if (style->attributeSets != NULL) 01136 xmlHashFree((xmlHashTablePtr) style->attributeSets, 01137 (xmlHashDeallocator) xsltFreeAttrElemList); 01138 style->attributeSets = NULL; 01139 } Generated on Sat May 26 2012 04:17:40 for ReactOS by
1.7.6.1
|