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

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

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