Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(832)

Side by Side Diff: third_party/libxslt/libxslt/attributes.c

Issue 2865973002: Check in the libxslt roll script. (Closed)
Patch Set: Consistent quotes. Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libxslt/libxslt/attributes.h ('k') | third_party/libxslt/libxslt/attrvt.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * attributes.c: Implementation of the XSLT attributes handling
3 *
4 * Reference:
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12 #define IN_LIBXSLT
13 #include "libxslt.h"
14
15 #include <string.h>
16
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
19 #endif
20 #ifdef HAVE_MATH_H
21 #include <math.h>
22 #endif
23 #ifdef HAVE_FLOAT_H
24 #include <float.h>
25 #endif
26 #ifdef HAVE_IEEEFP_H
27 #include <ieeefp.h>
28 #endif
29 #ifdef HAVE_NAN_H
30 #include <nan.h>
31 #endif
32 #ifdef HAVE_CTYPE_H
33 #include <ctype.h>
34 #endif
35
36 #include <libxml/xmlmemory.h>
37 #include <libxml/tree.h>
38 #include <libxml/hash.h>
39 #include <libxml/xmlerror.h>
40 #include <libxml/uri.h>
41 #include <libxml/parserInternals.h>
42 #include "xslt.h"
43 #include "xsltInternals.h"
44 #include "xsltutils.h"
45 #include "attributes.h"
46 #include "namespaces.h"
47 #include "templates.h"
48 #include "imports.h"
49 #include "transform.h"
50 #include "preproc.h"
51
52 #define WITH_XSLT_DEBUG_ATTRIBUTES
53 #ifdef WITH_XSLT_DEBUG
54 #define WITH_XSLT_DEBUG_ATTRIBUTES
55 #endif
56
57 /*
58 * Useful macros
59 */
60 #ifdef IS_BLANK
61 #undef IS_BLANK
62 #endif
63
64 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
65 ((c) == 0x0D))
66
67 #define IS_BLANK_NODE(n) \
68 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
69
70 #define ATTRSET_UNRESOLVED 0
71 #define ATTRSET_RESOLVING 1
72 #define ATTRSET_RESOLVED 2
73
74
75 /*
76 * The in-memory structure corresponding to an XSLT Attribute in
77 * an attribute set
78 */
79
80
81 typedef struct _xsltAttrElem xsltAttrElem;
82 typedef xsltAttrElem *xsltAttrElemPtr;
83 struct _xsltAttrElem {
84 struct _xsltAttrElem *next;/* chained list */
85 xmlNodePtr attr; /* the xsl:attribute definition */
86 };
87
88 typedef struct _xsltUseAttrSet xsltUseAttrSet;
89 typedef xsltUseAttrSet *xsltUseAttrSetPtr;
90 struct _xsltUseAttrSet {
91 struct _xsltUseAttrSet *next; /* chained list */
92 const xmlChar *ncname;
93 const xmlChar *ns;
94 };
95
96 typedef struct _xsltAttrSet xsltAttrSet;
97 typedef xsltAttrSet *xsltAttrSetPtr;
98 struct _xsltAttrSet {
99 int state;
100 xsltAttrElemPtr attrs; /* list head */
101 xsltUseAttrSetPtr useAttrSets; /* list head */
102 };
103
104 typedef struct _xsltAttrSetContext xsltAttrSetContext;
105 typedef xsltAttrSetContext *xsltAttrSetContextPtr;
106 struct _xsltAttrSetContext {
107 xsltStylesheetPtr topStyle;
108 xsltStylesheetPtr style;
109 };
110
111 static void
112 xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
113 xsltStylesheetPtr style, const xmlChar *name,
114 const xmlChar *ns, int depth);
115
116 /************************************************************************
117 * *
118 * XSLT Attribute handling *
119 * *
120 ************************************************************************/
121
122 /**
123 * xsltNewAttrElem:
124 * @attr: the new xsl:attribute node
125 *
126 * Create a new XSLT AttrElem
127 *
128 * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
129 */
130 static xsltAttrElemPtr
131 xsltNewAttrElem(xmlNodePtr attr) {
132 xsltAttrElemPtr cur;
133
134 cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem));
135 if (cur == NULL) {
136 xsltGenericError(xsltGenericErrorContext,
137 "xsltNewAttrElem : malloc failed\n");
138 return(NULL);
139 }
140 memset(cur, 0, sizeof(xsltAttrElem));
141 cur->attr = attr;
142 return(cur);
143 }
144
145 /**
146 * xsltFreeAttrElem:
147 * @attr: an XSLT AttrElem
148 *
149 * Free up the memory allocated by @attr
150 */
151 static void
152 xsltFreeAttrElem(xsltAttrElemPtr attr) {
153 xmlFree(attr);
154 }
155
156 /**
157 * xsltFreeAttrElemList:
158 * @list: an XSLT AttrElem list
159 *
160 * Free up the memory allocated by @list
161 */
162 static void
163 xsltFreeAttrElemList(xsltAttrElemPtr list) {
164 xsltAttrElemPtr next;
165
166 while (list != NULL) {
167 next = list->next;
168 xsltFreeAttrElem(list);
169 list = next;
170 }
171 }
172
173 /**
174 * xsltAddAttrElemList:
175 * @list: an XSLT AttrElem list
176 * @attr: the new xsl:attribute node
177 *
178 * Add the new attribute to the list.
179 *
180 * Returns the new list pointer
181 */
182 static xsltAttrElemPtr
183 xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) {
184 xsltAttrElemPtr next, cur;
185
186 if (attr == NULL)
187 return(list);
188 if (list == NULL)
189 return(xsltNewAttrElem(attr));
190 cur = list;
191 while (cur != NULL) {
192 next = cur->next;
193 if (next == NULL) {
194 cur->next = xsltNewAttrElem(attr);
195 return(list);
196 }
197 cur = next;
198 }
199 return(list);
200 }
201
202 /**
203 * xsltNewUseAttrSet:
204 * @ncname: local name
205 * @ns: namespace URI
206 *
207 * Create a new XSLT UseAttrSet
208 *
209 * Returns the newly allocated xsltUseAttrSetPtr or NULL in case of error.
210 */
211 static xsltUseAttrSetPtr
212 xsltNewUseAttrSet(const xmlChar *ncname, const xmlChar *ns) {
213 xsltUseAttrSetPtr cur;
214
215 cur = (xsltUseAttrSetPtr) xmlMalloc(sizeof(xsltUseAttrSet));
216 if (cur == NULL) {
217 xsltGenericError(xsltGenericErrorContext,
218 "xsltNewUseAttrSet : malloc failed\n");
219 return(NULL);
220 }
221 memset(cur, 0, sizeof(xsltUseAttrSet));
222 cur->ncname = ncname;
223 cur->ns = ns;
224 return(cur);
225 }
226
227 /**
228 * xsltFreeUseAttrSet:
229 * @use: an XSLT UseAttrSet
230 *
231 * Free up the memory allocated by @use
232 */
233 static void
234 xsltFreeUseAttrSet(xsltUseAttrSetPtr use) {
235 xmlFree(use);
236 }
237
238 /**
239 * xsltFreeUseAttrSetList:
240 * @list: an XSLT UseAttrSet list
241 *
242 * Free up the memory allocated by @list
243 */
244 static void
245 xsltFreeUseAttrSetList(xsltUseAttrSetPtr list) {
246 xsltUseAttrSetPtr next;
247
248 while (list != NULL) {
249 next = list->next;
250 xsltFreeUseAttrSet(list);
251 list = next;
252 }
253 }
254
255 /**
256 * xsltAddUseAttrSetList:
257 * @list: a xsltUseAttrSet list
258 * @ncname: local name
259 * @ns: namespace URI
260 *
261 * Add the use-attribute-set name to the list.
262 *
263 * Returns the new list pointer.
264 */
265 static xsltUseAttrSetPtr
266 xsltAddUseAttrSetList(xsltUseAttrSetPtr list, const xmlChar *ncname,
267 const xmlChar *ns) {
268 xsltUseAttrSetPtr next, cur;
269
270 if (ncname == NULL)
271 return(list);
272 if (list == NULL)
273 return(xsltNewUseAttrSet(ncname, ns));
274 cur = list;
275 while (cur != NULL) {
276 if ((cur->ncname == ncname) && (cur->ns == ns))
277 return(list);
278 next = cur->next;
279 if (next == NULL) {
280 cur->next = xsltNewUseAttrSet(ncname, ns);
281 return(list);
282 }
283 cur = next;
284 }
285 return(list);
286 }
287
288 /**
289 * xsltNewAttrSet:
290 *
291 * Create a new attribute set.
292 *
293 * Returns the newly allocated xsltAttrSetPtr or NULL in case of error.
294 */
295 static xsltAttrSetPtr
296 xsltNewAttrSet() {
297 xsltAttrSetPtr cur;
298
299 cur = (xsltAttrSetPtr) xmlMalloc(sizeof(xsltAttrSet));
300 if (cur == NULL) {
301 xsltGenericError(xsltGenericErrorContext,
302 "xsltNewAttrSet : malloc failed\n");
303 return(NULL);
304 }
305 memset(cur, 0, sizeof(xsltAttrSet));
306 return(cur);
307 }
308
309 /**
310 * xsltFreeAttrSet:
311 * @set: an attribute set
312 *
313 * Free memory allocated by @set
314 */
315 static void
316 xsltFreeAttrSet(xsltAttrSetPtr set) {
317 if (set == NULL)
318 return;
319
320 xsltFreeAttrElemList(set->attrs);
321 xsltFreeUseAttrSetList(set->useAttrSets);
322 xmlFree(set);
323 }
324
325 /**
326 * xsltMergeAttrSets:
327 * @set: an attribute set
328 * @other: another attribute set
329 *
330 * Add all the attributes from @other to @set,
331 * but drop redefinition of existing values.
332 */
333 static void
334 xsltMergeAttrSets(xsltAttrSetPtr set, xsltAttrSetPtr other) {
335 xsltAttrElemPtr cur;
336 xsltAttrElemPtr old = other->attrs;
337 int add;
338
339 while (old != NULL) {
340 /*
341 * Check that the attribute is not yet in the list
342 */
343 cur = set->attrs;
344 add = 1;
345 while (cur != NULL) {
346 xsltStylePreCompPtr curComp = cur->attr->psvi;
347 xsltStylePreCompPtr oldComp = old->attr->psvi;
348
349 if ((curComp->name == oldComp->name) &&
350 (curComp->ns == oldComp->ns)) {
351 add = 0;
352 break;
353 }
354 if (cur->next == NULL)
355 break;
356 cur = cur->next;
357 }
358
359 if (add == 1) {
360 if (cur == NULL) {
361 set->attrs = xsltNewAttrElem(old->attr);
362 } else if (add) {
363 cur->next = xsltNewAttrElem(old->attr);
364 }
365 }
366
367 old = old->next;
368 }
369 }
370
371 /************************************************************************
372 * *
373 * Module interfaces *
374 * *
375 ************************************************************************/
376
377 /**
378 * xsltParseStylesheetAttributeSet:
379 * @style: the XSLT stylesheet
380 * @cur: the "attribute-set" element
381 *
382 * parse an XSLT stylesheet attribute-set element
383 */
384
385 void
386 xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) {
387 const xmlChar *ncname;
388 const xmlChar *prefix;
389 const xmlChar *nsUri = NULL;
390 xmlChar *value;
391 xmlNodePtr child;
392 xsltAttrSetPtr set;
393
394 if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE))
395 return;
396
397 value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL);
398 if ((value == NULL) || (*value == 0)) {
399 xsltGenericError(xsltGenericErrorContext,
400 "xsl:attribute-set : name is missing\n");
401 if (value)
402 xmlFree(value);
403 return;
404 }
405
406 if (xmlValidateQName(value, 0)) {
407 xsltTransformError(NULL, style, cur,
408 "xsl:attribute-set : The name '%s' is not a valid QName.\n",
409 value);
410 style->errors++;
411 xmlFree(value);
412 return;
413 }
414
415 ncname = xsltSplitQName(style->dict, value, &prefix);
416 xmlFree(value);
417 value = NULL;
418 if (prefix != NULL) {
419 xmlNsPtr ns = xmlSearchNs(style->doc, cur, prefix);
420 if (ns == NULL) {
421 xsltTransformError(NULL, style, cur,
422 "xsl:attribute-set : No namespace found for QName '%s:%s'\n",
423 prefix, ncname);
424 style->errors++;
425 return;
426 }
427 nsUri = ns->href;
428 }
429
430 if (style->attributeSets == NULL) {
431 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
432 xsltGenericDebug(xsltGenericDebugContext,
433 "creating attribute set table\n");
434 #endif
435 style->attributeSets = xmlHashCreate(10);
436 }
437 if (style->attributeSets == NULL)
438 return;
439
440 set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
441 if (set == NULL) {
442 set = xsltNewAttrSet();
443 if (set == NULL)
444 return;
445 xmlHashAddEntry2(style->attributeSets, ncname, nsUri, set);
446 }
447
448 /*
449 * Parse the content. Only xsl:attribute elements are allowed.
450 */
451 child = cur->children;
452 while (child != NULL) {
453 /*
454 * Report invalid nodes.
455 */
456 if ((child->type != XML_ELEMENT_NODE) ||
457 (child->ns == NULL) ||
458 (! IS_XSLT_ELEM(child)))
459 {
460 if (child->type == XML_ELEMENT_NODE)
461 xsltTransformError(NULL, style, child,
462 "xsl:attribute-set : unexpected child %s\n",
463 child->name);
464 else
465 xsltTransformError(NULL, style, child,
466 "xsl:attribute-set : child of unexpected type\n");
467 } else if (!IS_XSLT_NAME(child, "attribute")) {
468 xsltTransformError(NULL, style, child,
469 "xsl:attribute-set : unexpected child xsl:%s\n",
470 child->name);
471 } else {
472 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
473 xsltGenericDebug(xsltGenericDebugContext,
474 "add attribute to list %s\n", ncname);
475 #endif
476 xsltStylePreCompute(style, child);
477 if (child->children != NULL) {
478 #ifdef XSLT_REFACTORED
479 xsltParseSequenceConstructor(XSLT_CCTXT(style),
480 child->children);
481 #else
482 xsltParseTemplateContent(style, child);
483 #endif
484 }
485 if (child->psvi == NULL) {
486 xsltTransformError(NULL, style, child,
487 "xsl:attribute-set : internal error, attribute %s not "
488 "compiled\n", child->name);
489 }
490 else {
491 set->attrs = xsltAddAttrElemList(set->attrs, child);
492 }
493 }
494
495 child = child->next;
496 }
497
498 /*
499 * Process attribute "use-attribute-sets".
500 */
501 value = xmlGetNsProp(cur, BAD_CAST "use-attribute-sets", NULL);
502 if (value != NULL) {
503 const xmlChar *curval, *endval;
504 curval = value;
505 while (*curval != 0) {
506 while (IS_BLANK(*curval)) curval++;
507 if (*curval == 0)
508 break;
509 endval = curval;
510 while ((*endval != 0) && (!IS_BLANK(*endval))) endval++;
511 curval = xmlDictLookup(style->dict, curval, endval - curval);
512 if (curval) {
513 const xmlChar *ncname2 = NULL;
514 const xmlChar *prefix2 = NULL;
515 const xmlChar *nsUri2 = NULL;
516
517 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
518 xsltGenericDebug(xsltGenericDebugContext,
519 "xsl:attribute-set : %s adds use %s\n", ncname, curval);
520 #endif
521
522 if (xmlValidateQName(curval, 0)) {
523 xsltTransformError(NULL, style, cur,
524 "xsl:attribute-set : The name '%s' in "
525 "use-attribute-sets is not a valid QName.\n", curval);
526 style->errors++;
527 xmlFree(value);
528 return;
529 }
530
531 ncname2 = xsltSplitQName(style->dict, curval, &prefix2);
532 if (prefix2 != NULL) {
533 xmlNsPtr ns2 = xmlSearchNs(style->doc, cur, prefix2);
534 if (ns2 == NULL) {
535 xsltTransformError(NULL, style, cur,
536 "xsl:attribute-set : No namespace found for QName "
537 "'%s:%s' in use-attribute-sets\n",
538 prefix2, ncname2);
539 style->errors++;
540 xmlFree(value);
541 return;
542 }
543 nsUri2 = ns2->href;
544 }
545 set->useAttrSets = xsltAddUseAttrSetList(set->useAttrSets,
546 ncname2, nsUri2);
547 }
548 curval = endval;
549 }
550 xmlFree(value);
551 value = NULL;
552 }
553
554 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
555 xsltGenericDebug(xsltGenericDebugContext,
556 "updated attribute list %s\n", ncname);
557 #endif
558 }
559
560 /**
561 * xsltResolveUseAttrSets:
562 * @set: the attribute set
563 * @asctx: the context for attribute set resolution
564 * @depth: recursion depth
565 *
566 * Process "use-attribute-sets".
567 */
568 static void
569 xsltResolveUseAttrSets(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
570 int depth) {
571 xsltStylesheetPtr cur;
572 xsltAttrSetPtr other;
573 xsltUseAttrSetPtr use = set->useAttrSets;
574 xsltUseAttrSetPtr next;
575
576 while (use != NULL) {
577 /*
578 * Iterate top stylesheet and all imports.
579 */
580 cur = topStyle;
581 while (cur != NULL) {
582 if (cur->attributeSets) {
583 other = xmlHashLookup2(cur->attributeSets, use->ncname,
584 use->ns);
585 if (other != NULL) {
586 xsltResolveAttrSet(other, topStyle, cur, use->ncname,
587 use->ns, depth + 1);
588 xsltMergeAttrSets(set, other);
589 break;
590 }
591 }
592 cur = xsltNextImport(cur);
593 }
594
595 next = use->next;
596 /* Free useAttrSets early. */
597 xsltFreeUseAttrSet(use);
598 use = next;
599 }
600
601 set->useAttrSets = NULL;
602 }
603
604 /**
605 * xsltResolveAttrSet:
606 * @set: the attribute set
607 * @asctx: the context for attribute set resolution
608 * @name: the local name of the attirbute set
609 * @ns: the namespace of the attribute set
610 * @depth: recursion depth
611 *
612 * resolve the references in an attribute set.
613 */
614 static void
615 xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle,
616 xsltStylesheetPtr style, const xmlChar *name,
617 const xmlChar *ns, int depth) {
618 xsltStylesheetPtr cur;
619 xsltAttrSetPtr other;
620
621 if (set->state == ATTRSET_RESOLVED)
622 return;
623 if (set->state == ATTRSET_RESOLVING) {
624 xsltTransformError(NULL, topStyle, NULL,
625 "xsl:attribute-set : use-attribute-sets recursion detected"
626 " on %s\n", name);
627 topStyle->errors++;
628 set->state = ATTRSET_RESOLVED;
629 return;
630 }
631 if (depth > 100) {
632 xsltTransformError(NULL, topStyle, NULL,
633 "xsl:attribute-set : use-attribute-sets maximum recursion "
634 "depth exceeded on %s\n", name);
635 topStyle->errors++;
636 return;
637 }
638
639 set->state = ATTRSET_RESOLVING;
640
641 xsltResolveUseAttrSets(set, topStyle, depth);
642
643 /* Merge imported sets. */
644 cur = xsltNextImport(style);
645 while (cur != NULL) {
646 if (cur->attributeSets != NULL) {
647 other = xmlHashLookup2(cur->attributeSets, name, ns);
648
649 if (other != NULL) {
650 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
651 xsltGenericDebug(xsltGenericDebugContext,
652 "xsl:attribute-set : merging import for %s\n", name);
653 #endif
654 xsltResolveUseAttrSets(other, topStyle, depth);
655 xsltMergeAttrSets(set, other);
656 xmlHashRemoveEntry2(cur->attributeSets, name, ns, NULL);
657 xsltFreeAttrSet(other);
658 }
659 }
660
661 cur = xsltNextImport(cur);
662 }
663
664 set->state = ATTRSET_RESOLVED;
665 }
666
667 /**
668 * xsltResolveSASCallback:
669 * @set: the attribute set
670 * @asctx: the context for attribute set resolution
671 * @name: the local name of the attirbute set
672 * @ns: the namespace of the attribute set
673 *
674 * resolve the references in an attribute set.
675 */
676 static void
677 xsltResolveSASCallback(xsltAttrSetPtr set, xsltAttrSetContextPtr asctx,
678 const xmlChar *name, const xmlChar *ns,
679 ATTRIBUTE_UNUSED const xmlChar *ignored) {
680 xsltStylesheetPtr topStyle = asctx->topStyle;
681 xsltStylesheetPtr style = asctx->style;
682
683 xsltResolveAttrSet(set, topStyle, style, name, ns, 1);
684
685 /* Move attribute sets to top stylesheet. */
686 if (style != topStyle) {
687 /*
688 * This imported stylesheet won't be visited anymore. Don't bother
689 * removing the hash entry.
690 */
691 if (xmlHashAddEntry2(topStyle->attributeSets, name, ns, set) < 0) {
692 xsltGenericError(xsltGenericErrorContext,
693 "xsl:attribute-set : internal error, can't move imported "
694 " attribute set %s\n", name);
695 }
696 }
697 }
698
699 /**
700 * xsltResolveStylesheetAttributeSet:
701 * @style: the XSLT stylesheet
702 *
703 * resolve the references between attribute sets.
704 */
705 void
706 xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) {
707 xsltStylesheetPtr cur;
708 xsltAttrSetContext asctx;
709
710 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
711 xsltGenericDebug(xsltGenericDebugContext,
712 "Resolving attribute sets references\n");
713 #endif
714 asctx.topStyle = style;
715 cur = style;
716 while (cur != NULL) {
717 if (cur->attributeSets != NULL) {
718 if (style->attributeSets == NULL) {
719 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
720 xsltGenericDebug(xsltGenericDebugContext,
721 "creating attribute set table\n");
722 #endif
723 style->attributeSets = xmlHashCreate(10);
724 }
725 asctx.style = cur;
726 xmlHashScanFull(cur->attributeSets,
727 (xmlHashScannerFull) xsltResolveSASCallback, &asctx);
728
729 if (cur != style) {
730 /*
731 * the attribute lists have either been migrated to style
732 * or freed directly in xsltResolveSASCallback()
733 */
734 xmlHashFree(cur->attributeSets, NULL);
735 cur->attributeSets = NULL;
736 }
737 }
738 cur = xsltNextImport(cur);
739 }
740 }
741
742 /**
743 * xsltAttribute:
744 * @ctxt: a XSLT process context
745 * @contextNode: the current node in the source tree
746 * @inst: the xsl:attribute element
747 * @castedComp: precomputed information
748 *
749 * Process the xslt attribute node on the source node
750 */
751 void
752 xsltAttribute(xsltTransformContextPtr ctxt,
753 xmlNodePtr contextNode,
754 xmlNodePtr inst,
755 xsltStylePreCompPtr castedComp)
756 {
757 #ifdef XSLT_REFACTORED
758 xsltStyleItemAttributePtr comp =
759 (xsltStyleItemAttributePtr) castedComp;
760 #else
761 xsltStylePreCompPtr comp = castedComp;
762 #endif
763 xmlNodePtr targetElem;
764 xmlChar *prop = NULL;
765 const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL;
766 xmlChar *value = NULL;
767 xmlNsPtr ns = NULL;
768 xmlAttrPtr attr;
769
770 if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) ||
771 (inst->type != XML_ELEMENT_NODE) )
772 return;
773
774 /*
775 * A comp->has_name == 0 indicates that we need to skip this instruction,
776 * since it was evaluated to be invalid already during compilation.
777 */
778 if (!comp->has_name)
779 return;
780 /*
781 * BIG NOTE: This previously used xsltGetSpecialNamespace() and
782 * xsltGetNamespace(), but since both are not appropriate, we
783 * will process namespace lookup here to avoid adding yet another
784 * ns-lookup function to namespaces.c.
785 */
786 /*
787 * SPEC XSLT 1.0: Error cases:
788 * - Creating nodes other than text nodes during the instantiation of
789 * the content of the xsl:attribute element; implementations may
790 * either signal the error or ignore the offending nodes."
791 */
792
793 if (comp == NULL) {
794 xsltTransformError(ctxt, NULL, inst,
795 "Internal error in xsltAttribute(): "
796 "The XSLT 'attribute' instruction was not compiled.\n");
797 return;
798 }
799 /*
800 * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
801 * So report an internal error?
802 */
803 if (ctxt->insert == NULL)
804 return;
805 /*
806 * SPEC XSLT 1.0:
807 * "Adding an attribute to a node that is not an element;
808 * implementations may either signal the error or ignore the attribute."
809 *
810 * TODO: I think we should signal such errors in the future, and maybe
811 * provide an option to ignore such errors.
812 */
813 targetElem = ctxt->insert;
814 if (targetElem->type != XML_ELEMENT_NODE)
815 return;
816
817 /*
818 * SPEC XSLT 1.0:
819 * "Adding an attribute to an element after children have been added
820 * to it; implementations may either signal the error or ignore the
821 * attribute."
822 *
823 * TODO: We should decide whether not to report such errors or
824 * to ignore them; note that we *ignore* if the parent is not an
825 * element, but here we report an error.
826 */
827 if (targetElem->children != NULL) {
828 /*
829 * NOTE: Ah! This seems to be intended to support streamed
830 * result generation!.
831 */
832 xsltTransformError(ctxt, NULL, inst,
833 "xsl:attribute: Cannot add attributes to an "
834 "element if children have been already added "
835 "to the element.\n");
836 return;
837 }
838
839 /*
840 * Process the name
841 * ----------------
842 */
843
844 #ifdef WITH_DEBUGGER
845 if (ctxt->debugStatus != XSLT_DEBUG_NONE)
846 xslHandleDebugger(inst, contextNode, NULL, ctxt);
847 #endif
848
849 if (comp->name == NULL) {
850 /* TODO: fix attr acquisition wrt to the XSLT namespace */
851 prop = xsltEvalAttrValueTemplate(ctxt, inst,
852 (const xmlChar *) "name", XSLT_NAMESPACE);
853 if (prop == NULL) {
854 xsltTransformError(ctxt, NULL, inst,
855 "xsl:attribute: The attribute 'name' is missing.\n");
856 goto error;
857 }
858 if (xmlValidateQName(prop, 0)) {
859 xsltTransformError(ctxt, NULL, inst,
860 "xsl:attribute: The effective name '%s' is not a "
861 "valid QName.\n", prop);
862 /* we fall through to catch any further errors, if possible */
863 }
864
865 /*
866 * Reject a name of "xmlns".
867 */
868 if (xmlStrEqual(prop, BAD_CAST "xmlns")) {
869 xsltTransformError(ctxt, NULL, inst,
870 "xsl:attribute: The effective name 'xmlns' is not allowed.\n");
871 xmlFree(prop);
872 goto error;
873 }
874
875 name = xsltSplitQName(ctxt->dict, prop, &prefix);
876 xmlFree(prop);
877 } else {
878 /*
879 * The "name" value was static.
880 */
881 #ifdef XSLT_REFACTORED
882 prefix = comp->nsPrefix;
883 name = comp->name;
884 #else
885 name = xsltSplitQName(ctxt->dict, comp->name, &prefix);
886 #endif
887 }
888
889 /*
890 * Process namespace semantics
891 * ---------------------------
892 *
893 * Evaluate the namespace name.
894 */
895 if (comp->has_ns) {
896 /*
897 * The "namespace" attribute was existent.
898 */
899 if (comp->ns != NULL) {
900 /*
901 * No AVT; just plain text for the namespace name.
902 */
903 if (comp->ns[0] != 0)
904 nsName = comp->ns;
905 } else {
906 xmlChar *tmpNsName;
907 /*
908 * Eval the AVT.
909 */
910 /* TODO: check attr acquisition wrt to the XSLT namespace */
911 tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst,
912 (const xmlChar *) "namespace", XSLT_NAMESPACE);
913 /*
914 * This fixes bug #302020: The AVT might also evaluate to the
915 * empty string; this means that the empty string also indicates
916 * "no namespace".
917 * SPEC XSLT 1.0:
918 * "If the string is empty, then the expanded-name of the
919 * attribute has a null namespace URI."
920 */
921 if ((tmpNsName != NULL) && (tmpNsName[0] != 0))
922 nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1);
923 xmlFree(tmpNsName);
924 }
925
926 if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
927 xsltTransformError(ctxt, NULL, inst,
928 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
929 "forbidden.\n");
930 goto error;
931 }
932 if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) {
933 prefix = BAD_CAST "xml";
934 } else if (xmlStrEqual(prefix, BAD_CAST "xml")) {
935 prefix = NULL;
936 }
937 } else if (prefix != NULL) {
938 /*
939 * SPEC XSLT 1.0:
940 * "If the namespace attribute is not present, then the QName is
941 * expanded into an expanded-name using the namespace declarations
942 * in effect for the xsl:attribute element, *not* including any
943 * default namespace declaration."
944 */
945 ns = xmlSearchNs(inst->doc, inst, prefix);
946 if (ns == NULL) {
947 /*
948 * Note that this is treated as an error now (checked with
949 * Saxon, Xalan-J and MSXML).
950 */
951 xsltTransformError(ctxt, NULL, inst,
952 "xsl:attribute: The QName '%s:%s' has no "
953 "namespace binding in scope in the stylesheet; "
954 "this is an error, since the namespace was not "
955 "specified by the instruction itself.\n", prefix, name);
956 } else
957 nsName = ns->href;
958 }
959
960 /*
961 * Find/create a matching ns-decl in the result tree.
962 */
963 ns = NULL;
964
965 #if 0
966 if (0) {
967 /*
968 * OPTIMIZE TODO: How do we know if we are adding to a
969 * fragment or to the result tree?
970 *
971 * If we are adding to a result tree fragment (i.e., not to the
972 * actual result tree), we'll don't bother searching for the
973 * ns-decl, but just store it in the dummy-doc of the result
974 * tree fragment.
975 */
976 if (nsName != NULL) {
977 /*
978 * TODO: Get the doc of @targetElem.
979 */
980 ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix);
981 }
982 }
983 #endif
984
985 if (nsName != NULL) {
986 /*
987 * Something about ns-prefixes:
988 * SPEC XSLT 1.0:
989 * "XSLT processors may make use of the prefix of the QName specified
990 * in the name attribute when selecting the prefix used for outputting
991 * the created attribute as XML; however, they are not required to do
992 * so and, if the prefix is xmlns, they must not do so"
993 */
994 /*
995 * xsl:attribute can produce a scenario where the prefix is NULL,
996 * so generate a prefix.
997 */
998 if ((prefix == NULL) || xmlStrEqual(prefix, BAD_CAST "xmlns")) {
999 xmlChar *pref = xmlStrdup(BAD_CAST "ns_1");
1000
1001 ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, targetElem);
1002
1003 xmlFree(pref);
1004 } else {
1005 ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix,
1006 targetElem);
1007 }
1008 if (ns == NULL) {
1009 xsltTransformError(ctxt, NULL, inst,
1010 "Namespace fixup error: Failed to acquire an in-scope "
1011 "namespace binding for the generated attribute '{%s}%s'.\n",
1012 nsName, name);
1013 goto error;
1014 }
1015 }
1016 /*
1017 * Construction of the value
1018 * -------------------------
1019 */
1020 if (inst->children == NULL) {
1021 /*
1022 * No content.
1023 * TODO: Do we need to put the empty string in ?
1024 */
1025 attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) "");
1026 } else if ((inst->children->next == NULL) &&
1027 ((inst->children->type == XML_TEXT_NODE) ||
1028 (inst->children->type == XML_CDATA_SECTION_NODE)))
1029 {
1030 xmlNodePtr copyTxt;
1031
1032 /*
1033 * xmlSetNsProp() will take care of duplicates.
1034 */
1035 attr = xmlSetNsProp(ctxt->insert, ns, name, NULL);
1036 if (attr == NULL) /* TODO: report error ? */
1037 goto error;
1038 /*
1039 * This was taken over from xsltCopyText() (transform.c).
1040 */
1041 if (ctxt->internalized &&
1042 (ctxt->insert->doc != NULL) &&
1043 (ctxt->insert->doc->dict == ctxt->dict))
1044 {
1045 copyTxt = xmlNewText(NULL);
1046 if (copyTxt == NULL) /* TODO: report error */
1047 goto error;
1048 /*
1049 * This is a safe scenario where we don't need to lookup
1050 * the dict.
1051 */
1052 copyTxt->content = inst->children->content;
1053 /*
1054 * Copy "disable-output-escaping" information.
1055 * TODO: Does this have any effect for attribute values
1056 * anyway?
1057 */
1058 if (inst->children->name == xmlStringTextNoenc)
1059 copyTxt->name = xmlStringTextNoenc;
1060 } else {
1061 /*
1062 * Copy the value.
1063 */
1064 copyTxt = xmlNewText(inst->children->content);
1065 if (copyTxt == NULL) /* TODO: report error */
1066 goto error;
1067 }
1068 attr->children = attr->last = copyTxt;
1069 copyTxt->parent = (xmlNodePtr) attr;
1070 copyTxt->doc = attr->doc;
1071 /*
1072 * Copy "disable-output-escaping" information.
1073 * TODO: Does this have any effect for attribute values
1074 * anyway?
1075 */
1076 if (inst->children->name == xmlStringTextNoenc)
1077 copyTxt->name = xmlStringTextNoenc;
1078
1079 /*
1080 * since we create the attribute without content IDness must be
1081 * asserted as a second step
1082 */
1083 if ((copyTxt->content != NULL) &&
1084 (xmlIsID(attr->doc, attr->parent, attr)))
1085 xmlAddID(NULL, attr->doc, copyTxt->content, attr);
1086 } else {
1087 /*
1088 * The sequence constructor might be complex, so instantiate it.
1089 */
1090 value = xsltEvalTemplateString(ctxt, contextNode, inst);
1091 if (value != NULL) {
1092 attr = xmlSetNsProp(ctxt->insert, ns, name, value);
1093 xmlFree(value);
1094 } else {
1095 /*
1096 * TODO: Do we have to add the empty string to the attr?
1097 * TODO: Does a value of NULL indicate an
1098 * error in xsltEvalTemplateString() ?
1099 */
1100 attr = xmlSetNsProp(ctxt->insert, ns, name,
1101 (const xmlChar *) "");
1102 }
1103 }
1104
1105 error:
1106 return;
1107 }
1108
1109 /**
1110 * xsltApplyAttributeSet:
1111 * @ctxt: the XSLT stylesheet
1112 * @node: the node in the source tree.
1113 * @inst: the attribute node "xsl:use-attribute-sets"
1114 * @attrSets: the list of QNames of the attribute-sets to be applied
1115 *
1116 * Apply the xsl:use-attribute-sets.
1117 * If @attrSets is NULL, then @inst will be used to exctract this
1118 * value.
1119 * If both, @attrSets and @inst, are NULL, then this will do nothing.
1120 */
1121 void
1122 xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node,
1123 xmlNodePtr inst,
1124 const xmlChar *attrSets)
1125 {
1126 const xmlChar *ncname = NULL;
1127 const xmlChar *prefix = NULL;
1128 const xmlChar *curstr, *endstr;
1129 xsltAttrSetPtr set;
1130 xsltStylesheetPtr style;
1131
1132 if (attrSets == NULL) {
1133 if (inst == NULL)
1134 return;
1135 else {
1136 /*
1137 * Extract the value from @inst.
1138 */
1139 if (inst->type == XML_ATTRIBUTE_NODE) {
1140 if ( ((xmlAttrPtr) inst)->children != NULL)
1141 attrSets = ((xmlAttrPtr) inst)->children->content;
1142
1143 }
1144 if (attrSets == NULL) {
1145 /*
1146 * TODO: Return an error?
1147 */
1148 return;
1149 }
1150 }
1151 }
1152 /*
1153 * Parse/apply the list of QNames.
1154 */
1155 curstr = attrSets;
1156 while (*curstr != 0) {
1157 while (IS_BLANK(*curstr))
1158 curstr++;
1159 if (*curstr == 0)
1160 break;
1161 endstr = curstr;
1162 while ((*endstr != 0) && (!IS_BLANK(*endstr)))
1163 endstr++;
1164 curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr);
1165 if (curstr) {
1166 xmlNsPtr ns;
1167 const xmlChar *nsUri = NULL;
1168
1169 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
1170 xsltGenericDebug(xsltGenericDebugContext,
1171 "apply attribute set %s\n", curstr);
1172 #endif
1173
1174 if (xmlValidateQName(curstr, 0)) {
1175 xsltTransformError(ctxt, NULL, inst,
1176 "The name '%s' in use-attribute-sets is not a valid "
1177 "QName.\n", curstr);
1178 return;
1179 }
1180
1181 ncname = xsltSplitQName(ctxt->dict, curstr, &prefix);
1182 if (prefix != NULL) {
1183 ns = xmlSearchNs(inst->doc, inst, prefix);
1184 if (ns == NULL) {
1185 xsltTransformError(ctxt, NULL, inst,
1186 "use-attribute-set : No namespace found for QName "
1187 "'%s:%s'\n", prefix, ncname);
1188 return;
1189 }
1190 nsUri = ns->href;
1191 }
1192
1193 style = ctxt->style;
1194
1195 #ifdef WITH_DEBUGGER
1196 if ((style != NULL) &&
1197 (style->attributeSets != NULL) &&
1198 (ctxt->debugStatus != XSLT_DEBUG_NONE))
1199 {
1200 set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
1201 if ((set != NULL) && (set->attrs != NULL) &&
1202 (set->attrs->attr != NULL))
1203 xslHandleDebugger(set->attrs->attr->parent, node, NULL,
1204 ctxt);
1205 }
1206 #endif
1207 /*
1208 * Lookup the referenced attribute-set. All attribute sets were
1209 * moved to the top stylesheet so there's no need to iterate
1210 * imported stylesheets
1211 */
1212 set = xmlHashLookup2(style->attributeSets, ncname, nsUri);
1213 if (set != NULL) {
1214 xsltAttrElemPtr cur = set->attrs;
1215 while (cur != NULL) {
1216 if (cur->attr != NULL) {
1217 xsltAttribute(ctxt, node, cur->attr,
1218 cur->attr->psvi);
1219 }
1220 cur = cur->next;
1221 }
1222 }
1223 }
1224 curstr = endstr;
1225 }
1226 }
1227
1228 /**
1229 * xsltFreeAttributeSetsHashes:
1230 * @style: an XSLT stylesheet
1231 *
1232 * Free up the memory used by attribute sets
1233 */
1234 void
1235 xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) {
1236 if (style->attributeSets != NULL)
1237 xmlHashFree((xmlHashTablePtr) style->attributeSets,
1238 (xmlHashDeallocator) xsltFreeAttrSet);
1239 style->attributeSets = NULL;
1240 }
OLDNEW
« no previous file with comments | « third_party/libxslt/libxslt/attributes.h ('k') | third_party/libxslt/libxslt/attrvt.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698