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(xsltAttrSetPtr set
, xsltAttrSetContextPtr asctx
,
640 const xmlChar
*name
, const xmlChar
*ns
,
641 ATTRIBUTE_UNUSED
const xmlChar
*ignored
) {
642 xsltStylesheetPtr topStyle
= asctx
->topStyle
;
643 xsltStylesheetPtr style
= asctx
->style
;
645 xsltResolveAttrSet(set
, topStyle
, style
, name
, ns
, 1);
647 /* Move attribute sets to top stylesheet. */
648 if (style
!= topStyle
) {
650 * This imported stylesheet won't be visited anymore. Don't bother
651 * removing the hash entry.
653 if (xmlHashAddEntry2(topStyle
->attributeSets
, name
, ns
, set
) < 0) {
654 xsltGenericError(xsltGenericErrorContext
,
655 "xsl:attribute-set : internal error, can't move imported "
656 " attribute set %s\n", name
);
662 * xsltResolveStylesheetAttributeSet:
663 * @style: the XSLT stylesheet
665 * resolve the references between attribute sets.
668 xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style
) {
669 xsltStylesheetPtr cur
;
670 xsltAttrSetContext asctx
;
672 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
673 xsltGenericDebug(xsltGenericDebugContext
,
674 "Resolving attribute sets references\n");
676 asctx
.topStyle
= style
;
678 while (cur
!= NULL
) {
679 if (cur
->attributeSets
!= NULL
) {
680 if (style
->attributeSets
== NULL
) {
681 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
682 xsltGenericDebug(xsltGenericDebugContext
,
683 "creating attribute set table\n");
685 style
->attributeSets
= xmlHashCreate(10);
688 xmlHashScanFull(cur
->attributeSets
,
689 (xmlHashScannerFull
) xsltResolveSASCallback
, &asctx
);
693 * the attribute lists have either been migrated to style
694 * or freed directly in xsltResolveSASCallback()
696 xmlHashFree(cur
->attributeSets
, NULL
);
697 cur
->attributeSets
= NULL
;
700 cur
= xsltNextImport(cur
);
706 * @ctxt: a XSLT process context
707 * @contextNode: the current node in the source tree
708 * @inst: the xsl:attribute element
709 * @castedComp: precomputed information
711 * Process the xslt attribute node on the source node
714 xsltAttribute(xsltTransformContextPtr ctxt
,
715 xmlNodePtr contextNode
,
717 xsltStylePreCompPtr castedComp
)
719 #ifdef XSLT_REFACTORED
720 xsltStyleItemAttributePtr comp
=
721 (xsltStyleItemAttributePtr
) castedComp
;
723 xsltStylePreCompPtr comp
= castedComp
;
725 xmlNodePtr targetElem
;
726 xmlChar
*prop
= NULL
;
727 const xmlChar
*name
= NULL
, *prefix
= NULL
, *nsName
= NULL
;
728 xmlChar
*value
= NULL
;
732 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
) ||
733 (inst
->type
!= XML_ELEMENT_NODE
) )
737 * A comp->has_name == 0 indicates that we need to skip this instruction,
738 * since it was evaluated to be invalid already during compilation.
743 * BIG NOTE: This previously used xsltGetSpecialNamespace() and
744 * xsltGetNamespace(), but since both are not appropriate, we
745 * will process namespace lookup here to avoid adding yet another
746 * ns-lookup function to namespaces.c.
749 * SPEC XSLT 1.0: Error cases:
750 * - Creating nodes other than text nodes during the instantiation of
751 * the content of the xsl:attribute element; implementations may
752 * either signal the error or ignore the offending nodes."
756 xsltTransformError(ctxt
, NULL
, inst
,
757 "Internal error in xsltAttribute(): "
758 "The XSLT 'attribute' instruction was not compiled.\n");
762 * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
763 * So report an internal error?
765 if (ctxt
->insert
== NULL
)
769 * "Adding an attribute to a node that is not an element;
770 * implementations may either signal the error or ignore the attribute."
772 * TODO: I think we should signal such errors in the future, and maybe
773 * provide an option to ignore such errors.
775 targetElem
= ctxt
->insert
;
776 if (targetElem
->type
!= XML_ELEMENT_NODE
)
781 * "Adding an attribute to an element after children have been added
782 * to it; implementations may either signal the error or ignore the
785 * TODO: We should decide whether not to report such errors or
786 * to ignore them; note that we *ignore* if the parent is not an
787 * element, but here we report an error.
789 if (targetElem
->children
!= NULL
) {
791 * NOTE: Ah! This seems to be intended to support streamed
792 * result generation!.
794 xsltTransformError(ctxt
, NULL
, inst
,
795 "xsl:attribute: Cannot add attributes to an "
796 "element if children have been already added "
797 "to the element.\n");
807 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
808 xslHandleDebugger(inst
, contextNode
, NULL
, ctxt
);
811 if (comp
->name
== NULL
) {
812 /* TODO: fix attr acquisition wrt to the XSLT namespace */
813 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
814 (const xmlChar
*) "name", XSLT_NAMESPACE
);
816 xsltTransformError(ctxt
, NULL
, inst
,
817 "xsl:attribute: The attribute 'name' is missing.\n");
820 if (xmlValidateQName(prop
, 0)) {
821 xsltTransformError(ctxt
, NULL
, inst
,
822 "xsl:attribute: The effective name '%s' is not a "
823 "valid QName.\n", prop
);
824 /* we fall through to catch any further errors, if possible */
828 * Reject a name of "xmlns".
830 if (xmlStrEqual(prop
, BAD_CAST
"xmlns")) {
831 xsltTransformError(ctxt
, NULL
, inst
,
832 "xsl:attribute: The effective name 'xmlns' is not allowed.\n");
837 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
841 * The "name" value was static.
843 #ifdef XSLT_REFACTORED
844 prefix
= comp
->nsPrefix
;
847 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
852 * Process namespace semantics
853 * ---------------------------
855 * Evaluate the namespace name.
859 * The "namespace" attribute was existent.
861 if (comp
->ns
!= NULL
) {
863 * No AVT; just plain text for the namespace name.
865 if (comp
->ns
[0] != 0)
872 /* TODO: check attr acquisition wrt to the XSLT namespace */
873 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
874 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
876 * This fixes bug #302020: The AVT might also evaluate to the
877 * empty string; this means that the empty string also indicates
880 * "If the string is empty, then the expanded-name of the
881 * attribute has a null namespace URI."
883 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
884 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
888 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
889 xsltTransformError(ctxt
, NULL
, inst
,
890 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
894 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
895 prefix
= BAD_CAST
"xml";
896 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
899 } else if (prefix
!= NULL
) {
902 * "If the namespace attribute is not present, then the QName is
903 * expanded into an expanded-name using the namespace declarations
904 * in effect for the xsl:attribute element, *not* including any
905 * default namespace declaration."
907 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
910 * Note that this is treated as an error now (checked with
911 * Saxon, Xalan-J and MSXML).
913 xsltTransformError(ctxt
, NULL
, inst
,
914 "xsl:attribute: The QName '%s:%s' has no "
915 "namespace binding in scope in the stylesheet; "
916 "this is an error, since the namespace was not "
917 "specified by the instruction itself.\n", prefix
, name
);
923 * Find/create a matching ns-decl in the result tree.
930 * OPTIMIZE TODO: How do we know if we are adding to a
931 * fragment or to the result tree?
933 * If we are adding to a result tree fragment (i.e., not to the
934 * actual result tree), we'll don't bother searching for the
935 * ns-decl, but just store it in the dummy-doc of the result
938 if (nsName
!= NULL
) {
940 * TODO: Get the doc of @targetElem.
942 ns
= xsltTreeAcquireStoredNs(some doc
, nsName
, prefix
);
947 if (nsName
!= NULL
) {
949 * Something about ns-prefixes:
951 * "XSLT processors may make use of the prefix of the QName specified
952 * in the name attribute when selecting the prefix used for outputting
953 * the created attribute as XML; however, they are not required to do
954 * so and, if the prefix is xmlns, they must not do so"
957 * xsl:attribute can produce a scenario where the prefix is NULL,
958 * so generate a prefix.
960 if ((prefix
== NULL
) || xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
961 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
963 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, targetElem
);
967 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
971 xsltTransformError(ctxt
, NULL
, inst
,
972 "Namespace fixup error: Failed to acquire an in-scope "
973 "namespace binding for the generated attribute '{%s}%s'.\n",
979 * Construction of the value
980 * -------------------------
982 if (inst
->children
== NULL
) {
985 * TODO: Do we need to put the empty string in ?
987 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, (const xmlChar
*) "");
988 } else if ((inst
->children
->next
== NULL
) &&
989 ((inst
->children
->type
== XML_TEXT_NODE
) ||
990 (inst
->children
->type
== XML_CDATA_SECTION_NODE
)))
995 * xmlSetNsProp() will take care of duplicates.
997 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, NULL
);
998 if (attr
== NULL
) /* TODO: report error ? */
1001 * This was taken over from xsltCopyText() (transform.c).
1003 if (ctxt
->internalized
&&
1004 (ctxt
->insert
->doc
!= NULL
) &&
1005 (ctxt
->insert
->doc
->dict
== ctxt
->dict
))
1007 copyTxt
= xmlNewText(NULL
);
1008 if (copyTxt
== NULL
) /* TODO: report error */
1011 * This is a safe scenario where we don't need to lookup
1014 copyTxt
->content
= inst
->children
->content
;
1016 * Copy "disable-output-escaping" information.
1017 * TODO: Does this have any effect for attribute values
1020 if (inst
->children
->name
== xmlStringTextNoenc
)
1021 copyTxt
->name
= xmlStringTextNoenc
;
1026 copyTxt
= xmlNewText(inst
->children
->content
);
1027 if (copyTxt
== NULL
) /* TODO: report error */
1030 attr
->children
= attr
->last
= copyTxt
;
1031 copyTxt
->parent
= (xmlNodePtr
) attr
;
1032 copyTxt
->doc
= attr
->doc
;
1034 * Copy "disable-output-escaping" information.
1035 * TODO: Does this have any effect for attribute values
1038 if (inst
->children
->name
== xmlStringTextNoenc
)
1039 copyTxt
->name
= xmlStringTextNoenc
;
1042 * since we create the attribute without content IDness must be
1043 * asserted as a second step
1045 if ((copyTxt
->content
!= NULL
) &&
1046 (xmlIsID(attr
->doc
, attr
->parent
, attr
)))
1047 xmlAddID(NULL
, attr
->doc
, copyTxt
->content
, attr
);
1050 * The sequence constructor might be complex, so instantiate it.
1052 value
= xsltEvalTemplateString(ctxt
, contextNode
, inst
);
1053 if (value
!= NULL
) {
1054 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, value
);
1058 * TODO: Do we have to add the empty string to the attr?
1059 * TODO: Does a value of NULL indicate an
1060 * error in xsltEvalTemplateString() ?
1062 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
,
1063 (const xmlChar
*) "");
1072 * xsltApplyAttributeSet:
1073 * @ctxt: the XSLT stylesheet
1074 * @node: the node in the source tree.
1075 * @inst: the attribute node "xsl:use-attribute-sets"
1076 * @attrSets: the list of QNames of the attribute-sets to be applied
1078 * Apply the xsl:use-attribute-sets.
1079 * If @attrSets is NULL, then @inst will be used to exctract this
1081 * If both, @attrSets and @inst, are NULL, then this will do nothing.
1084 xsltApplyAttributeSet(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1086 const xmlChar
*attrSets
)
1088 const xmlChar
*ncname
= NULL
;
1089 const xmlChar
*prefix
= NULL
;
1090 const xmlChar
*curstr
, *endstr
;
1092 xsltStylesheetPtr style
;
1094 if (attrSets
== NULL
) {
1099 * Extract the value from @inst.
1101 if (inst
->type
== XML_ATTRIBUTE_NODE
) {
1102 if ( ((xmlAttrPtr
) inst
)->children
!= NULL
)
1103 attrSets
= ((xmlAttrPtr
) inst
)->children
->content
;
1106 if (attrSets
== NULL
) {
1108 * TODO: Return an error?
1115 * Parse/apply the list of QNames.
1118 while (*curstr
!= 0) {
1119 while (IS_BLANK(*curstr
))
1124 while ((*endstr
!= 0) && (!IS_BLANK(*endstr
)))
1126 curstr
= xmlDictLookup(ctxt
->dict
, curstr
, endstr
- curstr
);
1129 const xmlChar
*nsUri
= NULL
;
1131 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
1132 xsltGenericDebug(xsltGenericDebugContext
,
1133 "apply attribute set %s\n", curstr
);
1136 if (xmlValidateQName(curstr
, 0)) {
1137 xsltTransformError(ctxt
, NULL
, inst
,
1138 "The name '%s' in use-attribute-sets is not a valid "
1139 "QName.\n", curstr
);
1143 ncname
= xsltSplitQName(ctxt
->dict
, curstr
, &prefix
);
1144 if (prefix
!= NULL
) {
1145 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
1147 xsltTransformError(ctxt
, NULL
, inst
,
1148 "use-attribute-set : No namespace found for QName "
1149 "'%s:%s'\n", prefix
, ncname
);
1155 style
= ctxt
->style
;
1157 #ifdef WITH_DEBUGGER
1158 if ((style
!= NULL
) &&
1159 (style
->attributeSets
!= NULL
) &&
1160 (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
))
1162 set
= xmlHashLookup2(style
->attributeSets
, ncname
, nsUri
);
1163 if ((set
!= NULL
) && (set
->attrs
!= NULL
) &&
1164 (set
->attrs
->attr
!= NULL
))
1165 xslHandleDebugger(set
->attrs
->attr
->parent
, node
, NULL
,
1170 * Lookup the referenced attribute-set. All attribute sets were
1171 * moved to the top stylesheet so there's no need to iterate
1172 * imported stylesheets
1174 set
= xmlHashLookup2(style
->attributeSets
, ncname
, nsUri
);
1176 xsltAttrElemPtr cur
= set
->attrs
;
1177 while (cur
!= NULL
) {
1178 if (cur
->attr
!= NULL
) {
1179 xsltAttribute(ctxt
, node
, cur
->attr
,
1191 * xsltFreeAttributeSetsHashes:
1192 * @style: an XSLT stylesheet
1194 * Free up the memory used by attribute sets
1197 xsltFreeAttributeSetsHashes(xsltStylesheetPtr style
) {
1198 if (style
->attributeSets
!= NULL
)
1199 xmlHashFree((xmlHashTablePtr
) style
->attributeSets
,
1200 (xmlHashDeallocator
) xsltFreeAttrSet
);
1201 style
->attributeSets
= NULL
;