KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > style > StyleElement


1 package com.icl.saxon.style;
2 import com.icl.saxon.tree.AttributeCollection;
3 import com.icl.saxon.*;
4 import com.icl.saxon.om.*;
5 import com.icl.saxon.tree.ElementWithAttributes;
6 import com.icl.saxon.tree.DocumentImpl;
7 import com.icl.saxon.tree.NodeImpl;
8 import com.icl.saxon.expr.*;
9 import com.icl.saxon.pattern.Pattern;
10 import com.icl.saxon.pattern.NoNodeTest;
11 import com.icl.saxon.output.*;
12 import com.icl.saxon.trace.*; // e.g.
13

14 import org.xml.sax.*;
15 import org.w3c.dom.Node JavaDoc;
16
17 import java.util.*;
18 import java.io.*;
19 import java.text.*;
20
21 import javax.xml.transform.stream.StreamResult JavaDoc;
22 import javax.xml.transform.TransformerException JavaDoc;
23 import javax.xml.transform.TransformerConfigurationException JavaDoc;
24
25 /**
26 * Abstract superclass for all element nodes in the stylesheet. <BR>
27 * Note: this class implements Locator. The element
28 * retains information about its own location in the stylesheet, which is useful when
29 * an XSL error is found.
30 */

31
32 public abstract class StyleElement extends ElementWithAttributes
33         implements Locator {
34
35     protected Vector attributeSets = null;
36     protected short[] extensionNamespaces = null; // a list of URI codes
37
private short[] excludedNamespaces = null; // a list of URI codes
38
protected String JavaDoc version = null;
39     protected StaticContext staticContext = null;
40     protected TransformerConfigurationException JavaDoc validationError = null;
41     protected int reportingCircumstances = REPORT_ALWAYS;
42
43     // Conditions under which an error is to be reported
44

45     public final static int REPORT_ALWAYS = 1;
46     public final static int REPORT_UNLESS_FORWARDS_COMPATIBLE = 2;
47     public final static int REPORT_IF_INSTANTIATED = 3;
48     
49     /**
50     * Constructor
51     */

52
53     public StyleElement() {}
54
55     /**
56     * Make this node a substitute for a temporary one previously added to the tree. See
57     * StyleNodeFactory for details. "A node like the other one in all things but its class".
58     * Note that at this stage, the node will not yet be known to its parent, though it will
59     * contain a reference to its parent; and it will have no children.
60     */

61
62     public void substituteFor(StyleElement temp) {
63         this.parent = temp.parent;
64         this.attributeList = temp.attributeList;
65         this.namespaceList = temp.namespaceList;
66         this.nameCode = temp.nameCode;
67         this.sequence = temp.sequence;
68         this.attributeSets = temp.attributeSets;
69         this.extensionNamespaces = temp.extensionNamespaces;
70         this.excludedNamespaces = temp.excludedNamespaces;
71         this.version = temp.version;
72         this.root = temp.root;
73         this.staticContext = temp.staticContext;
74         this.validationError = temp.validationError;
75         this.reportingCircumstances = temp.reportingCircumstances;
76     }
77
78     /**
79     * Set a validation error
80     */

81     
82     protected void setValidationError(TransformerException JavaDoc reason,
83                                       int circumstances) {
84         if (reason instanceof TransformerConfigurationException JavaDoc) {
85             validationError = (TransformerConfigurationException JavaDoc)reason;
86         } else {
87             validationError = new TransformerConfigurationException JavaDoc(reason);
88         }
89         reportingCircumstances = circumstances;
90     }
91
92     /**
93     * Determine whether this node is an instruction. The default implementation says it isn't.
94     */

95
96     public boolean isInstruction() {
97         return false;
98     }
99
100     /**
101     * Determine whether this element does any processing after instantiating any children.
102     * The default implementation says it does. Tail recursion only works if call-template is
103     * nested entirely in elements that do no such processing. (If the element is empty, this
104     * property is irrelevant, because the element cannot contain an xsl:call-template).
105     */

106
107     public boolean doesPostProcessing() {
108         return true;
109     }
110
111     /**
112     * Determine whether this type of element is allowed to contain a template-body
113     */

114
115     public boolean mayContainTemplateBody() {
116         return false;
117     }
118
119     /**
120     * Get the containing XSLStyleSheet element
121     */

122     
123     public XSLStyleSheet getContainingStyleSheet() {
124         NodeImpl next = this;
125         while (!(next instanceof XSLStyleSheet)) {
126             next = (NodeImpl)next.getParent();
127         }
128         return (XSLStyleSheet)next;
129     }
130
131     /**
132     * Get the import precedence of this stylesheet element.
133     */

134
135     public int getPrecedence() {
136         return getContainingStyleSheet().getPrecedence();
137     }
138
139     /**
140     * Get the StandardNames object
141     */

142     
143     public final StandardNames getStandardNames() {
144         DocumentImpl root = (DocumentImpl)getDocumentRoot();
145         return ((StyleNodeFactory)root.getNodeFactory()).getStandardNames();
146     }
147
148     /**
149     * Process the attributes of this element and all its children
150     */

151
152     public void processAllAttributes() throws TransformerConfigurationException JavaDoc {
153         staticContext = new ExpressionContext(this);
154         processAttributes();
155         NodeImpl child = (NodeImpl)getFirstChild();
156         while (child != null) {
157             if (child instanceof StyleElement) {
158                 ((StyleElement)child).processAllAttributes();
159             }
160             child = (NodeImpl)child.getNextSibling();
161         }
162     }
163
164     /**
165     * Process the attribute list for the element. This is a wrapper method that calls
166     * prepareAttributes (provided in the subclass) and traps any exceptions
167     */

168
169     public final void processAttributes() throws TransformerConfigurationException JavaDoc {
170         try {
171             prepareAttributes();
172         } catch (TransformerConfigurationException JavaDoc err) {
173             if (forwardsCompatibleModeIsEnabled()) {
174                 //setValidationError(err, REPORT_IF_INSTANTIATED);
175
setValidationError(err, REPORT_UNLESS_FORWARDS_COMPATIBLE);
176             } else {
177                 compileError(err);
178             }
179         }
180     }
181
182     /**
183     * Check whether an unknown attribute is permitted.
184     * @param nc The name code of the attribute name
185     */

186     
187     protected void checkUnknownAttribute(int nc) throws TransformerConfigurationException JavaDoc {
188         if (forwardsCompatibleModeIsEnabled()) {
189             // then unknown attributes are permitted and ignored
190
return;
191         }
192         String JavaDoc attributeURI = getNamePool().getURI(nc);
193         String JavaDoc elementURI = getURI();
194         int attributeFingerprint = nc & 0xfffff;
195         StandardNames sn = getStandardNames();
196         
197         // allow xsl:extension-element-prefixes etc on an extension element
198

199         if (isInstruction() &&
200              attributeURI.equals(Namespace.XSLT) &&
201              !(elementURI.equals(Namespace.XSLT)) &&
202              (attributeFingerprint == sn.XSL_EXTENSION_ELEMENT_PREFIXES ||
203               attributeFingerprint == sn.XSL_EXCLUDE_RESULT_PREFIXES ||
204               attributeFingerprint == sn.XSL_VERSION)) {
205             return;
206         }
207         
208         if (attributeURI.equals("") || attributeURI.equals(Namespace.XSLT)) {
209             compileError("Attribute " + getNamePool().getDisplayName(nc) +
210                  " is not allowed on this element");
211         }
212     }
213     
214
215     /**
216     * Set the attribute list for the element. This is called to process the attributes (note
217     * the distinction from processAttributes in the superclass).
218     * Must be supplied in a subclass
219     */

220
221     public abstract void prepareAttributes() throws TransformerConfigurationException JavaDoc;
222
223     /**
224     * Make an expression in the context of this stylesheet element
225     */

226     
227     public Expression makeExpression(String JavaDoc expression)
228     throws TransformerConfigurationException JavaDoc {
229         try {
230             return Expression.make(expression, staticContext);
231         } catch(XPathException err) {
232             compileError(err);
233             return new ErrorExpression(err);
234         }
235     }
236
237     /**
238     * Make a pattern in the context of this stylesheet element
239     */

240     
241     public Pattern makePattern(String JavaDoc pattern)
242     throws TransformerConfigurationException JavaDoc {
243         try {
244             return Pattern.make(pattern, staticContext);
245         } catch(XPathException err) {
246             compileError(err);
247             return NoNodeTest.getInstance();
248         }
249     }
250
251     /**
252     * Make an attribute value template in the context of this stylesheet element
253     */

254     
255     public Expression makeAttributeValueTemplate(String JavaDoc expression)
256     throws TransformerConfigurationException JavaDoc {
257         try {
258             return AttributeValueTemplate.make(expression, staticContext);
259         } catch(XPathException err) {
260             compileError(err);
261             return new StringValue(expression);
262         }
263     }
264
265     /**
266     * Process the [xsl:]extension-element-prefixes attribute if there is one
267     * @param nc the name code of the attribute required
268     */

269
270     protected void processExtensionElementAttribute(int nc)
271     throws TransformerConfigurationException JavaDoc {
272         String JavaDoc ext = getAttributeValue(nc & 0xfffff);
273         if (ext!=null) {
274             // go round twice, once to count the values and next to add them to the array
275
int count = 0;
276             StringTokenizer st1 = new StringTokenizer(ext);
277             while (st1.hasMoreTokens()) {
278                 String JavaDoc s = st1.nextToken();
279                 count++;
280             }
281             extensionNamespaces = new short[count];
282             count = 0;
283             StringTokenizer st2 = new StringTokenizer(ext);
284             while (st2.hasMoreTokens()) {
285                 String JavaDoc s = st2.nextToken();
286                 if (s.equals("#default")) {
287                     s = "";
288                 }
289                 try {
290                     short uriCode = getURICodeForPrefix(s);
291                     extensionNamespaces[count++] = uriCode;
292                 } catch (NamespaceException err) {
293                     extensionNamespaces = null;
294                     compileError(err.getMessage());
295                 }
296             }
297         }
298     }
299
300     /**
301     * Process the [xsl:]exclude-result-prefixes attribute if there is one
302     * @param nc the name code of the attribute required
303     */

304
305     protected void processExcludedNamespaces(int nc)
306     throws TransformerConfigurationException JavaDoc {
307         String JavaDoc ext = getAttributeValue(nc & 0xfffff);
308         if (ext!=null) {
309             // go round twice, once to count the values and next to add them to the array
310
int count = 0;
311             StringTokenizer st1 = new StringTokenizer(ext);
312             while (st1.hasMoreTokens()) {
313                 String JavaDoc s = st1.nextToken();
314                 count++;
315             }
316             excludedNamespaces = new short[count];
317             count = 0;
318             StringTokenizer st2 = new StringTokenizer(ext);
319             while (st2.hasMoreTokens()) {
320                 String JavaDoc s = st2.nextToken();
321                 if (s.equals("#default")) {
322                     s = "";
323                 }
324                 try {
325                     short uriCode = getURICodeForPrefix(s);
326                     excludedNamespaces[count++] = uriCode;
327                 } catch (NamespaceException err) {
328                     excludedNamespaces = null;
329                     compileError(err.getMessage());
330                 }
331             }
332         }
333     }
334
335     /**
336     * Process the [xsl:]version attribute if there is one
337     * @param nc the name code of the attribute required
338     */

339
340     protected void processVersionAttribute(int nc) {
341         version = getAttributeValue(nc & 0xfffff);
342     }
343
344     /**
345     * Get the version number on this element, or inherited from its ancestors
346     */

347
348     public String JavaDoc getVersion() {
349         if (version==null) {
350             NodeInfo node = (NodeInfo)getParentNode();
351             if (node instanceof StyleElement) {
352                 version = ((StyleElement)node).getVersion();
353             } else {
354                 version = "1.0"; // defensive programming
355
}
356         }
357         return version;
358     }
359
360     /**
361     * Determine whether forwards-compatible mode is enabled for this element
362     */

363
364     public boolean forwardsCompatibleModeIsEnabled() {
365         return !(getVersion().equals("1.0"));
366     }
367         
368     /**
369     * Check whether a particular extension element namespace is defined on this node.
370     * This checks this node only, not the ancestor nodes.
371     * The implementation checks whether the prefix is included in the
372     * [xsl:]extension-element-prefixes attribute.
373     * @param uriCode the namespace URI code being tested
374     */

375
376     protected boolean definesExtensionElement(short uriCode) {
377         if (extensionNamespaces==null) {
378             return false;
379         }
380         for (int i=0; i<extensionNamespaces.length; i++) {
381             if (extensionNamespaces[i] == uriCode) {
382                 return true;
383             }
384         }
385         return false;
386     }
387
388     /**
389     * Check whether a namespace uri defines an extension element. This checks whether the
390     * namespace is defined as an extension namespace on this or any ancestor node.
391     * @param uriCode the namespace URI code being tested
392     */

393
394     public boolean isExtensionNamespace(short uriCode) {
395         NodeImpl anc = this;
396         while (anc instanceof StyleElement) {
397             if (((StyleElement)anc).definesExtensionElement(uriCode)) {
398                 return true;
399             }
400             anc = (NodeImpl)anc.getParent();
401         }
402         return false;
403     }
404
405     /**
406     * Check whether this node excludes a particular namespace from the result.
407     * This method checks this node only, not the ancestor nodes.
408     * @param uriCode the code of the namespace URI being tested
409     */

410
411     protected boolean definesExcludedNamespace(short uriCode) {
412         if (excludedNamespaces==null) {
413             return false;
414         }
415         for (int i=0; i<excludedNamespaces.length; i++) {
416             if (excludedNamespaces[i] == uriCode) {
417                 return true;
418             }
419         }
420         return false;
421     }
422
423     /**
424     * Check whether a namespace uri defines an namespace excluded from the result.
425     * This checks whether the namespace is defined as an excluded namespace on this
426     * or any ancestor node.
427     * @param uriCode the code of the namespace URI being tested
428     */

429
430     public boolean isExcludedNamespace(short uriCode) {
431         if (uriCode==Namespace.XSLT_CODE) return true;
432         if (isExtensionNamespace(uriCode)) return true;
433         NodeImpl anc = this;
434         while (anc instanceof StyleElement) {
435             if (((StyleElement)anc).definesExcludedNamespace(uriCode)) {
436                 return true;
437             }
438             anc = (NodeImpl)anc.getParent();
439         }
440         return false;
441     }
442
443     /**
444     * Check that the element is valid. This is called once for each element, after
445     * the entire tree has been built. As well as validation, it can perform first-time
446     * initialisation. The default implementation does nothing; it is normally overriden
447     * in subclasses.
448     */

449
450     public void validate() throws TransformerConfigurationException JavaDoc {}
451
452     /**
453     * Default preprocessing method does nothing. It is implemented for those top-level elements
454     * that can be evaluated before the source document is available, for example xsl:key,
455     * xsl:attribute-set, xsl:template, xsl:locale
456     */

457
458     public void preprocess() throws TransformerConfigurationException JavaDoc {}
459
460     /**
461     * Recursive walk through the stylesheet to validate all nodes
462     */

463
464     public void validateSubtree() throws TransformerConfigurationException JavaDoc {
465         if (validationError!=null) {
466             if (reportingCircumstances == REPORT_ALWAYS) {
467                 compileError(validationError);
468             } else if (reportingCircumstances == REPORT_UNLESS_FORWARDS_COMPATIBLE
469                           && !forwardsCompatibleModeIsEnabled()) {
470                 compileError(validationError);
471             }
472         } else {
473             try {
474                 validate();
475             } catch (TransformerConfigurationException JavaDoc err) {
476                 if (forwardsCompatibleModeIsEnabled()) {
477                     setValidationError(err, REPORT_IF_INSTANTIATED);
478                 } else {
479                     compileError(err);
480                 }
481             }
482             
483             validateChildren();
484         }
485     }
486     
487     protected void validateChildren() throws TransformerConfigurationException JavaDoc {
488         NodeImpl child = (NodeImpl)getFirstChild();
489         while (child != null) {
490             if (child instanceof StyleElement) {
491                 ((StyleElement)child).validateSubtree();
492             }
493             child = (NodeImpl)child.getNextSibling();
494         }
495     }
496
497     /**
498     * Get the principal XSLStyleSheet node. This gets the principal style sheet, i.e. the
499     * one originally loaded, that forms the root of the import/include tree
500     */

501
502     protected XSLStyleSheet getPrincipalStyleSheet() {
503         XSLStyleSheet sheet = getContainingStyleSheet();
504         while (true) {
505             XSLStyleSheet next = sheet.getImporter();
506             if (next==null) return sheet;
507             sheet = next;
508         }
509     }
510
511     /**
512     * Get the PreparedStyleSheet object.
513     * @return the PreparedStyleSheet to which this stylesheet element belongs
514     */

515
516     public PreparedStyleSheet getPreparedStyleSheet() {
517         return getPrincipalStyleSheet().getPreparedStyleSheet();
518     }
519
520     /**
521     * Check that the stylesheet element is within a template body
522     * @throws TransformerConfigurationException if not within a template body
523     */

524
525     public void checkWithinTemplate() throws TransformerConfigurationException JavaDoc {
526         StyleElement parent = (StyleElement)getParentNode();
527         if (!parent.mayContainTemplateBody()) {
528             compileError("Element must only be used within a template body");
529         }
530     }
531
532     /**
533     * Convenience method to check that the stylesheet element is at the top level
534     * @throws TransformerConfigurationException if not at top level
535     */

536
537     public void checkTopLevel() throws TransformerConfigurationException JavaDoc {
538         if (!(getParentNode() instanceof XSLStyleSheet)) {
539             compileError("Element must only be used at top level of stylesheet");
540         }
541     }
542
543     /**
544     * Convenience method to check that the stylesheet element is not at the top level
545     * @throws TransformerConfigurationException if it is at the top level
546     */

547
548     public void checkNotTopLevel() throws TransformerConfigurationException JavaDoc {
549         if (getParentNode() instanceof XSLStyleSheet) {
550             compileError("Element must not be used at top level of stylesheet");
551         }
552     }
553
554     /**
555     * Convenience method to check that the stylesheet element is empty
556     * @throws TransformerConfigurationException if it is not empty
557     */

558
559     public void checkEmpty() throws TransformerConfigurationException JavaDoc {
560         if (getFirstChild()!=null) {
561             compileError("Element must be empty");
562         }
563     }
564
565     /**
566     * Convenience method to report the absence of a mandatory attribute
567     * @throws TransformerConfigurationException if the attribute is missing
568     */

569
570     public void reportAbsence(String JavaDoc attribute)
571     throws TransformerConfigurationException JavaDoc {
572         compileError("Element must have a \"" + attribute + "\" attribute");
573     }
574
575     /**
576     * Process: called to do the real work of this stylesheet element. This method
577     * must be implemented in each subclass.
578     * @param context The context in the source XML document, giving access to the current node,
579     * the current variables, etc.
580     */

581
582     public abstract void process(Context context) throws TransformerException JavaDoc;
583
584     /**
585     * Process the children of this node in the stylesheet
586     * @param context The context in the source XML document, giving access to the current node,
587     * the current variables, etc.
588     */

589
590     public void processChildren(Context context) throws TransformerException JavaDoc {
591         
592         if (context.getController().isTracing()) { // e.g.
593
TraceListener listener = context.getController().getTraceListener();
594
595             NodeImpl node = (NodeImpl)getFirstChild();
596             while (node!=null) {
597
598                 listener.enter(node, context);
599
600                 if (node.getNodeType() == NodeInfo.TEXT) {
601                     node.copy(context.getOutputter());
602                 } else if (node instanceof StyleElement) {
603                     StyleElement snode = (StyleElement)node;
604                     if (snode.validationError != null) {
605                         fallbackProcessing(snode, context);
606                     } else {
607                         try {
608                             context.setStaticContext(snode.staticContext);
609                             snode.process(context);
610                         } catch (TransformerException JavaDoc err) {
611                             throw snode.styleError(err);
612                         }
613                     }
614                 }
615
616                 listener.leave(node, context);
617                 node = (NodeImpl)node.getNextSibling();
618             }
619
620         } else {
621
622             NodeImpl node = (NodeImpl)getFirstChild();
623             while (node!=null) {
624
625                 if (node.getNodeType() == NodeInfo.TEXT) {
626                     node.copy(context.getOutputter());
627                 } else if (node instanceof StyleElement) {
628                     StyleElement snode = (StyleElement)node;
629                     if (snode.validationError != null) {
630                         fallbackProcessing(snode, context);
631                     } else {
632                         try {
633                             context.setStaticContext(snode.staticContext);
634                             snode.process(context);
635                         } catch (TransformerException JavaDoc err) {
636                             throw snode.styleError(err);
637                         }
638                     }
639                 }
640                 node = (NodeImpl)node.getNextSibling();
641             }
642
643         }
644     }
645
646     // diagnostic version of process()
647

648     private void processX(Context context) throws TransformerException JavaDoc {
649         System.err.println("Processing " + context.getCurrentNodeInfo() + " using " + this);
650         process(context);
651     }
652
653     /**
654     * Perform fallback processing
655     */

656     
657     protected void fallbackProcessing(StyleElement instruction, Context context) throws TransformerException JavaDoc {
658         // process any xsl:fallback children; if there are none, report the original failure reason
659
XSLFallback fallback = null;
660         Node JavaDoc child = instruction.getFirstChild();
661         while (child!=null) {
662             if (child instanceof XSLFallback) {
663                 fallback = (XSLFallback)child;
664                 break;
665             }
666             child = child.getNextSibling();
667         }
668       
669         if (fallback==null) {
670             throw instruction.styleError(instruction.validationError);
671         }
672
673         boolean tracing = context.getController().isTracing();
674
675         while (child!=null) {
676             if (child instanceof XSLFallback) {
677                 XSLFallback f = (XSLFallback)child;
678                 
679                 if (tracing) {
680                     TraceListener listener = context.getController().getTraceListener();
681                     listener.enter(f, context);
682                     f.process(context);
683                     listener.leave(f, context);
684                 } else {
685                     f.process(context);
686                 }
687             }
688             child = child.getNextSibling();
689         }
690         
691         
692     }
693
694     /**
695     * Modify the "select" expression to include any sort keys specified. Used in XSLForEach
696     * and XSLApplyTemplates
697     */

698
699     protected Expression handleSortKeys(Expression select) {
700         // handle sort keys if any
701

702         int numberOfSortKeys = 0;
703         Node JavaDoc child = getFirstChild();
704
705         while(child!=null) {
706             if (child instanceof XSLSort) {
707                 numberOfSortKeys++;
708             }
709             child = child.getNextSibling();
710         }
711
712         if (numberOfSortKeys > 0) {
713             SortedSelection sortExpression = new SortedSelection(select, numberOfSortKeys);
714             child = getFirstChild();
715
716             int k=0;
717             while(child!=null) {
718                 if (child instanceof XSLSort) {
719                     sortExpression.setSortKey(
720                         ((XSLSort)child).getSortKeyDefinition(),
721                         k++);
722                 }
723                 child = child.getNextSibling();
724             }
725             return sortExpression;
726         
727         } else {
728             return new NodeListExpression(select); // sorts into document order
729
}
730     }
731
732     /**
733     * Determine the list of attribute-sets associated with this element.
734     * This is used for xsl:element, xsl:copy, xsl:attribute-set, and on literal
735     * result elements
736     */

737
738     protected void findAttributeSets(String JavaDoc use)
739     throws TransformerConfigurationException JavaDoc {
740
741         attributeSets = new Vector();
742         
743         XSLStyleSheet stylesheet = getPrincipalStyleSheet();
744         Vector toplevel = stylesheet.getTopLevel();
745
746         StringTokenizer st = new StringTokenizer(use);
747         while (st.hasMoreTokens()) {
748             String JavaDoc asetname = st.nextToken();
749             int fprint;
750             try {
751                 fprint = makeNameCode(asetname, false) & 0xfffff;
752             } catch (NamespaceException err) {
753                 compileError(err.getMessage());
754                 fprint = -1;
755             }
756             boolean found = false;
757
758             // search for the named attribute set, using all of them if there are several with the
759
// same name
760

761             for (int i=0; i<toplevel.size(); i++) {
762                 if (toplevel.elementAt(i) instanceof XSLAttributeSet) {
763                     XSLAttributeSet t = (XSLAttributeSet)toplevel.elementAt(i);
764                     if (t.getAttributeSetFingerprint() == fprint) {
765                         attributeSets.addElement(t);
766                         found = true;
767                     }
768                 }
769             }
770             
771             if (!found) {
772                 compileError("No attribute-set exists named " + asetname);
773             }
774         }
775     }
776
777     /**
778     * Expand the attribute sets referenced in this element's use-attribute-sets attribute
779     */

780
781     protected void processAttributeSets(Context context)
782     throws TransformerException JavaDoc {
783         if (attributeSets==null) return;
784         Controller c = context.getController();
785         for (int i=0; i<attributeSets.size(); i++) {
786             XSLAttributeSet aset = (XSLAttributeSet)attributeSets.elementAt(i);
787             
788             // detect circular references. TODO: Ideally we should do this at compile time
789
Object JavaDoc isBeingExpanded = c.getUserData(aset, "is-being-expanded");
790             if (isBeingExpanded!=null) {
791                 throw styleError("Circular reference to attribute set");
792             }
793             c.setUserData(aset, "is-being-expanded", "is-being-expanded");
794             aset.expand(context);
795             c.setUserData(aset, "is-being-expanded", null);
796         }
797     }
798
799     /**
800     * Construct an exception with diagnostic information
801     */

802
803     protected TransformerException JavaDoc styleError(TransformerException JavaDoc error) {
804         if (error instanceof StyleException) return error;
805         if (error instanceof TerminationException) return error;
806         if (error.getLocator()==null) {
807             return new TransformerException JavaDoc(error.getMessage(),
808                                             this,
809                                             error.getException());
810         }
811         return error;
812     }
813
814     protected TransformerException JavaDoc styleError(String JavaDoc message) {
815         return new TransformerException JavaDoc(message, this);
816     }
817
818     /**
819     * Construct an exception with diagnostic information
820     */

821
822     protected void compileError(TransformerException JavaDoc error)
823     throws TransformerConfigurationException JavaDoc {
824         if (error.getLocator()==null) {
825             error.setLocator(this);
826         }
827         PreparedStyleSheet pss = getPreparedStyleSheet();
828         try {
829             if (pss==null) {
830                 // it is null before the stylesheet has been fully built
831
throw error;
832             } else {
833                 pss.reportError(error);
834             }
835         } catch (TransformerException JavaDoc err2) {
836             if (err2 instanceof TransformerConfigurationException JavaDoc) {
837                 throw (TransformerConfigurationException JavaDoc)err2;
838             }
839             if (err2.getException() instanceof TransformerConfigurationException JavaDoc) {
840                 throw (TransformerConfigurationException JavaDoc)err2.getException();
841             }
842             TransformerConfigurationException JavaDoc tce = new TransformerConfigurationException JavaDoc(error);
843             tce.setLocator(this);
844             throw tce;
845         }
846     }
847
848     protected void compileError(String JavaDoc message)
849     throws TransformerConfigurationException JavaDoc {
850         TransformerConfigurationException JavaDoc tce =
851             new TransformerConfigurationException JavaDoc(message);
852         tce.setLocator(this);
853         compileError(tce);
854     }
855
856     /**
857     * Test whether this is a top-level element
858     */

859
860     public boolean isTopLevel() {
861         return (getParentNode() instanceof XSLStyleSheet);
862     }
863
864     /**
865     * Bind a variable used in this element to the XSLVariable element in which it is declared
866     * @param fingerprint The fingerprint of the name of the variable
867     * @return a Binding for the variable
868     * @throw XPathException if the variable has not been declared
869     */

870
871     public Binding bindVariable(int fingerprint) throws XPathException {
872         Binding binding = getVariableBinding(fingerprint);
873         if (binding==null) {
874             throw new XPathException("Variable " + getNamePool().getDisplayName(fingerprint) + " has not been declared");
875         }
876         return binding;
877     }
878
879     /**
880     * Bind a variable used in this element to the XSLVariable element in which it is declared
881     * @name The absolute name of the variable (prefixed by namespace URI)
882     * @return a Binding for the variable, or null if it has not been declared
883     */

884
885     public Binding getVariableBinding(int fprint) {
886         NodeImpl curr = this;
887         NodeImpl prev = this;
888
889         // first search for a local variable declaration
890
if (!isTopLevel()) {
891             while (true) {
892                 curr = (NodeImpl)curr.getPreviousSibling();
893                 while (curr==null) {
894                     curr = (NodeImpl)prev.getParent();
895                     prev = curr;
896                     if (curr.getParent() instanceof XSLStyleSheet) break; // top level
897
curr = (NodeImpl)curr.getPreviousSibling();
898                 }
899                 if (curr.getParent() instanceof XSLStyleSheet) break;
900                 if (curr instanceof Binding) {
901                     int var = ((Binding)curr).getVariableFingerprint();
902                     if (var==fprint) {
903                         return (Binding)curr;
904                     }
905                 }
906             }
907         }
908        
909         // Now check for a global variable
910
// we rely on the search following the order of decreasing import precedence.
911

912         XSLStyleSheet root = getPrincipalStyleSheet();
913         Vector toplevel = root.getTopLevel();
914         for (int i=toplevel.size()-1; i>=0; i--) {
915             Object JavaDoc child = toplevel.elementAt(i);
916             if (child instanceof Binding && child != this) {
917                 int var = ((Binding)child).getVariableFingerprint();
918                 if (var==fprint) {
919                     return (Binding)child;
920                 }
921             }
922         }
923         
924         return null;
925     }
926
927     /**
928     * List the variables that are in scope for this stylesheet element.
929     * Designed for a debugger, not used by the processor.
930     * @return two Enumeration of Strings, the global ones [0] and the local ones [1]
931     */

932     
933     public Enumeration[] getVariableNames() { // e.g.
934
Hashtable local = new Hashtable();
935         Hashtable global = new Hashtable();
936
937         NodeImpl curr = this;
938         NodeImpl prev = this;
939         NamePool pool = getNamePool();
940
941         // first collect the local variable declarations
942

943         if (!isTopLevel()) {
944             while (true) {
945                 curr = (NodeImpl)curr.getPreviousSibling();
946                 while (curr==null) {
947                     curr = (NodeImpl)prev.getParent();
948                     prev = curr;
949                     if (curr.getParent() instanceof XSLStyleSheet) break; // top level
950
curr = (NodeImpl)curr.getPreviousSibling();
951                 }
952                 if (curr.getParentNode() instanceof XSLStyleSheet) break;
953                 if (curr instanceof Binding) {
954                     int fprint = ((Binding)curr).getVariableFingerprint();
955                     String JavaDoc uri = pool.getURI(fprint);
956                     String JavaDoc lname = pool.getLocalName(fprint);
957                     String JavaDoc varname = uri + "^" + lname;
958                     if (local.get(varname)==null) {
959                         local.put(varname, varname);
960                     }
961                 }
962             }
963         }
964
965         // Now collect the global variables
966
// we rely on the search following the order of increasing import precedence.
967

968         XSLStyleSheet root = getPrincipalStyleSheet();
969         Vector toplevel = root.getTopLevel();
970         for (int i=0; i<toplevel.size(); i++) {
971             Object JavaDoc child = toplevel.elementAt(i);
972             if (child instanceof Binding && child != this) {
973                 int fprint = ((Binding)child).getVariableFingerprint();
974                 String JavaDoc uri = pool.getURI(fprint);
975                 String JavaDoc lname = pool.getLocalName(fprint);
976                 String JavaDoc varname = uri + "^" + lname;
977                 if (local.get(varname)==null) {
978                     global.put(varname, varname);
979                 }
980             }
981         }
982
983         Enumeration info[] = new Enumeration[2];
984         info[0] = global.keys();
985         info[1] = local.keys();
986         return info;
987     }
988
989
990     /**
991     * Get a Function declared using a saxon:function element in the stylesheet
992     * @param fingerprint the fingerprint of the name of the function
993     * @return the Function object represented by this saxon:function; or null if not found
994     */

995
996     public Function getStyleSheetFunction(int fingerprint) {
997
998         // we rely on the search following the order of decreasing import precedence.
999

1000        XSLStyleSheet root = getPrincipalStyleSheet();
1001        Vector toplevel = root.getTopLevel();
1002        for (int i=toplevel.size()-1; i>=0; i--) {
1003            Object JavaDoc child = toplevel.elementAt(i);
1004            if (child instanceof SAXONFunction &&
1005                    ((SAXONFunction)child).getFunctionFingerprint() == fingerprint) {
1006                StyleSheetFunctionCall fc = new StyleSheetFunctionCall();
1007                fc.setFunction((SAXONFunction)child);
1008                return fc;
1009            }
1010        }
1011        return null;
1012    }
1013
1014    /** needed to satisfy Locator interface
1015    */

1016    
1017    //public int getColumnNumber() {
1018
// return -1;
1019
//}
1020
}
1021
1022//
1023
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1024
// you may not use this file except in compliance with the License. You may obtain a copy of the
1025
// License at http://www.mozilla.org/MPL/
1026
//
1027
// Software distributed under the License is distributed on an "AS IS" basis,
1028
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1029
// See the License for the specific language governing rights and limitations under the License.
1030
//
1031
// The Original Code is: all this file.
1032
//
1033
// The Initial Developer of the Original Code is
1034
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
1035
//
1036
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1037
//
1038
// Contributor(s):
1039
// Portions marked "e.g." are from Edwin Glaser (edwin@pannenleiter.de)
1040
//
1041
Popular Tags