2 * attributes.c: Implementation of the XSLT attributes handling
5 * http://www.w3.org/TR/1999/REC-xslt-19991116
7 * See Copyright for the status of this software.
14 #define WITH_XSLT_DEBUG_ATTRIBUTES
15 #ifdef WITH_XSLT_DEBUG
16 #define WITH_XSLT_DEBUG_ATTRIBUTES
26 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
29 #define IS_BLANK_NODE(n) \
30 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
32 #define ATTRSET_UNRESOLVED 0
33 #define ATTRSET_RESOLVING 1
34 #define ATTRSET_RESOLVED 2
38 * The in-memory structure corresponding to an XSLT Attribute in
43 typedef struct _xsltAttrElem xsltAttrElem
;
44 typedef xsltAttrElem
*xsltAttrElemPtr
;
45 struct _xsltAttrElem
{
46 struct _xsltAttrElem
*next
;/* chained list */
47 xmlNodePtr attr
; /* the xsl:attribute definition */
50 typedef struct _xsltUseAttrSet xsltUseAttrSet
;
51 typedef xsltUseAttrSet
*xsltUseAttrSetPtr
;
52 struct _xsltUseAttrSet
{
53 struct _xsltUseAttrSet
*next
; /* chained list */
54 const xmlChar
*ncname
;
58 typedef struct _xsltAttrSet xsltAttrSet
;
59 typedef xsltAttrSet
*xsltAttrSetPtr
;
62 xsltAttrElemPtr attrs
; /* list head */
63 xsltUseAttrSetPtr useAttrSets
; /* list head */
66 typedef struct _xsltAttrSetContext xsltAttrSetContext
;
67 typedef xsltAttrSetContext
*xsltAttrSetContextPtr
;
68 struct _xsltAttrSetContext
{
69 xsltStylesheetPtr topStyle
;
70 xsltStylesheetPtr style
;
74 xsltResolveAttrSet(xsltAttrSetPtr set
, xsltStylesheetPtr topStyle
,
75 xsltStylesheetPtr style
, const xmlChar
*name
,
76 const xmlChar
*ns
, int depth
);
78 /************************************************************************
80 * XSLT Attribute handling *
82 ************************************************************************/
86 * @attr: the new xsl:attribute node
88 * Create a new XSLT AttrElem
90 * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
92 static xsltAttrElemPtr
93 xsltNewAttrElem(xmlNodePtr attr
) {
96 cur
= (xsltAttrElemPtr
) xmlMalloc(sizeof(xsltAttrElem
));
98 xsltGenericError(xsltGenericErrorContext
,
99 "xsltNewAttrElem : malloc failed\n");
102 memset(cur
, 0, sizeof(xsltAttrElem
));
109 * @attr: an XSLT AttrElem
111 * Free up the memory allocated by @attr
114 xsltFreeAttrElem(xsltAttrElemPtr attr
) {
119 * xsltFreeAttrElemList:
120 * @list: an XSLT AttrElem list
122 * Free up the memory allocated by @list
125 xsltFreeAttrElemList(xsltAttrElemPtr list
) {
126 xsltAttrElemPtr next
;
128 while (list
!= NULL
) {
130 xsltFreeAttrElem(list
);
136 * xsltAddAttrElemList:
137 * @list: an XSLT AttrElem list
138 * @attr: the new xsl:attribute node
140 * Add the new attribute to the list.
142 * Returns the new list pointer
144 static xsltAttrElemPtr
145 xsltAddAttrElemList(xsltAttrElemPtr list
, xmlNodePtr attr
) {
146 xsltAttrElemPtr next
, cur
;
151 return(xsltNewAttrElem(attr
));
153 while (cur
!= NULL
) {
156 cur
->next
= xsltNewAttrElem(attr
);
166 * @ncname: local name
169 * Create a new XSLT UseAttrSet
171 * Returns the newly allocated xsltUseAttrSetPtr or NULL in case of error.
173 static xsltUseAttrSetPtr
174 xsltNewUseAttrSet(const xmlChar
*ncname
, const xmlChar
*ns
) {
175 xsltUseAttrSetPtr cur
;
177 cur
= (xsltUseAttrSetPtr
) xmlMalloc(sizeof(xsltUseAttrSet
));
179 xsltGenericError(xsltGenericErrorContext
,
180 "xsltNewUseAttrSet : malloc failed\n");
183 memset(cur
, 0, sizeof(xsltUseAttrSet
));
184 cur
->ncname
= ncname
;
190 * xsltFreeUseAttrSet:
191 * @use: an XSLT UseAttrSet
193 * Free up the memory allocated by @use
196 xsltFreeUseAttrSet(xsltUseAttrSetPtr use
) {
201 * xsltFreeUseAttrSetList:
202 * @list: an XSLT UseAttrSet list
204 * Free up the memory allocated by @list
207 xsltFreeUseAttrSetList(xsltUseAttrSetPtr list
) {
208 xsltUseAttrSetPtr next
;
210 while (list
!= NULL
) {
212 xsltFreeUseAttrSet(list
);
218 * xsltAddUseAttrSetList:
219 * @list: a xsltUseAttrSet list
220 * @ncname: local name
223 * Add the use-attribute-set name to the list.
225 * Returns the new list pointer.
227 static xsltUseAttrSetPtr
228 xsltAddUseAttrSetList(xsltUseAttrSetPtr list
, const xmlChar
*ncname
,
230 xsltUseAttrSetPtr next
, cur
;
235 return(xsltNewUseAttrSet(ncname
, ns
));
237 while (cur
!= NULL
) {
238 if ((cur
->ncname
== ncname
) && (cur
->ns
== ns
))
242 cur
->next
= xsltNewUseAttrSet(ncname
, ns
);
253 * Create a new attribute set.
255 * Returns the newly allocated xsltAttrSetPtr or NULL in case of error.
257 static xsltAttrSetPtr
261 cur
= (xsltAttrSetPtr
) xmlMalloc(sizeof(xsltAttrSet
));
263 xsltGenericError(xsltGenericErrorContext
,
264 "xsltNewAttrSet : malloc failed\n");
267 memset(cur
, 0, sizeof(xsltAttrSet
));
273 * @set: an attribute set
275 * Free memory allocated by @set
278 xsltFreeAttrSet(xsltAttrSetPtr set
) {
282 xsltFreeAttrElemList(set
->attrs
);
283 xsltFreeUseAttrSetList(set
->useAttrSets
);
289 * @set: an attribute set
290 * @other: another attribute set
292 * Add all the attributes from @other to @set,
293 * but drop redefinition of existing values.
296 xsltMergeAttrSets(xsltAttrSetPtr set
, xsltAttrSetPtr other
) {
298 xsltAttrElemPtr old
= other
->attrs
;
301 while (old
!= NULL
) {
303 * Check that the attribute is not yet in the list
307 while (cur
!= NULL
) {
308 xsltStylePreCompPtr curComp
= cur
->attr
->psvi
;
309 xsltStylePreCompPtr oldComp
= old
->attr
->psvi
;
311 if ((curComp
->name
== oldComp
->name
) &&
312 (curComp
->ns
== oldComp
->ns
)) {
316 if (cur
->next
== NULL
)
323 set
->attrs
= xsltNewAttrElem(old
->attr
);
325 cur
->next
= xsltNewAttrElem(old
->attr
);
333 /************************************************************************
335 * Module interfaces *
337 ************************************************************************/
340 * xsltParseStylesheetAttributeSet:
341 * @style: the XSLT stylesheet
342 * @cur: the "attribute-set" element
344 * parse an XSLT stylesheet attribute-set element
348 xsltParseStylesheetAttributeSet(xsltStylesheetPtr style
, xmlNodePtr cur
) {
349 const xmlChar
*ncname
;
350 const xmlChar
*prefix
;
351 const xmlChar
*nsUri
= NULL
;
356 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
359 value
= xmlGetNsProp(cur
, (const xmlChar
*)"name", NULL
);
360 if ((value
== NULL
) || (*value
== 0)) {
361 xsltGenericError(xsltGenericErrorContext
,
362 "xsl:attribute-set : name is missing\n");
368 if (xmlValidateQName(value
, 0)) {
369 xsltTransformError(NULL
, style
, cur
,
370 "xsl:attribute-set : The name '%s' is not a valid QName.\n",
377 ncname
= xsltSplitQName(style
->dict
, value
, &prefix
);
380 if (prefix
!= NULL
) {
381 xmlNsPtr ns
= xmlSearchNs(style
->doc
, cur
, prefix
);
383 xsltTransformError(NULL
, style
, cur
,
384 "xsl:attribute-set : No namespace found for QName '%s:%s'\n",
392 if (style
->attributeSets
== NULL
) {
393 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
394 xsltGenericDebug(xsltGenericDebugContext
,
395 "creating attribute set table\n");
397 style
->attributeSets
= xmlHashCreate(10);
399 if (style
->attributeSets
== NULL
)
402 set
= xmlHashLookup2(style
->attributeSets
, ncname
, nsUri
);
404 set
= xsltNewAttrSet();
407 xmlHashAddEntry2(style
->attributeSets
, ncname
, nsUri
, set
);
411 * Parse the content. Only xsl:attribute elements are allowed.
413 child
= cur
->children
;
414 while (child
!= NULL
) {
416 * Report invalid nodes.
418 if ((child
->type
!= XML_ELEMENT_NODE
) ||
419 (child
->ns
== NULL
) ||
420 (! IS_XSLT_ELEM(child
)))
422 if (child
->type
== XML_ELEMENT_NODE
)
423 xsltTransformError(NULL
, style
, child
,
424 "xsl:attribute-set : unexpected child %s\n",
427 xsltTransformError(NULL
, style
, child
,
428 "xsl:attribute-set : child of unexpected type\n");
429 } else if (!IS_XSLT_NAME(child
, "attribute")) {
430 xsltTransformError(NULL
, style
, child
,
431 "xsl:attribute-set : unexpected child xsl:%s\n",
434 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
435 xsltGenericDebug(xsltGenericDebugContext
,
436 "add attribute to list %s\n", ncname
);
438 xsltStylePreCompute(style
, child
);
439 if (child
->children
!= NULL
) {
440 #ifdef XSLT_REFACTORED
441 xsltParseSequenceConstructor(XSLT_CCTXT(style
),
444 xsltParseTemplateContent(style
, child
);
447 if (child
->psvi
== NULL
) {
448 xsltTransformError(NULL
, style
, child
,
449 "xsl:attribute-set : internal error, attribute %s not "
450 "compiled\n", child
->name
);
453 set
->attrs
= xsltAddAttrElemList(set
->attrs
, child
);
461 * Process attribute "use-attribute-sets".
463 value
= xmlGetNsProp(cur
, BAD_CAST
"use-attribute-sets", NULL
);
465 const xmlChar
*curval
, *endval
;
467 while (*curval
!= 0) {
468 while (IS_BLANK(*curval
)) curval
++;
472 while ((*endval
!= 0) && (!IS_BLANK(*endval
))) endval
++;
473 curval
= xmlDictLookup(style
->dict
, curval
, endval
- curval
);
475 const xmlChar
*ncname2
= NULL
;
476 const xmlChar
*prefix2
= NULL
;
477 const xmlChar
*nsUri2
= NULL
;
479 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
480 xsltGenericDebug(xsltGenericDebugContext
,
481 "xsl:attribute-set : %s adds use %s\n", ncname
, curval
);
484 if (xmlValidateQName(curval
, 0)) {
485 xsltTransformError(NULL
, style
, cur
,
486 "xsl:attribute-set : The name '%s' in "
487 "use-attribute-sets is not a valid QName.\n", curval
);
493 ncname2
= xsltSplitQName(style
->dict
, curval
, &prefix2
);
494 if (prefix2
!= NULL
) {
495 xmlNsPtr ns2
= xmlSearchNs(style
->doc
, cur
, prefix2
);
497 xsltTransformError(NULL
, style
, cur
,
498 "xsl:attribute-set : No namespace found for QName "
499 "'%s:%s' in use-attribute-sets\n",
507 set
->useAttrSets
= xsltAddUseAttrSetList(set
->useAttrSets
,
516 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
517 xsltGenericDebug(xsltGenericDebugContext
,
518 "updated attribute list %s\n", ncname
);
523 * xsltResolveUseAttrSets:
524 * @set: the attribute set
525 * @asctx: the context for attribute set resolution
526 * @depth: recursion depth
528 * Process "use-attribute-sets".
531 xsltResolveUseAttrSets(xsltAttrSetPtr set
, xsltStylesheetPtr topStyle
,
533 xsltStylesheetPtr cur
;
534 xsltAttrSetPtr other
;
535 xsltUseAttrSetPtr use
= set
->useAttrSets
;
536 xsltUseAttrSetPtr next
;
538 while (use
!= NULL
) {
540 * Iterate top stylesheet and all imports.
543 while (cur
!= NULL
) {
544 if (cur
->attributeSets
) {
545 other
= xmlHashLookup2(cur
->attributeSets
, use
->ncname
,
548 xsltResolveAttrSet(other
, topStyle
, cur
, use
->ncname
,
550 xsltMergeAttrSets(set
, other
);
554 cur
= xsltNextImport(cur
);
558 /* Free useAttrSets early. */
559 xsltFreeUseAttrSet(use
);
563 set
->useAttrSets
= NULL
;
567 * xsltResolveAttrSet:
568 * @set: the attribute set
569 * @asctx: the context for attribute set resolution
570 * @name: the local name of the attirbute set
571 * @ns: the namespace of the attribute set
572 * @depth: recursion depth
574 * resolve the references in an attribute set.
577 xsltResolveAttrSet(xsltAttrSetPtr set
, xsltStylesheetPtr topStyle
,
578 xsltStylesheetPtr style
, const xmlChar
*name
,
579 const xmlChar
*ns
, int depth
) {
580 xsltStylesheetPtr cur
;
581 xsltAttrSetPtr other
;
583 if (set
->state
== ATTRSET_RESOLVED
)
585 if (set
->state
== ATTRSET_RESOLVING
) {
586 xsltTransformError(NULL
, topStyle
, NULL
,
587 "xsl:attribute-set : use-attribute-sets recursion detected"
590 set
->state
= ATTRSET_RESOLVED
;
594 xsltTransformError(NULL
, topStyle
, NULL
,
595 "xsl:attribute-set : use-attribute-sets maximum recursion "
596 "depth exceeded on %s\n", name
);
601 set
->state
= ATTRSET_RESOLVING
;
603 xsltResolveUseAttrSets(set
, topStyle
, depth
);
605 /* Merge imported sets. */
606 cur
= xsltNextImport(style
);
607 while (cur
!= NULL
) {
608 if (cur
->attributeSets
!= NULL
) {
609 other
= xmlHashLookup2(cur
->attributeSets
, name
, ns
);
612 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
613 xsltGenericDebug(xsltGenericDebugContext
,
614 "xsl:attribute-set : merging import for %s\n", name
);
616 xsltResolveUseAttrSets(other
, topStyle
, depth
);
617 xsltMergeAttrSets(set
, other
);
618 xmlHashRemoveEntry2(cur
->attributeSets
, name
, ns
, NULL
);
619 xsltFreeAttrSet(other
);
623 cur
= xsltNextImport(cur
);
626 set
->state
= ATTRSET_RESOLVED
;
630 * xsltResolveSASCallback:
631 * @set: the attribute set
632 * @asctx: the context for attribute set resolution
633 * @name: the local name of the attirbute set
634 * @ns: the namespace of the attribute set
636 * resolve the references in an attribute set.
639 xsltResolveSASCallback(void *payload
, void *data
,
640 const xmlChar
*name
, const xmlChar
*ns
,
641 ATTRIBUTE_UNUSED
const xmlChar
*ignored
) {
642 xsltAttrSetPtr set
= (xsltAttrSetPtr
) payload
;
643 xsltAttrSetContextPtr asctx
= (xsltAttrSetContextPtr
) data
;
644 xsltStylesheetPtr topStyle
= asctx
->topStyle
;
645 xsltStylesheetPtr style
= asctx
->style
;
647 xsltResolveAttrSet(set
, topStyle
, style
, name
, ns
, 1);
649 /* Move attribute sets to top stylesheet. */
650 if (style
!= topStyle
) {
652 * This imported stylesheet won't be visited anymore. Don't bother
653 * removing the hash entry.
655 if (xmlHashAddEntry2(topStyle
->attributeSets
, name
, ns
, set
) < 0) {
656 xsltGenericError(xsltGenericErrorContext
,
657 "xsl:attribute-set : internal error, can't move imported "
658 " attribute set %s\n", name
);
664 * xsltResolveStylesheetAttributeSet:
665 * @style: the XSLT stylesheet
667 * resolve the references between attribute sets.
670 xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style
) {
671 xsltStylesheetPtr cur
;
672 xsltAttrSetContext asctx
;
674 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
675 xsltGenericDebug(xsltGenericDebugContext
,
676 "Resolving attribute sets references\n");
678 asctx
.topStyle
= style
;
680 while (cur
!= NULL
) {
681 if (cur
->attributeSets
!= NULL
) {
682 if (style
->attributeSets
== NULL
) {
683 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
684 xsltGenericDebug(xsltGenericDebugContext
,
685 "creating attribute set table\n");
687 style
->attributeSets
= xmlHashCreate(10);
690 xmlHashScanFull(cur
->attributeSets
, xsltResolveSASCallback
,
695 * the attribute lists have either been migrated to style
696 * or freed directly in xsltResolveSASCallback()
698 xmlHashFree(cur
->attributeSets
, NULL
);
699 cur
->attributeSets
= NULL
;
702 cur
= xsltNextImport(cur
);
708 * @ctxt: a XSLT process context
709 * @contextNode: the current node in the source tree
710 * @inst: the xsl:attribute element
711 * @castedComp: precomputed information
713 * Process the xslt attribute node on the source node
716 xsltAttribute(xsltTransformContextPtr ctxt
,
717 xmlNodePtr contextNode
,
719 xsltElemPreCompPtr castedComp
)
721 #ifdef XSLT_REFACTORED
722 xsltStyleItemAttributePtr comp
=
723 (xsltStyleItemAttributePtr
) castedComp
;
725 xsltStylePreCompPtr comp
= (xsltStylePreCompPtr
) castedComp
;
727 xmlNodePtr targetElem
;
728 xmlChar
*prop
= NULL
;
729 const xmlChar
*name
= NULL
, *prefix
= NULL
, *nsName
= NULL
;
730 xmlChar
*value
= NULL
;
734 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
) ||
735 (inst
->type
!= XML_ELEMENT_NODE
) )
739 * A comp->has_name == 0 indicates that we need to skip this instruction,
740 * since it was evaluated to be invalid already during compilation.
745 * BIG NOTE: This previously used xsltGetSpecialNamespace() and
746 * xsltGetNamespace(), but since both are not appropriate, we
747 * will process namespace lookup here to avoid adding yet another
748 * ns-lookup function to namespaces.c.
751 * SPEC XSLT 1.0: Error cases:
752 * - Creating nodes other than text nodes during the instantiation of
753 * the content of the xsl:attribute element; implementations may
754 * either signal the error or ignore the offending nodes."
758 xsltTransformError(ctxt
, NULL
, inst
,
759 "Internal error in xsltAttribute(): "
760 "The XSLT 'attribute' instruction was not compiled.\n");
764 * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
765 * So report an internal error?
767 if (ctxt
->insert
== NULL
)
771 * "Adding an attribute to a node that is not an element;
772 * implementations may either signal the error or ignore the attribute."
774 * TODO: I think we should signal such errors in the future, and maybe
775 * provide an option to ignore such errors.
777 targetElem
= ctxt
->insert
;
778 if (targetElem
->type
!= XML_ELEMENT_NODE
)
783 * "Adding an attribute to an element after children have been added
784 * to it; implementations may either signal the error or ignore the
787 * TODO: We should decide whether not to report such errors or
788 * to ignore them; note that we *ignore* if the parent is not an
789 * element, but here we report an error.
791 if (targetElem
->children
!= NULL
) {
793 * NOTE: Ah! This seems to be intended to support streamed
794 * result generation!.
796 xsltTransformError(ctxt
, NULL
, inst
,
797 "xsl:attribute: Cannot add attributes to an "
798 "element if children have been already added "
799 "to the element.\n");
809 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
810 xslHandleDebugger(inst
, contextNode
, NULL
, ctxt
);
813 if (comp
->name
== NULL
) {
814 /* TODO: fix attr acquisition wrt to the XSLT namespace */
815 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
816 (const xmlChar
*) "name", XSLT_NAMESPACE
);
818 xsltTransformError(ctxt
, NULL
, inst
,
819 "xsl:attribute: The attribute 'name' is missing.\n");
822 if (xmlValidateQName(prop
, 0)) {
823 xsltTransformError(ctxt
, NULL
, inst
,
824 "xsl:attribute: The effective name '%s' is not a "
825 "valid QName.\n", prop
);
826 /* we fall through to catch any further errors, if possible */
830 * Reject a name of "xmlns".
832 if (xmlStrEqual(prop
, BAD_CAST
"xmlns")) {
833 xsltTransformError(ctxt
, NULL
, inst
,
834 "xsl:attribute: The effective name 'xmlns' is not allowed.\n");
839 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
843 * The "name" value was static.
845 #ifdef XSLT_REFACTORED
846 prefix
= comp
->nsPrefix
;
849 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
854 * Process namespace semantics
855 * ---------------------------
857 * Evaluate the namespace name.
861 * The "namespace" attribute was existent.
863 if (comp
->ns
!= NULL
) {
865 * No AVT; just plain text for the namespace name.
867 if (comp
->ns
[0] != 0)
874 /* TODO: check attr acquisition wrt to the XSLT namespace */
875 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
876 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
878 * This fixes bug #302020: The AVT might also evaluate to the
879 * empty string; this means that the empty string also indicates
882 * "If the string is empty, then the expanded-name of the
883 * attribute has a null namespace URI."
885 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
886 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
890 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
891 xsltTransformError(ctxt
, NULL
, inst
,
892 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
896 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
897 prefix
= BAD_CAST
"xml";
898 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
901 } else if (prefix
!= NULL
) {
904 * "If the namespace attribute is not present, then the QName is
905 * expanded into an expanded-name using the namespace declarations
906 * in effect for the xsl:attribute element, *not* including any
907 * default namespace declaration."
909 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
912 * Note that this is treated as an error now (checked with
913 * Saxon, Xalan-J and MSXML).
915 xsltTransformError(ctxt
, NULL
, inst
,
916 "xsl:attribute: The QName '%s:%s' has no "
917 "namespace binding in scope in the stylesheet; "
918 "this is an error, since the namespace was not "
919 "specified by the instruction itself.\n", prefix
, name
);
925 * Find/create a matching ns-decl in the result tree.
932 * OPTIMIZE TODO: How do we know if we are adding to a
933 * fragment or to the result tree?
935 * If we are adding to a result tree fragment (i.e., not to the
936 * actual result tree), we'll don't bother searching for the
937 * ns-decl, but just store it in the dummy-doc of the result
940 if (nsName
!= NULL
) {
942 * TODO: Get the doc of @targetElem.
944 ns
= xsltTreeAcquireStoredNs(some doc
, nsName
, prefix
);
949 if (nsName
!= NULL
) {
951 * Something about ns-prefixes:
953 * "XSLT processors may make use of the prefix of the QName specified
954 * in the name attribute when selecting the prefix used for outputting
955 * the created attribute as XML; however, they are not required to do
956 * so and, if the prefix is xmlns, they must not do so"
959 * xsl:attribute can produce a scenario where the prefix is NULL,
960 * so generate a prefix.
962 if ((prefix
== NULL
) || xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
963 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
965 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, targetElem
);
969 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
973 xsltTransformError(ctxt
, NULL
, inst
,
974 "Namespace fixup error: Failed to acquire an in-scope "
975 "namespace binding for the generated attribute '{%s}%s'.\n",
981 * Construction of the value
982 * -------------------------
984 if (inst
->children
== NULL
) {
987 * TODO: Do we need to put the empty string in ?
989 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, (const xmlChar
*) "");
990 } else if ((inst
->children
->next
== NULL
) &&
991 ((inst
->children
->type
== XML_TEXT_NODE
) ||
992 (inst
->children
->type
== XML_CDATA_SECTION_NODE
)))
997 * xmlSetNsProp() will take care of duplicates.
999 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, NULL
);
1000 if (attr
== NULL
) /* TODO: report error ? */
1003 * This was taken over from xsltCopyText() (transform.c).
1005 if (ctxt
->internalized
&&
1006 (ctxt
->insert
->doc
!= NULL
) &&
1007 (ctxt
->insert
->doc
->dict
== ctxt
->dict
))
1009 copyTxt
= xmlNewText(NULL
);
1010 if (copyTxt
== NULL
) /* TODO: report error */
1013 * This is a safe scenario where we don't need to lookup
1016 copyTxt
->content
= inst
->children
->content
;
1018 * Copy "disable-output-escaping" information.
1019 * TODO: Does this have any effect for attribute values
1022 if (inst
->children
->name
== xmlStringTextNoenc
)
1023 copyTxt
->name
= xmlStringTextNoenc
;
1028 copyTxt
= xmlNewText(inst
->children
->content
);
1029 if (copyTxt
== NULL
) /* TODO: report error */
1032 attr
->children
= attr
->last
= copyTxt
;
1033 copyTxt
->parent
= (xmlNodePtr
) attr
;
1034 copyTxt
->doc
= attr
->doc
;
1036 * Copy "disable-output-escaping" information.
1037 * TODO: Does this have any effect for attribute values
1040 if (inst
->children
->name
== xmlStringTextNoenc
)
1041 copyTxt
->name
= xmlStringTextNoenc
;
1044 * since we create the attribute without content IDness must be
1045 * asserted as a second step
1047 if ((copyTxt
->content
!= NULL
) &&
1048 (xmlIsID(attr
->doc
, attr
->parent
, attr
)))
1049 xmlAddID(NULL
, attr
->doc
, copyTxt
->content
, attr
);
1052 * The sequence constructor might be complex, so instantiate it.
1054 value
= xsltEvalTemplateString(ctxt
, contextNode
, inst
);
1055 if (value
!= NULL
) {
1056 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, value
);
1060 * TODO: Do we have to add the empty string to the attr?
1061 * TODO: Does a value of NULL indicate an
1062 * error in xsltEvalTemplateString() ?
1064 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
,
1065 (const xmlChar
*) "");
1074 * xsltApplyAttributeSet:
1075 * @ctxt: the XSLT stylesheet
1076 * @node: the node in the source tree.
1077 * @inst: the attribute node "xsl:use-attribute-sets"
1078 * @attrSets: the list of QNames of the attribute-sets to be applied
1080 * Apply the xsl:use-attribute-sets.
1081 * If @attrSets is NULL, then @inst will be used to exctract this
1083 * If both, @attrSets and @inst, are NULL, then this will do nothing.
1086 xsltApplyAttributeSet(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1088 const xmlChar
*attrSets
)
1090 const xmlChar
*ncname
= NULL
;
1091 const xmlChar
*prefix
= NULL
;
1092 const xmlChar
*curstr
, *endstr
;
1094 xsltStylesheetPtr style
;
1096 if (attrSets
== NULL
) {
1101 * Extract the value from @inst.
1103 if (inst
->type
== XML_ATTRIBUTE_NODE
) {
1104 if ( ((xmlAttrPtr
) inst
)->children
!= NULL
)
1105 attrSets
= ((xmlAttrPtr
) inst
)->children
->content
;
1108 if (attrSets
== NULL
) {
1110 * TODO: Return an error?
1117 * Parse/apply the list of QNames.
1120 while (*curstr
!= 0) {
1121 while (IS_BLANK(*curstr
))
1126 while ((*endstr
!= 0) && (!IS_BLANK(*endstr
)))
1128 curstr
= xmlDictLookup(ctxt
->dict
, curstr
, endstr
- curstr
);
1131 const xmlChar
*nsUri
= NULL
;
1133 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
1134 xsltGenericDebug(xsltGenericDebugContext
,
1135 "apply attribute set %s\n", curstr
);
1138 if (xmlValidateQName(curstr
, 0)) {
1139 xsltTransformError(ctxt
, NULL
, inst
,
1140 "The name '%s' in use-attribute-sets is not a valid "
1141 "QName.\n", curstr
);
1145 ncname
= xsltSplitQName(ctxt
->dict
, curstr
, &prefix
);
1146 if (prefix
!= NULL
) {
1147 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
1149 xsltTransformError(ctxt
, NULL
, inst
,
1150 "use-attribute-set : No namespace found for QName "
1151 "'%s:%s'\n", prefix
, ncname
);
1157 style
= ctxt
->style
;
1159 #ifdef WITH_DEBUGGER
1160 if ((style
!= NULL
) &&
1161 (style
->attributeSets
!= NULL
) &&
1162 (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
))
1164 set
= xmlHashLookup2(style
->attributeSets
, ncname
, nsUri
);
1165 if ((set
!= NULL
) && (set
->attrs
!= NULL
) &&
1166 (set
->attrs
->attr
!= NULL
))
1167 xslHandleDebugger(set
->attrs
->attr
->parent
, node
, NULL
,
1172 * Lookup the referenced attribute-set. All attribute sets were
1173 * moved to the top stylesheet so there's no need to iterate
1174 * imported stylesheets
1176 set
= xmlHashLookup2(style
->attributeSets
, ncname
, nsUri
);
1178 xsltAttrElemPtr cur
= set
->attrs
;
1179 while (cur
!= NULL
) {
1180 if (cur
->attr
!= NULL
) {
1181 xsltAttribute(ctxt
, node
, cur
->attr
,
1193 xsltFreeAttributeSetsEntry(void *payload
,
1194 const xmlChar
*name ATTRIBUTE_UNUSED
) {
1195 xsltFreeAttrSet((xsltAttrSetPtr
) payload
);
1199 * xsltFreeAttributeSetsHashes:
1200 * @style: an XSLT stylesheet
1202 * Free up the memory used by attribute sets
1205 xsltFreeAttributeSetsHashes(xsltStylesheetPtr style
) {
1206 if (style
->attributeSets
!= NULL
)
1207 xmlHashFree((xmlHashTablePtr
) style
->attributeSets
,
1208 xsltFreeAttributeSetsEntry
);
1209 style
->attributeSets
= NULL
;