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.
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
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>
43 #include "xsltInternals.h"
44 #include "xsltutils.h"
45 #include "attributes.h"
46 #include "namespaces.h"
47 #include "templates.h"
49 #include "transform.h"
52 #define WITH_XSLT_DEBUG_ATTRIBUTES
53 #ifdef WITH_XSLT_DEBUG
54 #define WITH_XSLT_DEBUG_ATTRIBUTES
58 * TODO: merge attribute sets from different import precedence.
59 * all this should be precomputed just before the transformation
60 * starts or at first hit with a cache in the context.
61 * The simple way for now would be to not allow redefinition of
62 * attributes once generated in the output tree, possibly costlier.
72 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
75 #define IS_BLANK_NODE(n) \
76 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
80 * The in-memory structure corresponding to an XSLT Attribute in
85 typedef struct _xsltAttrElem xsltAttrElem
;
86 typedef xsltAttrElem
*xsltAttrElemPtr
;
87 struct _xsltAttrElem
{
88 struct _xsltAttrElem
*next
;/* chained list */
89 xmlNodePtr attr
; /* the xsl:attribute definition */
90 const xmlChar
*set
; /* or the attribute set */
91 const xmlChar
*ns
; /* and its namespace */
94 /************************************************************************
96 * XSLT Attribute handling *
98 ************************************************************************/
102 * @attr: the new xsl:attribute node
104 * Create a new XSLT AttrElem
106 * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
108 static xsltAttrElemPtr
109 xsltNewAttrElem(xmlNodePtr attr
) {
112 cur
= (xsltAttrElemPtr
) xmlMalloc(sizeof(xsltAttrElem
));
114 xsltGenericError(xsltGenericErrorContext
,
115 "xsltNewAttrElem : malloc failed\n");
118 memset(cur
, 0, sizeof(xsltAttrElem
));
125 * @attr: an XSLT AttrElem
127 * Free up the memory allocated by @attr
130 xsltFreeAttrElem(xsltAttrElemPtr attr
) {
135 * xsltFreeAttrElemList:
136 * @list: an XSLT AttrElem list
138 * Free up the memory allocated by @list
141 xsltFreeAttrElemList(xsltAttrElemPtr list
) {
142 xsltAttrElemPtr next
;
144 while (list
!= NULL
) {
146 xsltFreeAttrElem(list
);
151 #ifdef XSLT_REFACTORED
153 * This was moved to xsltParseStylesheetAttributeSet().
157 * xsltAddAttrElemList:
158 * @list: an XSLT AttrElem list
159 * @attr: the new xsl:attribute node
161 * Add the new attribute to the list.
163 * Returns the new list pointer
165 static xsltAttrElemPtr
166 xsltAddAttrElemList(xsltAttrElemPtr list
, xmlNodePtr attr
) {
167 xsltAttrElemPtr next
, cur
;
172 return(xsltNewAttrElem(attr
));
174 while (cur
!= NULL
) {
176 if (cur
->attr
== attr
)
178 if (cur
->next
== NULL
) {
179 cur
->next
= xsltNewAttrElem(attr
);
186 #endif /* XSLT_REFACTORED */
189 * xsltMergeAttrElemList:
190 * @list: an XSLT AttrElem list
191 * @old: another XSLT AttrElem list
193 * Add all the attributes from list @old to list @list,
194 * but drop redefinition of existing values.
196 * Returns the new list pointer
198 static xsltAttrElemPtr
199 xsltMergeAttrElemList(xsltStylesheetPtr style
,
200 xsltAttrElemPtr list
, xsltAttrElemPtr old
) {
204 while (old
!= NULL
) {
205 if ((old
->attr
== NULL
) && (old
->set
== NULL
)) {
210 * Check that the attribute is not yet in the list
214 while (cur
!= NULL
) {
215 if ((cur
->attr
== NULL
) && (cur
->set
== NULL
)) {
216 if (cur
->next
== NULL
)
221 if ((cur
->set
!= NULL
) && (cur
->set
== old
->set
)) {
225 if (cur
->set
!= NULL
) {
226 if (cur
->next
== NULL
)
231 if (old
->set
!= NULL
) {
232 if (cur
->next
== NULL
)
237 if (cur
->attr
== old
->attr
) {
238 xsltGenericError(xsltGenericErrorContext
,
239 "xsl:attribute-set : use-attribute-sets recursion detected\n");
242 if (cur
->next
== NULL
)
249 * Changed to use the string-dict, rather than duplicating
250 * @set and @ns; this fixes bug #340400.
253 list
= xsltNewAttrElem(old
->attr
);
254 if (old
->set
!= NULL
) {
255 list
->set
= xmlDictLookup(style
->dict
, old
->set
, -1);
257 list
->ns
= xmlDictLookup(style
->dict
, old
->ns
, -1);
260 cur
->next
= xsltNewAttrElem(old
->attr
);
261 if (old
->set
!= NULL
) {
262 cur
->next
->set
= xmlDictLookup(style
->dict
, old
->set
, -1);
264 cur
->next
->ns
= xmlDictLookup(style
->dict
, old
->ns
, -1);
274 /************************************************************************
276 * Module interfaces *
278 ************************************************************************/
281 * xsltParseStylesheetAttributeSet:
282 * @style: the XSLT stylesheet
283 * @cur: the "attribute-set" element
285 * parse an XSLT stylesheet attribute-set element
289 xsltParseStylesheetAttributeSet(xsltStylesheetPtr style
, xmlNodePtr cur
) {
290 const xmlChar
*ncname
;
291 const xmlChar
*prefix
;
294 xsltAttrElemPtr attrItems
;
296 if ((cur
== NULL
) || (style
== NULL
))
299 value
= xmlGetNsProp(cur
, (const xmlChar
*)"name", NULL
);
301 xsltGenericError(xsltGenericErrorContext
,
302 "xsl:attribute-set : name is missing\n");
306 ncname
= xsltSplitQName(style
->dict
, value
, &prefix
);
310 if (style
->attributeSets
== NULL
) {
311 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
312 xsltGenericDebug(xsltGenericDebugContext
,
313 "creating attribute set table\n");
315 style
->attributeSets
= xmlHashCreate(10);
317 if (style
->attributeSets
== NULL
)
320 attrItems
= xmlHashLookup2(style
->attributeSets
, ncname
, prefix
);
323 * Parse the content. Only xsl:attribute elements are allowed.
325 child
= cur
->children
;
326 while (child
!= NULL
) {
328 * Report invalid nodes.
330 if ((child
->type
!= XML_ELEMENT_NODE
) ||
331 (child
->ns
== NULL
) ||
332 (! IS_XSLT_ELEM(child
)))
334 if (child
->type
== XML_ELEMENT_NODE
)
335 xsltTransformError(NULL
, style
, child
,
336 "xsl:attribute-set : unexpected child %s\n",
339 xsltTransformError(NULL
, style
, child
,
340 "xsl:attribute-set : child of unexpected type\n");
341 } else if (!IS_XSLT_NAME(child
, "attribute")) {
342 xsltTransformError(NULL
, style
, child
,
343 "xsl:attribute-set : unexpected child xsl:%s\n",
346 #ifdef XSLT_REFACTORED
347 xsltAttrElemPtr nextAttr
, curAttr
;
350 * Process xsl:attribute
351 * ---------------------
354 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
355 xsltGenericDebug(xsltGenericDebugContext
,
356 "add attribute to list %s\n", ncname
);
359 * The following was taken over from
360 * xsltAddAttrElemList().
362 if (attrItems
== NULL
) {
363 attrItems
= xsltNewAttrElem(child
);
366 while (curAttr
!= NULL
) {
367 nextAttr
= curAttr
->next
;
368 if (curAttr
->attr
== child
) {
370 * URGENT TODO: Can somebody explain
371 * why attrItems is set to curAttr
372 * here? Is this somehow related to
373 * avoidance of recursions?
378 if (curAttr
->next
== NULL
)
379 curAttr
->next
= xsltNewAttrElem(child
);
384 * Parse the xsl:attribute and its content.
386 xsltParseAnyXSLTElem(XSLT_CCTXT(style
), child
);
388 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
389 xsltGenericDebug(xsltGenericDebugContext
,
390 "add attribute to list %s\n", ncname
);
395 attrItems
= xsltAddAttrElemList(attrItems
, child
);
399 #ifdef XSLT_REFACTORED
406 * Process attribue "use-attribute-sets".
408 /* TODO check recursion */
409 value
= xmlGetNsProp(cur
, (const xmlChar
*)"use-attribute-sets",
412 const xmlChar
*curval
, *endval
;
414 while (*curval
!= 0) {
415 while (IS_BLANK(*curval
)) curval
++;
419 while ((*endval
!= 0) && (!IS_BLANK(*endval
))) endval
++;
420 curval
= xmlDictLookup(style
->dict
, curval
, endval
- curval
);
422 const xmlChar
*ncname2
= NULL
;
423 const xmlChar
*prefix2
= NULL
;
424 xsltAttrElemPtr refAttrItems
;
426 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
427 xsltGenericDebug(xsltGenericDebugContext
,
428 "xsl:attribute-set : %s adds use %s\n", ncname
, curval
);
430 ncname2
= xsltSplitQName(style
->dict
, curval
, &prefix2
);
431 refAttrItems
= xsltNewAttrElem(NULL
);
432 if (refAttrItems
!= NULL
) {
433 refAttrItems
->set
= ncname2
;
434 refAttrItems
->ns
= prefix2
;
435 attrItems
= xsltMergeAttrElemList(style
,
436 attrItems
, refAttrItems
);
437 xsltFreeAttrElem(refAttrItems
);
450 * TODO: Why is this dummy entry needed.?
452 if (attrItems
== NULL
)
453 attrItems
= xsltNewAttrElem(NULL
);
454 xmlHashUpdateEntry2(style
->attributeSets
, ncname
, prefix
, attrItems
, NULL
);
455 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
456 xsltGenericDebug(xsltGenericDebugContext
,
457 "updated attribute list %s\n", ncname
);
463 * @style: the XSLT stylesheet
464 * @name: the attribute list name
465 * @ns: the attribute list namespace
467 * lookup an attribute set based on the style cascade
469 * Returns the attribute set or NULL
471 static xsltAttrElemPtr
472 xsltGetSAS(xsltStylesheetPtr style
, const xmlChar
*name
, const xmlChar
*ns
) {
473 xsltAttrElemPtr values
;
475 while (style
!= NULL
) {
476 values
= xmlHashLookup2(style
->attributeSets
, name
, ns
);
479 style
= xsltNextImport(style
);
485 * xsltResolveSASCallback,:
486 * @style: the XSLT stylesheet
488 * resolve the references in an attribute set.
491 xsltResolveSASCallback(xsltAttrElemPtr values
, xsltStylesheetPtr style
,
492 const xmlChar
*name
, const xmlChar
*ns
,
493 ATTRIBUTE_UNUSED
const xmlChar
*ignored
) {
495 xsltAttrElemPtr refs
;
498 while (tmp
!= NULL
) {
499 if (tmp
->set
!= NULL
) {
501 * Check against cycles !
503 if ((xmlStrEqual(name
, tmp
->set
)) && (xmlStrEqual(ns
, tmp
->ns
))) {
504 xsltGenericError(xsltGenericErrorContext
,
505 "xsl:attribute-set : use-attribute-sets recursion detected on %s\n",
508 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
509 xsltGenericDebug(xsltGenericDebugContext
,
510 "Importing attribute list %s\n", tmp
->set
);
513 refs
= xsltGetSAS(style
, tmp
->set
, tmp
->ns
);
515 xsltGenericError(xsltGenericErrorContext
,
516 "xsl:attribute-set : use-attribute-sets %s reference missing %s\n",
520 * recurse first for cleanup
522 xsltResolveSASCallback(refs
, style
, name
, ns
, NULL
);
526 xsltMergeAttrElemList(style
, values
, refs
);
528 * Then suppress the reference
540 * xsltMergeSASCallback,:
541 * @style: the XSLT stylesheet
543 * Merge an attribute set from an imported stylesheet.
546 xsltMergeSASCallback(xsltAttrElemPtr values
, xsltStylesheetPtr style
,
547 const xmlChar
*name
, const xmlChar
*ns
,
548 ATTRIBUTE_UNUSED
const xmlChar
*ignored
) {
550 xsltAttrElemPtr topSet
;
552 ret
= xmlHashAddEntry2(style
->attributeSets
, name
, ns
, values
);
555 * Add failed, this attribute set can be removed.
557 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
558 xsltGenericDebug(xsltGenericDebugContext
,
559 "attribute set %s present already in top stylesheet"
560 " - merging\n", name
);
562 topSet
= xmlHashLookup2(style
->attributeSets
, name
, ns
);
564 xsltGenericError(xsltGenericErrorContext
,
565 "xsl:attribute-set : logic error merging from imports for"
566 " attribute-set %s\n", name
);
568 topSet
= xsltMergeAttrElemList(style
, topSet
, values
);
569 xmlHashUpdateEntry2(style
->attributeSets
, name
, ns
, topSet
, NULL
);
571 xsltFreeAttrElemList(values
);
572 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
574 xsltGenericDebug(xsltGenericDebugContext
,
575 "attribute set %s moved to top stylesheet\n",
582 * xsltResolveStylesheetAttributeSet:
583 * @style: the XSLT stylesheet
585 * resolve the references between attribute sets.
588 xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style
) {
589 xsltStylesheetPtr cur
;
591 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
592 xsltGenericDebug(xsltGenericDebugContext
,
593 "Resolving attribute sets references\n");
596 * First aggregate all the attribute sets definitions from the imports
598 cur
= xsltNextImport(style
);
599 while (cur
!= NULL
) {
600 if (cur
->attributeSets
!= NULL
) {
601 if (style
->attributeSets
== NULL
) {
602 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
603 xsltGenericDebug(xsltGenericDebugContext
,
604 "creating attribute set table\n");
606 style
->attributeSets
= xmlHashCreate(10);
608 xmlHashScanFull(cur
->attributeSets
,
609 (xmlHashScannerFull
) xsltMergeSASCallback
, style
);
611 * the attribute lists have either been migrated to style
612 * or freed directly in xsltMergeSASCallback()
614 xmlHashFree(cur
->attributeSets
, NULL
);
615 cur
->attributeSets
= NULL
;
617 cur
= xsltNextImport(cur
);
621 * Then resolve all the references and computes the resulting sets
623 if (style
->attributeSets
!= NULL
) {
624 xmlHashScanFull(style
->attributeSets
,
625 (xmlHashScannerFull
) xsltResolveSASCallback
, style
);
630 * xsltAttributeInternal:
631 * @ctxt: a XSLT process context
632 * @node: the current node in the source tree
633 * @inst: the xsl:attribute element
634 * @comp: precomputed information
635 * @fromAttributeSet: the attribute comes from an attribute-set
637 * Process the xslt attribute node on the source node
640 xsltAttributeInternal(xsltTransformContextPtr ctxt
,
641 xmlNodePtr contextNode
,
643 xsltStylePreCompPtr castedComp
,
644 int fromAttributeSet
)
646 #ifdef XSLT_REFACTORED
647 xsltStyleItemAttributePtr comp
=
648 (xsltStyleItemAttributePtr
) castedComp
;
650 xsltStylePreCompPtr comp
= castedComp
;
652 xmlNodePtr targetElem
;
653 xmlChar
*prop
= NULL
;
654 const xmlChar
*name
= NULL
, *prefix
= NULL
, *nsName
= NULL
;
655 xmlChar
*value
= NULL
;
659 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
))
663 * A comp->has_name == 0 indicates that we need to skip this instruction,
664 * since it was evaluated to be invalid already during compilation.
669 * BIG NOTE: This previously used xsltGetSpecialNamespace() and
670 * xsltGetNamespace(), but since both are not appropriate, we
671 * will process namespace lookup here to avoid adding yet another
672 * ns-lookup function to namespaces.c.
675 * SPEC XSLT 1.0: Error cases:
676 * - Creating nodes other than text nodes during the instantiation of
677 * the content of the xsl:attribute element; implementations may
678 * either signal the error or ignore the offending nodes."
682 xsltTransformError(ctxt
, NULL
, inst
,
683 "Internal error in xsltAttributeInternal(): "
684 "The XSLT 'attribute' instruction was not compiled.\n");
688 * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
689 * So report an internal error?
691 if (ctxt
->insert
== NULL
)
695 * "Adding an attribute to a node that is not an element;
696 * implementations may either signal the error or ignore the attribute."
698 * TODO: I think we should signal such errors in the future, and maybe
699 * provide an option to ignore such errors.
701 targetElem
= ctxt
->insert
;
702 if (targetElem
->type
!= XML_ELEMENT_NODE
)
707 * "Adding an attribute to an element after children have been added
708 * to it; implementations may either signal the error or ignore the
711 * TODO: We should decide whether not to report such errors or
712 * to ignore them; note that we *ignore* if the parent is not an
713 * element, but here we report an error.
715 if (targetElem
->children
!= NULL
) {
717 * NOTE: Ah! This seems to be intended to support streamed
718 * result generation!.
720 xsltTransformError(ctxt
, NULL
, inst
,
721 "xsl:attribute: Cannot add attributes to an "
722 "element if children have been already added "
723 "to the element.\n");
733 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
734 xslHandleDebugger(inst
, contextNode
, NULL
, ctxt
);
737 if (comp
->name
== NULL
) {
738 /* TODO: fix attr acquisition wrt to the XSLT namespace */
739 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
740 (const xmlChar
*) "name", XSLT_NAMESPACE
);
742 xsltTransformError(ctxt
, NULL
, inst
,
743 "xsl:attribute: The attribute 'name' is missing.\n");
746 if (xmlValidateQName(prop
, 0)) {
747 xsltTransformError(ctxt
, NULL
, inst
,
748 "xsl:attribute: The effective name '%s' is not a "
749 "valid QName.\n", prop
);
750 /* we fall through to catch any further errors, if possible */
752 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
756 * Reject a prefix of "xmlns".
758 if ((prefix
!= NULL
) &&
759 (!xmlStrncasecmp(prefix
, (xmlChar
*) "xmlns", 5)))
761 #ifdef WITH_XSLT_DEBUG_PARSING
762 xsltGenericDebug(xsltGenericDebugContext
,
763 "xsltAttribute: xmlns prefix forbidden\n");
767 * "It is an error if the string that results from instantiating
768 * the attribute value template is not a QName or is the string
769 * xmlns. An XSLT processor may signal the error; if it does not
770 * signal the error, it must recover by not adding the attribute
771 * to the result tree."
772 * TODO: Decide which way to go here.
779 * The "name" value was static.
781 #ifdef XSLT_REFACTORED
782 prefix
= comp
->nsPrefix
;
785 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
790 * Process namespace semantics
791 * ---------------------------
793 * Evaluate the namespace name.
797 * The "namespace" attribute was existent.
799 if (comp
->ns
!= NULL
) {
801 * No AVT; just plain text for the namespace name.
803 if (comp
->ns
[0] != 0)
810 /* TODO: check attr acquisition wrt to the XSLT namespace */
811 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
812 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
814 * This fixes bug #302020: The AVT might also evaluate to the
815 * empty string; this means that the empty string also indicates
818 * "If the string is empty, then the expanded-name of the
819 * attribute has a null namespace URI."
821 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
822 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
825 } else if (prefix
!= NULL
) {
828 * "If the namespace attribute is not present, then the QName is
829 * expanded into an expanded-name using the namespace declarations
830 * in effect for the xsl:attribute element, *not* including any
831 * default namespace declaration."
833 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
836 * Note that this is treated as an error now (checked with
837 * Saxon, Xalan-J and MSXML).
839 xsltTransformError(ctxt
, NULL
, inst
,
840 "xsl:attribute: The QName '%s:%s' has no "
841 "namespace binding in scope in the stylesheet; "
842 "this is an error, since the namespace was not "
843 "specified by the instruction itself.\n", prefix
, name
);
848 if (fromAttributeSet
) {
850 * This tries to ensure that xsl:attribute(s) coming
851 * from an xsl:attribute-set won't override attribute of
852 * literal result elements or of explicit xsl:attribute(s).
853 * URGENT TODO: This might be buggy, since it will miss to
854 * overwrite two equal attributes both from attribute sets.
856 attr
= xmlHasNsProp(targetElem
, name
, nsName
);
862 * Find/create a matching ns-decl in the result tree.
869 * OPTIMIZE TODO: How do we know if we are adding to a
870 * fragment or to the result tree?
872 * If we are adding to a result tree fragment (i.e., not to the
873 * actual result tree), we'll don't bother searching for the
874 * ns-decl, but just store it in the dummy-doc of the result
877 if (nsName
!= NULL
) {
879 * TODO: Get the doc of @targetElem.
881 ns
= xsltTreeAcquireStoredNs(some doc
, nsName
, prefix
);
886 if (nsName
!= NULL
) {
888 * Something about ns-prefixes:
890 * "XSLT processors may make use of the prefix of the QName specified
891 * in the name attribute when selecting the prefix used for outputting
892 * the created attribute as XML; however, they are not required to do
893 * so and, if the prefix is xmlns, they must not do so"
896 * xsl:attribute can produce a scenario where the prefix is NULL,
897 * so generate a prefix.
899 if (prefix
== NULL
) {
900 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
902 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, BAD_CAST pref
,
907 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
911 xsltTransformError(ctxt
, NULL
, inst
,
912 "Namespace fixup error: Failed to acquire an in-scope "
913 "namespace binding for the generated attribute '{%s}%s'.\n",
919 * Construction of the value
920 * -------------------------
922 if (inst
->children
== NULL
) {
925 * TODO: Do we need to put the empty string in ?
927 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, (const xmlChar
*) "");
928 } else if ((inst
->children
->next
== NULL
) &&
929 ((inst
->children
->type
== XML_TEXT_NODE
) ||
930 (inst
->children
->type
== XML_CDATA_SECTION_NODE
)))
935 * xmlSetNsProp() will take care of duplicates.
937 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, NULL
);
938 if (attr
== NULL
) /* TODO: report error ? */
941 * This was taken over from xsltCopyText() (transform.c).
943 if (ctxt
->internalized
&&
944 (ctxt
->insert
->doc
!= NULL
) &&
945 (ctxt
->insert
->doc
->dict
== ctxt
->dict
))
947 copyTxt
= xmlNewText(NULL
);
948 if (copyTxt
== NULL
) /* TODO: report error */
951 * This is a safe scenario where we don't need to lookup
954 copyTxt
->content
= inst
->children
->content
;
956 * Copy "disable-output-escaping" information.
957 * TODO: Does this have any effect for attribute values
960 if (inst
->children
->name
== xmlStringTextNoenc
)
961 copyTxt
->name
= xmlStringTextNoenc
;
966 copyTxt
= xmlNewText(inst
->children
->content
);
967 if (copyTxt
== NULL
) /* TODO: report error */
970 attr
->children
= attr
->last
= copyTxt
;
971 copyTxt
->parent
= (xmlNodePtr
) attr
;
972 copyTxt
->doc
= attr
->doc
;
974 * Copy "disable-output-escaping" information.
975 * TODO: Does this have any effect for attribute values
978 if (inst
->children
->name
== xmlStringTextNoenc
)
979 copyTxt
->name
= xmlStringTextNoenc
;
982 * since we create the attribute without content IDness must be
983 * asserted as a second step
985 if ((copyTxt
->content
!= NULL
) &&
986 (xmlIsID(attr
->doc
, attr
->parent
, attr
)))
987 xmlAddID(NULL
, attr
->doc
, copyTxt
->content
, attr
);
990 * The sequence constructor might be complex, so instantiate it.
992 value
= xsltEvalTemplateString(ctxt
, contextNode
, inst
);
994 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, value
);
998 * TODO: Do we have to add the empty string to the attr?
999 * TODO: Does a value of NULL indicate an
1000 * error in xsltEvalTemplateString() ?
1002 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
,
1003 (const xmlChar
*) "");
1013 * @ctxt: a XSLT process context
1014 * @node: the node in the source tree.
1015 * @inst: the xslt attribute node
1016 * @comp: precomputed information
1018 * Process the xslt attribute node on the source node
1021 xsltAttribute(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1022 xmlNodePtr inst
, xsltStylePreCompPtr comp
) {
1023 xsltAttributeInternal(ctxt
, node
, inst
, comp
, 0);
1027 * xsltApplyAttributeSet:
1028 * @ctxt: the XSLT stylesheet
1029 * @node: the node in the source tree.
1030 * @inst: the attribute node "xsl:use-attribute-sets"
1031 * @attrSets: the list of QNames of the attribute-sets to be applied
1033 * Apply the xsl:use-attribute-sets.
1034 * If @attrSets is NULL, then @inst will be used to exctract this
1036 * If both, @attrSets and @inst, are NULL, then this will do nothing.
1039 xsltApplyAttributeSet(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1041 const xmlChar
*attrSets
)
1043 const xmlChar
*ncname
= NULL
;
1044 const xmlChar
*prefix
= NULL
;
1045 const xmlChar
*curstr
, *endstr
;
1046 xsltAttrElemPtr attrs
;
1047 xsltStylesheetPtr style
;
1049 if (attrSets
== NULL
) {
1054 * Extract the value from @inst.
1056 if (inst
->type
== XML_ATTRIBUTE_NODE
) {
1057 if ( ((xmlAttrPtr
) inst
)->children
!= NULL
)
1058 attrSets
= ((xmlAttrPtr
) inst
)->children
->content
;
1061 if (attrSets
== NULL
) {
1063 * TODO: Return an error?
1070 * Parse/apply the list of QNames.
1073 while (*curstr
!= 0) {
1074 while (IS_BLANK(*curstr
))
1079 while ((*endstr
!= 0) && (!IS_BLANK(*endstr
)))
1081 curstr
= xmlDictLookup(ctxt
->dict
, curstr
, endstr
- curstr
);
1084 * TODO: Validate the QName.
1087 #ifdef WITH_XSLT_DEBUG_curstrUTES
1088 xsltGenericDebug(xsltGenericDebugContext
,
1089 "apply curstrute set %s\n", curstr
);
1091 ncname
= xsltSplitQName(ctxt
->dict
, curstr
, &prefix
);
1093 style
= ctxt
->style
;
1095 #ifdef WITH_DEBUGGER
1096 if ((style
!= NULL
) &&
1097 (style
->attributeSets
!= NULL
) &&
1098 (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
))
1101 xmlHashLookup2(style
->attributeSets
, ncname
, prefix
);
1102 if ((attrs
!= NULL
) && (attrs
->attr
!= NULL
))
1103 xslHandleDebugger(attrs
->attr
->parent
, node
, NULL
,
1108 * Lookup the referenced curstrute-set.
1110 while (style
!= NULL
) {
1112 xmlHashLookup2(style
->attributeSets
, ncname
, prefix
);
1113 while (attrs
!= NULL
) {
1114 if (attrs
->attr
!= NULL
) {
1115 xsltAttributeInternal(ctxt
, node
, attrs
->attr
,
1116 attrs
->attr
->psvi
, 1);
1118 attrs
= attrs
->next
;
1120 style
= xsltNextImport(style
);
1128 * xsltFreeAttributeSetsHashes:
1129 * @style: an XSLT stylesheet
1131 * Free up the memory used by attribute sets
1134 xsltFreeAttributeSetsHashes(xsltStylesheetPtr style
) {
1135 if (style
->attributeSets
!= NULL
)
1136 xmlHashFree((xmlHashTablePtr
) style
->attributeSets
,
1137 (xmlHashDeallocator
) xsltFreeAttrElemList
);
1138 style
->attributeSets
= NULL
;