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
20 * TODO: merge attribute sets from different import precedence.
21 * all this should be precomputed just before the transformation
22 * starts or at first hit with a cache in the context.
23 * The simple way for now would be to not allow redefinition of
24 * attributes once generated in the output tree, possibly costlier.
34 #define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \
37 #define IS_BLANK_NODE(n) \
38 (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content)))
42 * The in-memory structure corresponding to an XSLT Attribute in
47 typedef struct _xsltAttrElem xsltAttrElem
;
48 typedef xsltAttrElem
*xsltAttrElemPtr
;
49 struct _xsltAttrElem
{
50 struct _xsltAttrElem
*next
;/* chained list */
51 xmlNodePtr attr
; /* the xsl:attribute definition */
52 const xmlChar
*set
; /* or the attribute set */
53 const xmlChar
*ns
; /* and its namespace */
56 /************************************************************************
58 * XSLT Attribute handling *
60 ************************************************************************/
64 * @attr: the new xsl:attribute node
66 * Create a new XSLT AttrElem
68 * Returns the newly allocated xsltAttrElemPtr or NULL in case of error
70 static xsltAttrElemPtr
71 xsltNewAttrElem(xmlNodePtr attr
) {
74 cur
= (xsltAttrElemPtr
) xmlMalloc(sizeof(xsltAttrElem
));
76 xsltGenericError(xsltGenericErrorContext
,
77 "xsltNewAttrElem : malloc failed\n");
80 memset(cur
, 0, sizeof(xsltAttrElem
));
87 * @attr: an XSLT AttrElem
89 * Free up the memory allocated by @attr
92 xsltFreeAttrElem(xsltAttrElemPtr attr
) {
97 * xsltFreeAttrElemList:
98 * @list: an XSLT AttrElem list
100 * Free up the memory allocated by @list
103 xsltFreeAttrElemList(xsltAttrElemPtr list
) {
104 xsltAttrElemPtr next
;
106 while (list
!= NULL
) {
108 xsltFreeAttrElem(list
);
113 #ifdef XSLT_REFACTORED
115 * This was moved to xsltParseStylesheetAttributeSet().
119 * xsltAddAttrElemList:
120 * @list: an XSLT AttrElem list
121 * @attr: the new xsl:attribute node
123 * Add the new attribute to the list.
125 * Returns the new list pointer
127 static xsltAttrElemPtr
128 xsltAddAttrElemList(xsltAttrElemPtr list
, xmlNodePtr attr
) {
129 xsltAttrElemPtr next
, cur
;
134 return(xsltNewAttrElem(attr
));
136 while (cur
!= NULL
) {
138 if (cur
->attr
== attr
)
140 if (cur
->next
== NULL
) {
141 cur
->next
= xsltNewAttrElem(attr
);
148 #endif /* XSLT_REFACTORED */
151 * xsltMergeAttrElemList:
152 * @list: an XSLT AttrElem list
153 * @old: another XSLT AttrElem list
155 * Add all the attributes from list @old to list @list,
156 * but drop redefinition of existing values.
158 * Returns the new list pointer
160 static xsltAttrElemPtr
161 xsltMergeAttrElemList(xsltStylesheetPtr style
,
162 xsltAttrElemPtr list
, xsltAttrElemPtr old
) {
166 while (old
!= NULL
) {
167 if ((old
->attr
== NULL
) && (old
->set
== NULL
)) {
172 * Check that the attribute is not yet in the list
176 while (cur
!= NULL
) {
177 if ((cur
->attr
== NULL
) && (cur
->set
== NULL
)) {
178 if (cur
->next
== NULL
)
183 if ((cur
->set
!= NULL
) && (cur
->set
== old
->set
)) {
187 if (cur
->set
!= NULL
) {
188 if (cur
->next
== NULL
)
193 if (old
->set
!= NULL
) {
194 if (cur
->next
== NULL
)
199 if (cur
->attr
== old
->attr
) {
200 xsltGenericError(xsltGenericErrorContext
,
201 "xsl:attribute-set : use-attribute-sets recursion detected\n");
204 if (cur
->next
== NULL
)
211 * Changed to use the string-dict, rather than duplicating
212 * @set and @ns; this fixes bug #340400.
215 list
= xsltNewAttrElem(old
->attr
);
216 if (old
->set
!= NULL
) {
217 list
->set
= xmlDictLookup(style
->dict
, old
->set
, -1);
219 list
->ns
= xmlDictLookup(style
->dict
, old
->ns
, -1);
222 cur
->next
= xsltNewAttrElem(old
->attr
);
223 if (old
->set
!= NULL
) {
224 cur
->next
->set
= xmlDictLookup(style
->dict
, old
->set
, -1);
226 cur
->next
->ns
= xmlDictLookup(style
->dict
, old
->ns
, -1);
236 /************************************************************************
238 * Module interfaces *
240 ************************************************************************/
243 * xsltParseStylesheetAttributeSet:
244 * @style: the XSLT stylesheet
245 * @cur: the "attribute-set" element
247 * parse an XSLT stylesheet attribute-set element
251 xsltParseStylesheetAttributeSet(xsltStylesheetPtr style
, xmlNodePtr cur
) {
252 const xmlChar
*ncname
;
253 const xmlChar
*prefix
;
256 xsltAttrElemPtr attrItems
;
258 if ((cur
== NULL
) || (style
== NULL
) || (cur
->type
!= XML_ELEMENT_NODE
))
261 value
= xmlGetNsProp(cur
, (const xmlChar
*)"name", NULL
);
263 xsltGenericError(xsltGenericErrorContext
,
264 "xsl:attribute-set : name is missing\n");
268 ncname
= xsltSplitQName(style
->dict
, value
, &prefix
);
272 if (style
->attributeSets
== NULL
) {
273 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
274 xsltGenericDebug(xsltGenericDebugContext
,
275 "creating attribute set table\n");
277 style
->attributeSets
= xmlHashCreate(10);
279 if (style
->attributeSets
== NULL
)
282 attrItems
= xmlHashLookup2(style
->attributeSets
, ncname
, prefix
);
285 * Parse the content. Only xsl:attribute elements are allowed.
287 child
= cur
->children
;
288 while (child
!= NULL
) {
290 * Report invalid nodes.
292 if ((child
->type
!= XML_ELEMENT_NODE
) ||
293 (child
->ns
== NULL
) ||
294 (! IS_XSLT_ELEM(child
)))
296 if (child
->type
== XML_ELEMENT_NODE
)
297 xsltTransformError(NULL
, style
, child
,
298 "xsl:attribute-set : unexpected child %s\n",
301 xsltTransformError(NULL
, style
, child
,
302 "xsl:attribute-set : child of unexpected type\n");
303 } else if (!IS_XSLT_NAME(child
, "attribute")) {
304 xsltTransformError(NULL
, style
, child
,
305 "xsl:attribute-set : unexpected child xsl:%s\n",
308 #ifdef XSLT_REFACTORED
309 xsltAttrElemPtr nextAttr
, curAttr
;
312 * Process xsl:attribute
313 * ---------------------
316 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
317 xsltGenericDebug(xsltGenericDebugContext
,
318 "add attribute to list %s\n", ncname
);
321 * The following was taken over from
322 * xsltAddAttrElemList().
324 if (attrItems
== NULL
) {
325 attrItems
= xsltNewAttrElem(child
);
328 while (curAttr
!= NULL
) {
329 nextAttr
= curAttr
->next
;
330 if (curAttr
->attr
== child
) {
332 * URGENT TODO: Can somebody explain
333 * why attrItems is set to curAttr
334 * here? Is this somehow related to
335 * avoidance of recursions?
340 if (curAttr
->next
== NULL
)
341 curAttr
->next
= xsltNewAttrElem(child
);
346 * Parse the xsl:attribute and its content.
348 xsltParseAnyXSLTElem(XSLT_CCTXT(style
), child
);
350 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
351 xsltGenericDebug(xsltGenericDebugContext
,
352 "add attribute to list %s\n", ncname
);
357 attrItems
= xsltAddAttrElemList(attrItems
, child
);
361 #ifdef XSLT_REFACTORED
368 * Process attribue "use-attribute-sets".
370 /* TODO check recursion */
371 value
= xmlGetNsProp(cur
, (const xmlChar
*)"use-attribute-sets",
374 const xmlChar
*curval
, *endval
;
376 while (*curval
!= 0) {
377 while (IS_BLANK(*curval
)) curval
++;
381 while ((*endval
!= 0) && (!IS_BLANK(*endval
))) endval
++;
382 curval
= xmlDictLookup(style
->dict
, curval
, endval
- curval
);
384 const xmlChar
*ncname2
= NULL
;
385 const xmlChar
*prefix2
= NULL
;
386 xsltAttrElemPtr refAttrItems
;
388 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
389 xsltGenericDebug(xsltGenericDebugContext
,
390 "xsl:attribute-set : %s adds use %s\n", ncname
, curval
);
392 ncname2
= xsltSplitQName(style
->dict
, curval
, &prefix2
);
393 refAttrItems
= xsltNewAttrElem(NULL
);
394 if (refAttrItems
!= NULL
) {
395 refAttrItems
->set
= ncname2
;
396 refAttrItems
->ns
= prefix2
;
397 attrItems
= xsltMergeAttrElemList(style
,
398 attrItems
, refAttrItems
);
399 xsltFreeAttrElem(refAttrItems
);
412 * TODO: Why is this dummy entry needed.?
414 if (attrItems
== NULL
)
415 attrItems
= xsltNewAttrElem(NULL
);
416 xmlHashUpdateEntry2(style
->attributeSets
, ncname
, prefix
, attrItems
, NULL
);
417 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
418 xsltGenericDebug(xsltGenericDebugContext
,
419 "updated attribute list %s\n", ncname
);
425 * @style: the XSLT stylesheet
426 * @name: the attribute list name
427 * @ns: the attribute list namespace
429 * lookup an attribute set based on the style cascade
431 * Returns the attribute set or NULL
433 static xsltAttrElemPtr
434 xsltGetSAS(xsltStylesheetPtr style
, const xmlChar
*name
, const xmlChar
*ns
) {
435 xsltAttrElemPtr values
;
437 while (style
!= NULL
) {
438 values
= xmlHashLookup2(style
->attributeSets
, name
, ns
);
441 style
= xsltNextImport(style
);
447 * xsltResolveSASCallback,:
448 * @style: the XSLT stylesheet
450 * resolve the references in an attribute set.
453 xsltResolveSASCallback(xsltAttrElemPtr values
, xsltStylesheetPtr style
,
454 const xmlChar
*name
, const xmlChar
*ns
,
455 ATTRIBUTE_UNUSED
const xmlChar
*ignored
) {
457 xsltAttrElemPtr refs
;
460 while (tmp
!= NULL
) {
461 if (tmp
->set
!= NULL
) {
463 * Check against cycles !
465 if ((xmlStrEqual(name
, tmp
->set
)) && (xmlStrEqual(ns
, tmp
->ns
))) {
466 xsltGenericError(xsltGenericErrorContext
,
467 "xsl:attribute-set : use-attribute-sets recursion detected on %s\n",
470 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
471 xsltGenericDebug(xsltGenericDebugContext
,
472 "Importing attribute list %s\n", tmp
->set
);
475 refs
= xsltGetSAS(style
, tmp
->set
, tmp
->ns
);
477 xsltGenericError(xsltGenericErrorContext
,
478 "xsl:attribute-set : use-attribute-sets %s reference missing %s\n",
482 * recurse first for cleanup
484 xsltResolveSASCallback(refs
, style
, name
, ns
, NULL
);
488 xsltMergeAttrElemList(style
, values
, refs
);
490 * Then suppress the reference
502 * xsltMergeSASCallback,:
503 * @style: the XSLT stylesheet
505 * Merge an attribute set from an imported stylesheet.
508 xsltMergeSASCallback(xsltAttrElemPtr values
, xsltStylesheetPtr style
,
509 const xmlChar
*name
, const xmlChar
*ns
,
510 ATTRIBUTE_UNUSED
const xmlChar
*ignored
) {
512 xsltAttrElemPtr topSet
;
514 ret
= xmlHashAddEntry2(style
->attributeSets
, name
, ns
, values
);
517 * Add failed, this attribute set can be removed.
519 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
520 xsltGenericDebug(xsltGenericDebugContext
,
521 "attribute set %s present already in top stylesheet"
522 " - merging\n", name
);
524 topSet
= xmlHashLookup2(style
->attributeSets
, name
, ns
);
526 xsltGenericError(xsltGenericErrorContext
,
527 "xsl:attribute-set : logic error merging from imports for"
528 " attribute-set %s\n", name
);
530 topSet
= xsltMergeAttrElemList(style
, topSet
, values
);
531 xmlHashUpdateEntry2(style
->attributeSets
, name
, ns
, topSet
, NULL
);
533 xsltFreeAttrElemList(values
);
534 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
536 xsltGenericDebug(xsltGenericDebugContext
,
537 "attribute set %s moved to top stylesheet\n",
544 * xsltResolveStylesheetAttributeSet:
545 * @style: the XSLT stylesheet
547 * resolve the references between attribute sets.
550 xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style
) {
551 xsltStylesheetPtr cur
;
553 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
554 xsltGenericDebug(xsltGenericDebugContext
,
555 "Resolving attribute sets references\n");
558 * First aggregate all the attribute sets definitions from the imports
560 cur
= xsltNextImport(style
);
561 while (cur
!= NULL
) {
562 if (cur
->attributeSets
!= NULL
) {
563 if (style
->attributeSets
== NULL
) {
564 #ifdef WITH_XSLT_DEBUG_ATTRIBUTES
565 xsltGenericDebug(xsltGenericDebugContext
,
566 "creating attribute set table\n");
568 style
->attributeSets
= xmlHashCreate(10);
570 xmlHashScanFull(cur
->attributeSets
,
571 (xmlHashScannerFull
) xsltMergeSASCallback
, style
);
573 * the attribute lists have either been migrated to style
574 * or freed directly in xsltMergeSASCallback()
576 xmlHashFree(cur
->attributeSets
, NULL
);
577 cur
->attributeSets
= NULL
;
579 cur
= xsltNextImport(cur
);
583 * Then resolve all the references and computes the resulting sets
585 if (style
->attributeSets
!= NULL
) {
586 xmlHashScanFull(style
->attributeSets
,
587 (xmlHashScannerFull
) xsltResolveSASCallback
, style
);
592 * xsltAttributeInternal:
593 * @ctxt: a XSLT process context
594 * @node: the current node in the source tree
595 * @inst: the xsl:attribute element
596 * @comp: precomputed information
597 * @fromAttributeSet: the attribute comes from an attribute-set
599 * Process the xslt attribute node on the source node
602 xsltAttributeInternal(xsltTransformContextPtr ctxt
,
603 xmlNodePtr contextNode
,
605 xsltStylePreCompPtr castedComp
,
606 int fromAttributeSet
)
608 #ifdef XSLT_REFACTORED
609 xsltStyleItemAttributePtr comp
=
610 (xsltStyleItemAttributePtr
) castedComp
;
612 xsltStylePreCompPtr comp
= castedComp
;
614 xmlNodePtr targetElem
;
615 xmlChar
*prop
= NULL
;
616 const xmlChar
*name
= NULL
, *prefix
= NULL
, *nsName
= NULL
;
617 xmlChar
*value
= NULL
;
621 if ((ctxt
== NULL
) || (contextNode
== NULL
) || (inst
== NULL
) ||
622 (inst
->type
!= XML_ELEMENT_NODE
) )
626 * A comp->has_name == 0 indicates that we need to skip this instruction,
627 * since it was evaluated to be invalid already during compilation.
632 * BIG NOTE: This previously used xsltGetSpecialNamespace() and
633 * xsltGetNamespace(), but since both are not appropriate, we
634 * will process namespace lookup here to avoid adding yet another
635 * ns-lookup function to namespaces.c.
638 * SPEC XSLT 1.0: Error cases:
639 * - Creating nodes other than text nodes during the instantiation of
640 * the content of the xsl:attribute element; implementations may
641 * either signal the error or ignore the offending nodes."
645 xsltTransformError(ctxt
, NULL
, inst
,
646 "Internal error in xsltAttributeInternal(): "
647 "The XSLT 'attribute' instruction was not compiled.\n");
651 * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error?
652 * So report an internal error?
654 if (ctxt
->insert
== NULL
)
658 * "Adding an attribute to a node that is not an element;
659 * implementations may either signal the error or ignore the attribute."
661 * TODO: I think we should signal such errors in the future, and maybe
662 * provide an option to ignore such errors.
664 targetElem
= ctxt
->insert
;
665 if (targetElem
->type
!= XML_ELEMENT_NODE
)
670 * "Adding an attribute to an element after children have been added
671 * to it; implementations may either signal the error or ignore the
674 * TODO: We should decide whether not to report such errors or
675 * to ignore them; note that we *ignore* if the parent is not an
676 * element, but here we report an error.
678 if (targetElem
->children
!= NULL
) {
680 * NOTE: Ah! This seems to be intended to support streamed
681 * result generation!.
683 xsltTransformError(ctxt
, NULL
, inst
,
684 "xsl:attribute: Cannot add attributes to an "
685 "element if children have been already added "
686 "to the element.\n");
696 if (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
)
697 xslHandleDebugger(inst
, contextNode
, NULL
, ctxt
);
700 if (comp
->name
== NULL
) {
701 /* TODO: fix attr acquisition wrt to the XSLT namespace */
702 prop
= xsltEvalAttrValueTemplate(ctxt
, inst
,
703 (const xmlChar
*) "name", XSLT_NAMESPACE
);
705 xsltTransformError(ctxt
, NULL
, inst
,
706 "xsl:attribute: The attribute 'name' is missing.\n");
709 if (xmlValidateQName(prop
, 0)) {
710 xsltTransformError(ctxt
, NULL
, inst
,
711 "xsl:attribute: The effective name '%s' is not a "
712 "valid QName.\n", prop
);
713 /* we fall through to catch any further errors, if possible */
717 * Reject a name of "xmlns".
719 if (xmlStrEqual(prop
, BAD_CAST
"xmlns")) {
720 xsltTransformError(ctxt
, NULL
, inst
,
721 "xsl:attribute: The effective name 'xmlns' is not allowed.\n");
726 name
= xsltSplitQName(ctxt
->dict
, prop
, &prefix
);
730 * The "name" value was static.
732 #ifdef XSLT_REFACTORED
733 prefix
= comp
->nsPrefix
;
736 name
= xsltSplitQName(ctxt
->dict
, comp
->name
, &prefix
);
741 * Process namespace semantics
742 * ---------------------------
744 * Evaluate the namespace name.
748 * The "namespace" attribute was existent.
750 if (comp
->ns
!= NULL
) {
752 * No AVT; just plain text for the namespace name.
754 if (comp
->ns
[0] != 0)
761 /* TODO: check attr acquisition wrt to the XSLT namespace */
762 tmpNsName
= xsltEvalAttrValueTemplate(ctxt
, inst
,
763 (const xmlChar
*) "namespace", XSLT_NAMESPACE
);
765 * This fixes bug #302020: The AVT might also evaluate to the
766 * empty string; this means that the empty string also indicates
769 * "If the string is empty, then the expanded-name of the
770 * attribute has a null namespace URI."
772 if ((tmpNsName
!= NULL
) && (tmpNsName
[0] != 0))
773 nsName
= xmlDictLookup(ctxt
->dict
, BAD_CAST tmpNsName
, -1);
777 if (xmlStrEqual(nsName
, BAD_CAST
"http://www.w3.org/2000/xmlns/")) {
778 xsltTransformError(ctxt
, NULL
, inst
,
779 "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ "
783 if (xmlStrEqual(nsName
, XML_XML_NAMESPACE
)) {
784 prefix
= BAD_CAST
"xml";
785 } else if (xmlStrEqual(prefix
, BAD_CAST
"xml")) {
788 } else if (prefix
!= NULL
) {
791 * "If the namespace attribute is not present, then the QName is
792 * expanded into an expanded-name using the namespace declarations
793 * in effect for the xsl:attribute element, *not* including any
794 * default namespace declaration."
796 ns
= xmlSearchNs(inst
->doc
, inst
, prefix
);
799 * Note that this is treated as an error now (checked with
800 * Saxon, Xalan-J and MSXML).
802 xsltTransformError(ctxt
, NULL
, inst
,
803 "xsl:attribute: The QName '%s:%s' has no "
804 "namespace binding in scope in the stylesheet; "
805 "this is an error, since the namespace was not "
806 "specified by the instruction itself.\n", prefix
, name
);
811 if (fromAttributeSet
) {
813 * This tries to ensure that xsl:attribute(s) coming
814 * from an xsl:attribute-set won't override attribute of
815 * literal result elements or of explicit xsl:attribute(s).
816 * URGENT TODO: This might be buggy, since it will miss to
817 * overwrite two equal attributes both from attribute sets.
819 attr
= xmlHasNsProp(targetElem
, name
, nsName
);
825 * Find/create a matching ns-decl in the result tree.
832 * OPTIMIZE TODO: How do we know if we are adding to a
833 * fragment or to the result tree?
835 * If we are adding to a result tree fragment (i.e., not to the
836 * actual result tree), we'll don't bother searching for the
837 * ns-decl, but just store it in the dummy-doc of the result
840 if (nsName
!= NULL
) {
842 * TODO: Get the doc of @targetElem.
844 ns
= xsltTreeAcquireStoredNs(some doc
, nsName
, prefix
);
849 if (nsName
!= NULL
) {
851 * Something about ns-prefixes:
853 * "XSLT processors may make use of the prefix of the QName specified
854 * in the name attribute when selecting the prefix used for outputting
855 * the created attribute as XML; however, they are not required to do
856 * so and, if the prefix is xmlns, they must not do so"
859 * xsl:attribute can produce a scenario where the prefix is NULL,
860 * so generate a prefix.
862 if ((prefix
== NULL
) || xmlStrEqual(prefix
, BAD_CAST
"xmlns")) {
863 xmlChar
*pref
= xmlStrdup(BAD_CAST
"ns_1");
865 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, pref
, targetElem
);
869 ns
= xsltGetSpecialNamespace(ctxt
, inst
, nsName
, prefix
,
873 xsltTransformError(ctxt
, NULL
, inst
,
874 "Namespace fixup error: Failed to acquire an in-scope "
875 "namespace binding for the generated attribute '{%s}%s'.\n",
881 * Construction of the value
882 * -------------------------
884 if (inst
->children
== NULL
) {
887 * TODO: Do we need to put the empty string in ?
889 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, (const xmlChar
*) "");
890 } else if ((inst
->children
->next
== NULL
) &&
891 ((inst
->children
->type
== XML_TEXT_NODE
) ||
892 (inst
->children
->type
== XML_CDATA_SECTION_NODE
)))
897 * xmlSetNsProp() will take care of duplicates.
899 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, NULL
);
900 if (attr
== NULL
) /* TODO: report error ? */
903 * This was taken over from xsltCopyText() (transform.c).
905 if (ctxt
->internalized
&&
906 (ctxt
->insert
->doc
!= NULL
) &&
907 (ctxt
->insert
->doc
->dict
== ctxt
->dict
))
909 copyTxt
= xmlNewText(NULL
);
910 if (copyTxt
== NULL
) /* TODO: report error */
913 * This is a safe scenario where we don't need to lookup
916 copyTxt
->content
= inst
->children
->content
;
918 * Copy "disable-output-escaping" information.
919 * TODO: Does this have any effect for attribute values
922 if (inst
->children
->name
== xmlStringTextNoenc
)
923 copyTxt
->name
= xmlStringTextNoenc
;
928 copyTxt
= xmlNewText(inst
->children
->content
);
929 if (copyTxt
== NULL
) /* TODO: report error */
932 attr
->children
= attr
->last
= copyTxt
;
933 copyTxt
->parent
= (xmlNodePtr
) attr
;
934 copyTxt
->doc
= attr
->doc
;
936 * Copy "disable-output-escaping" information.
937 * TODO: Does this have any effect for attribute values
940 if (inst
->children
->name
== xmlStringTextNoenc
)
941 copyTxt
->name
= xmlStringTextNoenc
;
944 * since we create the attribute without content IDness must be
945 * asserted as a second step
947 if ((copyTxt
->content
!= NULL
) &&
948 (xmlIsID(attr
->doc
, attr
->parent
, attr
)))
949 xmlAddID(NULL
, attr
->doc
, copyTxt
->content
, attr
);
952 * The sequence constructor might be complex, so instantiate it.
954 value
= xsltEvalTemplateString(ctxt
, contextNode
, inst
);
956 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
, value
);
960 * TODO: Do we have to add the empty string to the attr?
961 * TODO: Does a value of NULL indicate an
962 * error in xsltEvalTemplateString() ?
964 attr
= xmlSetNsProp(ctxt
->insert
, ns
, name
,
965 (const xmlChar
*) "");
975 * @ctxt: a XSLT process context
976 * @node: the node in the source tree.
977 * @inst: the xslt attribute node
978 * @comp: precomputed information
980 * Process the xslt attribute node on the source node
983 xsltAttribute(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
984 xmlNodePtr inst
, xsltStylePreCompPtr comp
) {
985 xsltAttributeInternal(ctxt
, node
, inst
, comp
, 0);
989 * xsltApplyAttributeSet:
990 * @ctxt: the XSLT stylesheet
991 * @node: the node in the source tree.
992 * @inst: the attribute node "xsl:use-attribute-sets"
993 * @attrSets: the list of QNames of the attribute-sets to be applied
995 * Apply the xsl:use-attribute-sets.
996 * If @attrSets is NULL, then @inst will be used to exctract this
998 * If both, @attrSets and @inst, are NULL, then this will do nothing.
1001 xsltApplyAttributeSet(xsltTransformContextPtr ctxt
, xmlNodePtr node
,
1003 const xmlChar
*attrSets
)
1005 const xmlChar
*ncname
= NULL
;
1006 const xmlChar
*prefix
= NULL
;
1007 const xmlChar
*curstr
, *endstr
;
1008 xsltAttrElemPtr attrs
;
1009 xsltStylesheetPtr style
;
1011 if (attrSets
== NULL
) {
1016 * Extract the value from @inst.
1018 if (inst
->type
== XML_ATTRIBUTE_NODE
) {
1019 if ( ((xmlAttrPtr
) inst
)->children
!= NULL
)
1020 attrSets
= ((xmlAttrPtr
) inst
)->children
->content
;
1023 if (attrSets
== NULL
) {
1025 * TODO: Return an error?
1032 * Parse/apply the list of QNames.
1035 while (*curstr
!= 0) {
1036 while (IS_BLANK(*curstr
))
1041 while ((*endstr
!= 0) && (!IS_BLANK(*endstr
)))
1043 curstr
= xmlDictLookup(ctxt
->dict
, curstr
, endstr
- curstr
);
1046 * TODO: Validate the QName.
1049 #ifdef WITH_XSLT_DEBUG_curstrUTES
1050 xsltGenericDebug(xsltGenericDebugContext
,
1051 "apply curstrute set %s\n", curstr
);
1053 ncname
= xsltSplitQName(ctxt
->dict
, curstr
, &prefix
);
1055 style
= ctxt
->style
;
1057 #ifdef WITH_DEBUGGER
1058 if ((style
!= NULL
) &&
1059 (style
->attributeSets
!= NULL
) &&
1060 (ctxt
->debugStatus
!= XSLT_DEBUG_NONE
))
1063 xmlHashLookup2(style
->attributeSets
, ncname
, prefix
);
1064 if ((attrs
!= NULL
) && (attrs
->attr
!= NULL
))
1065 xslHandleDebugger(attrs
->attr
->parent
, node
, NULL
,
1070 * Lookup the referenced curstrute-set.
1072 while (style
!= NULL
) {
1074 xmlHashLookup2(style
->attributeSets
, ncname
, prefix
);
1075 while (attrs
!= NULL
) {
1076 if (attrs
->attr
!= NULL
) {
1077 xsltAttributeInternal(ctxt
, node
, attrs
->attr
,
1078 attrs
->attr
->psvi
, 1);
1080 attrs
= attrs
->next
;
1082 style
= xsltNextImport(style
);
1090 * xsltFreeAttributeSetsHashes:
1091 * @style: an XSLT stylesheet
1093 * Free up the memory used by attribute sets
1096 xsltFreeAttributeSetsHashes(xsltStylesheetPtr style
) {
1097 if (style
->attributeSets
!= NULL
)
1098 xmlHashFree((xmlHashTablePtr
) style
->attributeSets
,
1099 (xmlHashDeallocator
) xsltFreeAttrElemList
);
1100 style
->attributeSets
= NULL
;