KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > style > StyleElement


1 package net.sf.saxon.style;
2
3 import net.sf.saxon.Err;
4 import net.sf.saxon.PreparedStylesheet;
5 import net.sf.saxon.Configuration;
6 import net.sf.saxon.event.LocationProvider;
7 import net.sf.saxon.expr.*;
8 import net.sf.saxon.instruct.*;
9 import net.sf.saxon.om.*;
10 import net.sf.saxon.pattern.*;
11 import net.sf.saxon.sort.SortKeyDefinition;
12 import net.sf.saxon.trace.InstructionInfo;
13 import net.sf.saxon.trace.Location;
14 import net.sf.saxon.trans.DynamicError;
15 import net.sf.saxon.trans.SaxonErrorCode;
16 import net.sf.saxon.trans.StaticError;
17 import net.sf.saxon.trans.XPathException;
18 import net.sf.saxon.tree.ElementWithAttributes;
19 import net.sf.saxon.type.*;
20 import net.sf.saxon.value.*;
21 import org.xml.sax.Locator JavaDoc;
22
23 import javax.xml.transform.SourceLocator JavaDoc;
24 import javax.xml.transform.TransformerConfigurationException JavaDoc;
25 import javax.xml.transform.TransformerException JavaDoc;
26 import java.math.BigDecimal JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31
32 /**
33  * Abstract superclass for all element nodes in the stylesheet. <BR>
34  * Note: this class implements Locator. The element
35  * retains information about its own location in the stylesheet, which is useful when
36  * an XSL error is found.
37  */

38
39 public abstract class StyleElement extends ElementWithAttributes
40         implements Locator JavaDoc, Container, InstructionInfo {
41
42     protected short[] extensionNamespaces = null; // a list of URI codes
43
private short[] excludedNamespaces = null; // a list of URI codes
44
protected BigDecimal JavaDoc version = null;
45     protected StaticContext staticContext = null;
46     protected StaticError validationError = null;
47     protected int reportingCircumstances = REPORT_ALWAYS;
48     protected String JavaDoc defaultXPathNamespace = null;
49     protected String JavaDoc defaultCollationName = null;
50     private int lineNumber; // maintained here because it's more efficient
51
// than using the lineNumberMap
52
private boolean explaining = false;
53     // true if saxon:explain="yes"
54
private int objectNameCode = -1;
55     // for instructions that define an XSLT named object, the name of that object
56
private XSLStylesheet containingStylesheet;
57
58     // Conditions under which an error is to be reported
59

60     public static final int REPORT_ALWAYS = 1;
61     public static final int REPORT_UNLESS_FORWARDS_COMPATIBLE = 2;
62     public static final int REPORT_IF_INSTANTIATED = 3;
63
64     /**
65      * Constructor
66      */

67
68     public StyleElement() {
69     }
70
71     public Executable getExecutable() {
72         return getPrincipalStylesheet().getExecutable();
73     }
74
75     /**
76      * Get the LocationProvider allowing location identifiers to be resolved.
77      */

78
79     public LocationProvider getLocationProvider() {
80         return getExecutable().getLocationMap();
81     }
82
83     /**
84      * Get the namepool to be used at run-time, this namepool holds the names used in
85      * all XPath expressions and patterns
86      */

87
88     public NamePool getTargetNamePool() {
89         return getPrincipalStylesheet().getTargetNamePool();
90     }
91
92     /**
93      * Get the static context for expressions on this element
94      *
95      * @return the static context
96      */

97
98     public StaticContext getStaticContext() {
99         if (staticContext == null) {
100             staticContext = new ExpressionContext(this);
101         }
102         return staticContext;
103     }
104
105     public int getLineNumber() {
106         return lineNumber;
107     }
108
109     public void setLineNumber(int lineNumber) {
110         this.lineNumber = lineNumber;
111     }
112
113     /**
114      * Determine whether saxon:explain has been set to "yes"
115      */

116
117     protected boolean isExplaining() {
118         return explaining;
119     }
120
121     /**
122      * Make this node a substitute for a temporary one previously added to the tree. See
123      * StyleNodeFactory for details. "A node like the other one in all things but its class".
124      * Note that at this stage, the node will not yet be known to its parent, though it will
125      * contain a reference to its parent; and it will have no children.
126      */

127
128     public void substituteFor(StyleElement temp) {
129         this.parent = temp.parent;
130         this.attributeList = temp.attributeList;
131         this.namespaceList = temp.namespaceList;
132         this.nameCode = temp.nameCode;
133         this.sequence = temp.sequence;
134         this.extensionNamespaces = temp.extensionNamespaces;
135         this.excludedNamespaces = temp.excludedNamespaces;
136         this.version = temp.version;
137         this.root = temp.root;
138         this.staticContext = temp.staticContext;
139         this.validationError = temp.validationError;
140         this.reportingCircumstances = temp.reportingCircumstances;
141         this.lineNumber = temp.lineNumber;
142     }
143
144     /**
145      * Set a validation error
146      */

147
148     protected void setValidationError(TransformerException JavaDoc reason,
149                                       int circumstances) {
150         validationError = StaticError.makeStaticError(reason);
151         reportingCircumstances = circumstances;
152     }
153
154     /**
155      * Determine whether this node is an instruction. The default implementation says it isn't.
156      */

157
158     public boolean isInstruction() {
159         return false;
160     }
161
162     /**
163      * Determine the type of item returned by this instruction (only relevant if
164      * it is an instruction). Default implementation returns Type.ITEM, indicating
165      * that we don't know, it might be anything. Returns null in the case of an element
166      * such as xsl:sort or xsl:variable that can appear in a sequence constructor but
167      * contributes nothing to the result sequence.
168      *
169      * @return the item type returned
170      */

171
172     protected ItemType getReturnedItemType() {
173         return AnyItemType.getInstance();
174     }
175
176     /**
177      * Get the most general type of item returned by the children of this instruction
178      *
179      * @return the lowest common supertype of the item types returned by the children
180      */

181
182     protected ItemType getCommonChildItemType() {
183         ItemType t = NoNodeTest.getInstance();
184         AxisIterator children = iterateAxis(Axis.CHILD);
185         while (true) {
186             NodeInfo next = (NodeInfo)children.next();
187             if (next == null) {
188                 return t;
189             }
190             if (next instanceof StyleElement) {
191                 ItemType ret = ((StyleElement)next).getReturnedItemType();
192                 if (ret != null) {
193                     t = Type.getCommonSuperType(t, ret);
194                 }
195             } else {
196                 t = Type.getCommonSuperType(t, NodeKindTest.TEXT);
197             }
198             if (t == AnyItemType.getInstance()) {
199                 return t; // no point looking any further
200
}
201         }
202     }
203
204     /**
205      * Mark tail-recursive calls on templates and functions.
206      * For most instructions, this does nothing.
207      */

208
209     public void markTailCalls() {
210         // no-op
211
}
212
213     /**
214      * Determine whether this type of element is allowed to contain a sequence constructor
215      */

216
217     public boolean mayContainSequenceConstructor() {
218         return false;
219     }
220
221     /**
222      * Determine whether this type of element is allowed to contain an xsl:fallback
223      * instruction
224      */

225
226     public boolean mayContainFallback() {
227         return mayContainSequenceConstructor();
228     }
229
230     /**
231      * Get the containing XSLStylesheet element
232      */

233
234     public XSLStylesheet getContainingStylesheet() {
235         if (containingStylesheet == null) {
236             if (this instanceof XSLStylesheet) {
237                 containingStylesheet = (XSLStylesheet)this;
238             } else {
239                 containingStylesheet = ((StyleElement)getParent()).getContainingStylesheet();
240             }
241         }
242         return containingStylesheet;
243     }
244
245     /**
246      * Get the import precedence of this stylesheet element.
247      */

248
249     public int getPrecedence() {
250         return getContainingStylesheet().getPrecedence();
251     }
252
253     /**
254      * Get the URI for a namespace prefix using the in-scope namespaces for
255      * this element in the stylesheet
256      *
257      * @param prefix The namespace prefix: may be the empty string
258      * @param useDefault True if the default namespace is to be used when the
259      * prefix is "".
260      * @return the namespace URI if the prefix is bound to a namespace; "" if the
261      * prefix ("") is bound to no namespace; null if the prefix is not bound.
262      */

263
264 // public String getURIForPrefix(String prefix, boolean useDefault) {
265
// if ("".equals(prefix) && !useDefault) {
266
// return "";
267
// } else {
268
// try {
269
// short uricode = getURICodeForPrefix(prefix);
270
// return getNamePool().getURIFromURICode(uricode);
271
// } catch (NamespaceException e) {
272
// return null;
273
// }
274
// }
275
// }
276

277     /**
278      * Make a NameCode, using this Element as the context for namespace resolution, and
279      * registering the code in the namepool. If the name is unprefixed, the
280      * default namespace is <b>not</b> used.
281      *
282      * @param qname The name as written, in the form "[prefix:]localname". The name must have
283      * already been validated as a syntactically-correct QName.
284      * @throws XPathException if the qname is not a lexically-valid QName, or if the name
285      * is in a reserved namespace.
286      * @throws NamespaceException if the prefix of the qname has not been declared
287      */

288
289     public final int makeNameCode(String JavaDoc qname)
290             throws XPathException, NamespaceException {
291
292         NamePool namePool = getTargetNamePool();
293         String JavaDoc[] parts;
294         try {
295             parts = Name.getQNameParts(qname);
296         } catch (QNameException err) {
297             StaticError e2 = new StaticError(err.getMessage());
298             e2.setErrorCode("XTSE0020");
299             throw e2;
300         }
301         String JavaDoc prefix = parts[0];
302         if ("".equals(prefix)) {
303             return namePool.allocate(prefix, (short)0, qname);
304
305         } else {
306
307             String JavaDoc uri = getURIForPrefix(prefix, false);
308             if (uri == null) {
309                 throw new NamespaceException(prefix);
310             }
311             if (NamespaceConstant.isReserved(uri)) {
312                 StaticError err = new StaticError("Namespace prefix " + prefix + " refers to a reserved namespace");
313                 err.setErrorCode("XTSE0080");
314                 throw err;
315             }
316             return namePool.allocate(prefix, uri, parts[1]);
317         }
318
319     }
320
321     /**
322      * Make a NamespaceContext object representing the list of in-scope namespaces. The NamePool
323      * used for numeric codes in the NamespaceContext will be the target name pool.
324      */

325
326     public SavedNamespaceContext makeNamespaceContext() {
327         return new SavedNamespaceContext(getInScopeNamespaceCodes(), getNamePool());
328     }
329
330     /**
331      * Process the attributes of this element and all its children
332      */

333
334     public void processAllAttributes() throws XPathException {
335         staticContext = new ExpressionContext(this);
336         processAttributes();
337         AxisIterator kids = iterateAxis(Axis.CHILD);
338         while (true) {
339             NodeInfo child = (NodeInfo)kids.next();
340             if (child == null) {
341                 return;
342             }
343             if (child instanceof StyleElement) {
344                 ((StyleElement)child).processAllAttributes();
345                 if (((StyleElement)child).explaining) {
346                     // saxon:explain on any element in a template/function now causes an explanation at the
347
// level of the template/function
348
explaining = true;
349                 }
350             }
351         }
352     }
353
354     /**
355      * Get an attribute value given the Clark name of the attribute (that is,
356      * the name in {uri}local format).
357      */

358
359     public String JavaDoc getAttributeValue(String JavaDoc clarkName) {
360         int fp = getNamePool().allocateClarkName(clarkName);
361         return getAttributeValue(fp);
362     }
363
364     /**
365      * Process the attribute list for the element. This is a wrapper method that calls
366      * prepareAttributes (provided in the subclass) and traps any exceptions
367      */

368
369     public final void processAttributes() throws XPathException {
370         try {
371             prepareAttributes();
372         } catch (XPathException err) {
373             if (forwardsCompatibleModeIsEnabled()) {
374                 setValidationError(err, REPORT_IF_INSTANTIATED);
375             } else {
376                 compileError(err);
377             }
378         }
379     }
380
381     /**
382      * Check whether an unknown attribute is permitted.
383      *
384      * @param nc The name code of the attribute name
385      */

386
387     protected void checkUnknownAttribute(int nc) throws XPathException {
388
389         String JavaDoc attributeURI = getNamePool().getURI(nc);
390         String JavaDoc elementURI = getURI();
391         String JavaDoc clarkName = getNamePool().getClarkName(nc);
392
393         if (clarkName.equals(StandardNames.SAXON_EXPLAIN)) {
394             explaining = "yes".equals(getAttributeValue(nc & 0xfffff));
395         }
396
397         if (forwardsCompatibleModeIsEnabled()) {
398             // then unknown attributes are permitted and ignored
399
return;
400         }
401
402         // allow xsl:extension-element-prefixes etc on an extension element
403

404         if (isInstruction() &&
405                 clarkName.startsWith('{' + NamespaceConstant.XSLT) &&
406                 !(elementURI.equals(NamespaceConstant.XSLT)) &&
407                 (clarkName.endsWith("}default-collation") ||
408                 clarkName.endsWith("}xpath-default-namespace") ||
409                 clarkName.endsWith("}extension-element-prefixes") ||
410                 clarkName.endsWith("}exclude-result-prefixes") ||
411                 clarkName.endsWith("}version") ||
412                 clarkName.endsWith("}use-when"))) {
413             return;
414         }
415
416         // allow standard attributes on an XSLT element
417

418         if (elementURI.equals(NamespaceConstant.XSLT) &&
419                 (clarkName == StandardNames.DEFAULT_COLLATION ||
420                 clarkName == StandardNames.XPATH_DEFAULT_NAMESPACE ||
421                 clarkName == StandardNames.EXTENSION_ELEMENT_PREFIXES ||
422                 clarkName == StandardNames.EXCLUDE_RESULT_PREFIXES ||
423                 clarkName == StandardNames.VERSION ||
424                 clarkName == StandardNames.USE_WHEN)) {
425             return;
426         }
427
428         if ("".equals(attributeURI) || NamespaceConstant.XSLT.equals(attributeURI)) {
429             compileError("Attribute " + Err.wrap(getNamePool().getDisplayName(nc), Err.ATTRIBUTE) +
430                     " is not allowed on element " + Err.wrap(getDisplayName(), Err.ELEMENT), "XTSE0010");
431         }
432     }
433
434
435     /**
436      * Set the attribute list for the element. This is called to process the attributes (note
437      * the distinction from processAttributes in the superclass).
438      * Must be supplied in a subclass
439      */

440
441     public abstract void prepareAttributes() throws XPathException;
442
443     /**
444      * Find the last child instruction of this instruction. Returns null if
445      * there are no child instructions, or if the last child is a text node.
446      */

447
448     protected StyleElement getLastChildInstruction() {
449         StyleElement last = null;
450         AxisIterator kids = iterateAxis(Axis.CHILD);
451         while (true) {
452             NodeInfo child = (NodeInfo)kids.next();
453             if (child == null) {
454                 return last;
455             }
456             if (child instanceof StyleElement) {
457                 last = (StyleElement)child;
458             } else {
459                 last = null;
460             }
461         }
462     }
463
464     /**
465      * Make an expression in the context of this stylesheet element
466      */

467
468     public Expression makeExpression(String JavaDoc expression)
469             throws XPathException {
470         try {
471             Expression exp = ExpressionTool.make(expression,
472                     staticContext,
473                     0, Token.EOF,
474                     getLineNumber());
475             return exp;
476         } catch (XPathException err) {
477             err.setLocator(this);
478             if (!forwardsCompatibleModeIsEnabled()) {
479                 compileError(err);
480             } else if (err.isTypeError()) {
481                 compileError(err);
482             }
483             ErrorExpression erexp = new ErrorExpression(err);
484             erexp.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
485             erexp.setParentExpression(this);
486             return erexp;
487         }
488     }
489
490     /**
491      * Make a pattern in the context of this stylesheet element
492      */

493
494     public Pattern makePattern(String JavaDoc pattern)
495             throws XPathException {
496         try {
497             return Pattern.make(pattern, staticContext, getPrincipalStylesheet().getExecutable());
498         } catch (XPathException err) {
499             if (forwardsCompatibleModeIsEnabled()) {
500                 compileWarning("Invalid pattern, ignored because in forwards-compatibility mode. " +
501                         err.getMessage(), err.getErrorCodeLocalPart());
502                 return new NodeTestPattern(NoNodeTest.getInstance());
503             } else {
504                 compileError(err);
505                 return new NodeTestPattern(AnyNodeTest.getInstance());
506             }
507         }
508     }
509
510     /**
511      * Make an attribute value template in the context of this stylesheet element
512      */

513
514     public Expression makeAttributeValueTemplate(String JavaDoc expression)
515             throws XPathException {
516         try {
517             return AttributeValueTemplate.make(expression, getLineNumber(), staticContext);
518         } catch (XPathException err) {
519             compileError(err);
520             return new StringValue(expression);
521         }
522     }
523
524     /**
525      * Process an attribute whose value is a SequenceType
526      */

527
528     public SequenceType makeSequenceType(String JavaDoc sequenceType)
529             throws XPathException {
530         getStaticContext();
531         try {
532             ExpressionParser parser = new ExpressionParser();
533             return parser.parseSequenceType(sequenceType, staticContext);
534         } catch (XPathException err) {
535             compileError(err);
536 // recovery path after reporting an error, e.g. undeclared namespace prefix
537
return SequenceType.ANY_SEQUENCE;
538         }
539     }
540
541     /**
542      * Process the [xsl:]extension-element-prefixes attribute if there is one
543      *
544      * @param nc the Clark name of the attribute required
545      */

546
547     protected void processExtensionElementAttribute(String JavaDoc nc)
548             throws XPathException {
549         String JavaDoc ext = getAttributeValue(nc);
550         if (ext != null) {
551             // go round twice, once to count the values and next to add them to the array
552
int count = 0;
553             StringTokenizer JavaDoc st1 = new StringTokenizer JavaDoc(ext);
554             while (st1.hasMoreTokens()) {
555                 st1.nextToken();
556                 count++;
557             }
558             extensionNamespaces = new short[count];
559             count = 0;
560             StringTokenizer JavaDoc st2 = new StringTokenizer JavaDoc(ext);
561             while (st2.hasMoreTokens()) {
562                 String JavaDoc s = st2.nextToken();
563                 if ("#default".equals(s)) {
564                     s = "";
565                 }
566                 try {
567                     short uriCode = getURICodeForPrefix(s);
568                     extensionNamespaces[count++] = uriCode;
569                 } catch (NamespaceException err) {
570                     extensionNamespaces = null;
571                     compileError(err.getMessage(), "XT0280");
572                 }
573             }
574         }
575     }
576
577     /**
578      * Process the [xsl:]exclude-result-prefixes attribute if there is one
579      *
580      * @param nc the Clark name of the attribute required
581      */

582
583     protected void processExcludedNamespaces(String JavaDoc nc)
584             throws XPathException {
585         String JavaDoc ext = getAttributeValue(nc);
586         if (ext != null) {
587             if ("#all".equals(ext.trim())) {
588                 int[] codes = getInScopeNamespaceCodes();
589                 excludedNamespaces = new short[codes.length];
590                 for (int i = 0; i < codes.length; i++) {
591                     excludedNamespaces[i] = (short)(codes[i] & 0xffff);
592                 }
593             } else {
594                 // go round twice, once to count the values and next to add them to the array
595
int count = 0;
596                 StringTokenizer JavaDoc st1 = new StringTokenizer JavaDoc(ext);
597                 while (st1.hasMoreTokens()) {
598                     st1.nextToken();
599                     count++;
600                 }
601                 excludedNamespaces = new short[count];
602                 count = 0;
603                 StringTokenizer JavaDoc st2 = new StringTokenizer JavaDoc(ext);
604                 while (st2.hasMoreTokens()) {
605                     String JavaDoc s = st2.nextToken();
606                     if ("#default".equals(s)) {
607                         s = "";
608                     } else if ("#all".equals(s)) {
609                         compileError("In exclude-result-prefixes, cannot mix #all with other values", "XTSE0020");
610                     }
611                     try {
612                         short uriCode = getURICodeForPrefix(s);
613                         excludedNamespaces[count++] = uriCode;
614                     } catch (NamespaceException err) {
615                         excludedNamespaces = null;
616                         compileError(err.getMessage(), "XTSE0280");
617                     }
618                 }
619             }
620         }
621     }
622
623     /**
624      * Process the [xsl:]version attribute if there is one
625      *
626      * @param nc the Clark name of the attribute required
627      */

628
629     protected void processVersionAttribute(String JavaDoc nc) throws XPathException {
630         String JavaDoc v = getAttributeValue(nc);
631         if (v != null) {
632             AtomicValue val = DecimalValue.makeDecimalValue(v, true);
633             if (val instanceof ValidationErrorValue) {
634                 compileError("The version attribute must be a decimal literal");
635             }
636             version = ((DecimalValue)val).getValue();
637         }
638     }
639
640     /**
641      * Get the numeric value of the version number on this element,
642      * or inherited from its ancestors
643      */

644
645     public BigDecimal JavaDoc getVersion() {
646         if (version == null) {
647             NodeInfo node = getParent();
648             if (node instanceof StyleElement) {
649                 version = ((StyleElement)node).getVersion();
650             } else {
651                 version = new BigDecimal JavaDoc("2.0"); // defensive programming
652
}
653         }
654         return version;
655     }
656
657     /**
658      * Determine whether forwards-compatible mode is enabled for this element
659      */

660
661     public boolean forwardsCompatibleModeIsEnabled() {
662         return getVersion().compareTo(BigDecimal.valueOf(2)) > 0;
663     }
664
665     /**
666      * Determine whether backwards-compatible mode is enabled for this element
667      */

668
669     public boolean backwardsCompatibleModeIsEnabled() {
670         return getVersion().compareTo(BigDecimal.valueOf(2)) < 0;
671     }
672
673     /**
674      * Process the [xsl:]default-xpath-namespace attribute if there is one
675      *
676      * @param nc the Clark name of the attribute required
677      */

678
679     protected void processDefaultCollationAttribute(String JavaDoc nc) throws XPathException {
680         String JavaDoc v = getAttributeValue(nc);
681         if (v != null) {
682             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(v);
683             while (st.hasMoreTokens()) {
684                 String JavaDoc uri = st.nextToken();
685                 if (uri.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) {
686                     defaultCollationName = uri;
687                     return;
688                 } else if (uri.startsWith("http://saxon.sf.net/")) {
689                     defaultCollationName = uri;
690                     return;
691                 } else if (getPrincipalStylesheet().getExecutable().getNamedCollation(uri) != null) {
692                     defaultCollationName = uri;
693                     return;
694                 }
695                 // if not recognized, try the next URI in order
696
}
697             compileError("No recognized collation URI found in default-collation attribute", "XTSE0125");
698         }
699     }
700
701     /**
702      * Get the default collation for this element
703      */

704
705     protected String JavaDoc getDefaultCollationName() {
706         StyleElement e = this;
707         while (true) {
708             if (e.defaultCollationName != null) {
709                 return e.defaultCollationName;
710             }
711             NodeInfo p = e.getParent();
712             if (!(p instanceof StyleElement)) {
713                 break;
714             }
715             e = (StyleElement)p;
716         }
717         return getPrincipalStylesheet().getDefaultCollationName();
718     }
719
720     /**
721      * Check whether a particular extension element namespace is defined on this node.
722      * This checks this node only, not the ancestor nodes.
723      * The implementation checks whether the prefix is included in the
724      * [xsl:]extension-element-prefixes attribute.
725      *
726      * @param uriCode the namespace URI code being tested
727      */

728
729     protected boolean definesExtensionElement(short uriCode) {
730         if (extensionNamespaces == null) {
731             return false;
732         }
733         for (int i = 0; i < extensionNamespaces.length; i++) {
734             if (extensionNamespaces[i] == uriCode) {
735                 return true;
736             }
737         }
738         return false;
739     }
740
741     /**
742      * Check whether a namespace uri defines an extension element. This checks whether the
743      * namespace is defined as an extension namespace on this or any ancestor node.
744      *
745      * @param uriCode the namespace URI code being tested
746      */

747
748     public boolean isExtensionNamespace(short uriCode) {
749         NodeInfo anc = this;
750         while (anc instanceof StyleElement) {
751             if (((StyleElement)anc).definesExtensionElement(uriCode)) {
752                 return true;
753             }
754             anc = anc.getParent();
755         }
756         return false;
757     }
758
759     /**
760      * Check whether this node excludes a particular namespace from the result.
761      * This method checks this node only, not the ancestor nodes.
762      *
763      * @param uriCode the code of the namespace URI being tested
764      */

765
766     protected boolean definesExcludedNamespace(short uriCode) {
767         if (excludedNamespaces == null) {
768             return false;
769         }
770         for (int i = 0; i < excludedNamespaces.length; i++) {
771             if (excludedNamespaces[i] == uriCode) {
772                 return true;
773             }
774         }
775         return false;
776     }
777
778     /**
779      * Check whether a namespace uri defines an namespace excluded from the result.
780      * This checks whether the namespace is defined as an excluded namespace on this
781      * or any ancestor node.
782      *
783      * @param uriCode the code of the namespace URI being tested
784      */

785
786     public boolean isExcludedNamespace(short uriCode) {
787         if (uriCode == NamespaceConstant.XSLT_CODE) {
788             return true;
789         }
790         if (isExtensionNamespace(uriCode)) {
791             return true;
792         }
793         NodeInfo anc = this;
794         while (anc instanceof StyleElement) {
795             if (((StyleElement)anc).definesExcludedNamespace(uriCode)) {
796                 return true;
797             }
798             anc = anc.getParent();
799         }
800         return false;
801     }
802
803     /**
804      * Process the [xsl:]default-xpath-namespace attribute if there is one
805      *
806      * @param nc the Clark name of the attribute required
807      */

808
809     protected void processDefaultXPathNamespaceAttribute(String JavaDoc nc) throws TransformerConfigurationException JavaDoc {
810         String JavaDoc v = getAttributeValue(nc);
811         if (v != null) {
812             defaultXPathNamespace = v;
813         }
814     }
815
816     /**
817      * Get the default XPath namespace code applicable to this element
818      */

819
820     protected short getDefaultXPathNamespace() {
821         NodeInfo anc = this;
822         while (anc instanceof StyleElement) {
823             String JavaDoc x = ((StyleElement)anc).defaultXPathNamespace;
824             if (x != null) {
825                 return getTargetNamePool().allocateCodeForURI(x);
826             }
827             anc = anc.getParent();
828         }
829         return NamespaceConstant.NULL_CODE;
830         // indicates that the default namespace is the null namespace
831
}
832
833     /**
834      * Get the Schema type definition for a type named in the stylesheet (in a
835      * "type" attribute).
836      *
837      * @throws XPathException
838      * if the type is not declared in an
839      * imported schema, or is not a built-in type
840      */

841
842     public SchemaType getSchemaType(String JavaDoc typeAtt) throws XPathException {
843         try {
844             String JavaDoc[] parts = Name.getQNameParts(typeAtt);
845             String JavaDoc lname = parts[1];
846             String JavaDoc uri;
847             if ("".equals(parts[0])) {
848                 // Name is unprefixed: use the default-xpath-namespace
849
short uricode = getDefaultXPathNamespace();
850                 uri = getTargetNamePool().getURIFromURICode(uricode);
851                 nameCode = getTargetNamePool().allocate(parts[0], uricode, lname);
852             } else {
853                 uri = getURIForPrefix(parts[0], false);
854                 if (uri == null) {
855                     compileError("Namespace prefix for type annotation is undeclared", "XTSE0280");
856                     return null;
857                 }
858             }
859             int nameCode = getTargetNamePool().allocate(parts[0], uri, lname);
860             if (uri.equals(NamespaceConstant.SCHEMA)) {
861                 SchemaType t = BuiltInSchemaFactory.getSchemaType(StandardNames.getFingerprint(uri, lname));
862                 if (t == null) {
863                     compileError("Unknown built-in type " + typeAtt);
864                     return null;
865                 }
866                 return t;
867             } else if (NamespaceConstant.isXDTNamespace(uri)) {
868                 ItemType t = Type.getBuiltInItemType(NamespaceConstant.XDT, lname);
869                 if (t == null) {
870                     if ("untyped".equals(lname)) {
871                         compileError("Cannot validate a node as 'untyped'");
872                     } else {
873                         compileError("Unknown built-in type " + typeAtt);
874                     }
875                 }
876                 return (BuiltInAtomicType)t;
877             }
878
879             // not a built-in type: look in the imported schemas
880

881             if (!getPrincipalStylesheet().isImportedSchema(uri)) {
882                 compileError("There is no imported schema for the namespace of type " + typeAtt);
883                 return null;
884             }
885             SchemaType stype = getConfiguration().getSchemaType(nameCode & 0xfffff);
886             if (stype == null) {
887                 compileError("There is no type named " + typeAtt + " in an imported schema");
888             }
889             return stype;
890
891         } catch (QNameException err) {
892             compileError("Invalid type name. " + err.getMessage());
893         }
894         return null;
895     }
896
897     /**
898      * Get the type annotation to use for a given schema type
899      */

900
901     public int getTypeAnnotation(SchemaType schemaType) {
902         if (schemaType != null) {
903             return schemaType.getFingerprint();
904         } else {
905             return -1;
906         }
907     }
908
909     /**
910      * Check that the stylesheet element is valid. This is called once for each element, after
911      * the entire tree has been built. As well as validation, it can perform first-time
912      * initialisation. The default implementation does nothing; it is normally overriden
913      * in subclasses.
914      */

915
916     public void validate() throws XPathException {
917     }
918
919     /**
920      * Hook to allow additional validation of a parent element immediately after its
921      * children have been validated.
922      */

923
924     public void postValidate() throws XPathException {
925     }
926
927     /**
928      * Type-check an expression. This is called to check each expression while the containing
929      * instruction is being validated. It is not just a static type-check, it also adds code
930      * to perform any necessary run-time type checking and/or conversion.
931      */

932
933     // Note: the typeCheck() call is done at the level of individual path expression; the optimize() call is done
934
// for a template or function as a whole. We can't do it all at the function/template level because
935
// the static context (e.g. namespaces) changes from one XPath expression to another.
936

937     public Expression typeCheck(String JavaDoc name, Expression exp) throws XPathException {
938
939         if (exp == null) {
940             return null;
941         }
942
943         //ExpressionTool.makeParentReferences(exp);
944
if (exp instanceof ComputedExpression) {
945             ((ComputedExpression)exp).setParentExpression(this);
946             // temporary, until the instruction is compiled
947
}
948
949         try {
950             exp = exp.typeCheck(staticContext, Type.ITEM_TYPE);
951             exp = ExpressionTool.resolveCallsToCurrentFunction(exp, getConfiguration());
952 // if (explaining) {
953
// System.err.println("Attribute '" + name + "' of element '" + getDisplayName() + "' at line " + getLineNumber() + ':');
954
// System.err.println("Static type: " +
955
// SequenceType.makeSequenceType(exp.getItemType(), exp.getCardinality()));
956
// System.err.println("Optimized expression tree:");
957
// exp.display(10, getNamePool(), System.err);
958
// }
959
if (getConfiguration().getTraceListener() != null) {
960                 InstructionDetails details = new InstructionDetails();
961                 details.setConstructType(Location.XPATH_IN_XSLT);
962                 details.setLineNumber(getLineNumber());
963                 details.setSystemId(getSystemId());
964                 details.setProperty("attribute-name", name);
965                 TraceWrapper trace = new TraceInstruction(exp, details);
966                 trace.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
967                 trace.setParentExpression(this);
968                 exp = trace;
969             }
970             return exp;
971         } catch (DynamicError err) {
972             // we can't report a dynamic error such as divide by zero unless the expression
973
// is actually executed.
974
if (err.isTypeError()) {
975                 compileError(err);
976                 return exp;
977             } else {
978                 ErrorExpression erexp = new ErrorExpression(err);
979                 erexp.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
980                 return erexp;
981             }
982         } catch (XPathException err) {
983             compileError(err);
984             ErrorExpression erexp = new ErrorExpression(err);
985             erexp.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
986             return erexp;
987         }
988     }
989
990     /**
991      * Allocate slots in the local stack frame to range variables used in an XPath expression
992      *
993      * @param exp the XPath expression for which slots are to be allocated
994      */

995
996     public void allocateSlots(Expression exp) {
997         SlotManager slotManager = getContainingSlotManager();
998         if (slotManager == null) {
999             throw new AssertionError JavaDoc("Slot manager has not been allocated");
1000            // previous code: ExpressionTool.allocateSlots(exp, 0, null);
1001
} else {
1002            int firstSlot = slotManager.getNumberOfVariables();
1003            int highWater = ExpressionTool.allocateSlots(exp, firstSlot, slotManager);
1004            if (highWater > firstSlot) {
1005                slotManager.setNumberOfVariables(highWater);
1006                // This algorithm is not very efficient because it never reuses
1007
// a slot when a variable goes out of scope. But at least it is safe.
1008
// Note that range variables within XPath expressions need to maintain
1009
// a slot until the instruction they are part of finishes, e.g. in
1010
// xsl:for-each.
1011
}
1012        }
1013    }
1014
1015    /**
1016     * Type-check a pattern. This is called to check each pattern while the containing
1017     * instruction is being validated. It is not just a static type-check, it also adds code
1018     * to perform any necessary run-time type checking and/or conversion.
1019     */

1020
1021    public Pattern typeCheck(String JavaDoc name, Pattern pattern) throws XPathException {
1022        if (pattern == null) {
1023            return null;
1024        }
1025        try {
1026            pattern = pattern.analyze(staticContext, Type.NODE_TYPE);
1027            boolean usesCurrent = false;
1028            int current = getNamePool().allocate("", NamespaceConstant.FN, "current") & NamePool.FP_MASK;
1029            if (pattern instanceof LocationPathPattern) {
1030                Iterator JavaDoc sub = pattern.iterateSubExpressions();
1031                while (sub.hasNext()) {
1032                    Expression filter = (Expression)sub.next();
1033                    if (ExpressionTool.callsFunction(filter, current)) {
1034                        usesCurrent = true;
1035                        break;
1036                    }
1037                }
1038                if (usesCurrent) {
1039                    Configuration config = getConfiguration();
1040                    RangeVariableDeclaration decl = new RangeVariableDeclaration();
1041                    decl.setNameCode(config.getNamePool().allocate("saxon", NamespaceConstant.SAXON, "current" + hashCode()));
1042                    decl.setVariableName("saxon:current");
1043                    decl.setRequiredType(SequenceType.SINGLE_ITEM);
1044                    LetExpression let = new LetExpression();
1045                    let.setSequence(new ContextItemExpression());
1046                    let.setVariableDeclaration(decl);
1047                    let.setAction(EmptySequence.getInstance());
1048                    PromotionOffer offer = new PromotionOffer(config.getOptimizer());
1049                    offer.action = PromotionOffer.REPLACE_CURRENT;
1050                    offer.containingExpression = let;
1051                    ((LocationPathPattern)pattern).resolveCurrent(let, offer);
1052                    allocateSlots(let);
1053                    decl.fixupReferences(let);
1054                }
1055            }
1056            return pattern;
1057        } catch (DynamicError err) {
1058            // we can't report a dynamic error such as divide by zero unless the pattern
1059
// is actually executed. We don't have an error pattern available, so we
1060
// construct one
1061
LocationPathPattern errpat = new LocationPathPattern();
1062            errpat.addFilter(new ErrorExpression(err));
1063            return errpat;
1064        } catch (XPathException err) {
1065            StaticError e2 = new StaticError("Error in " + name + " pattern", err);
1066            e2.setLocator(err.getLocator());
1067            e2.setErrorCode(err.getErrorCodeLocalPart());
1068            throw e2;
1069        }
1070    }
1071
1072    /**
1073     * Fix up references from XPath expressions. Overridden for function declarations
1074     * and variable declarations
1075     */

1076
1077    public void fixupReferences() throws XPathException {
1078        AxisIterator kids = iterateAxis(Axis.CHILD);
1079        while (true) {
1080            NodeInfo child = (NodeInfo)kids.next();
1081            if (child == null) {
1082                return;
1083            }
1084            if (child instanceof StyleElement) {
1085                ((StyleElement)child).fixupReferences();
1086            }
1087        }
1088    }
1089
1090    /**
1091     * Get the SlotManager for the containing Procedure definition
1092     *
1093     * @return the SlotManager associated with the containing Function, Template, etc,
1094     * or null if there is no such containing Function, Template etc.
1095     */

1096
1097    public SlotManager getContainingSlotManager() {
1098        NodeInfo node = this;
1099        while (true) {
1100            NodeInfo next = node.getParent();
1101            if (next instanceof XSLStylesheet) {
1102                if (node instanceof StylesheetProcedure) {
1103                    return ((StylesheetProcedure)node).getSlotManager();
1104                } else {
1105                    return null;
1106                }
1107            }
1108            node = next;
1109        }
1110    }
1111
1112
1113    /**
1114     * Recursive walk through the stylesheet to validate all nodes
1115     */

1116
1117    public void validateSubtree() throws XPathException {
1118        if (validationError != null) {
1119            if (reportingCircumstances == REPORT_ALWAYS) {
1120                compileError(validationError);
1121            } else if (reportingCircumstances == REPORT_UNLESS_FORWARDS_COMPATIBLE
1122                    && !forwardsCompatibleModeIsEnabled()) {
1123                compileError(validationError);
1124            }
1125        }
1126        try {
1127            validate();
1128        } catch (XPathException err) {
1129            if (forwardsCompatibleModeIsEnabled()) {
1130                setValidationError(err, REPORT_IF_INSTANTIATED);
1131            } else {
1132                compileError(err);
1133            }
1134        }
1135
1136        validateChildren();
1137        postValidate();
1138    }
1139
1140    /**
1141     * Validate the children of this node, recursively. Overridden for top-level
1142     * data elements.
1143     */

1144
1145    protected void validateChildren() throws XPathException {
1146        boolean containsInstructions = mayContainSequenceConstructor();
1147        AxisIterator kids = iterateAxis(Axis.CHILD);
1148        StyleElement lastChild = null;
1149        while (true) {
1150            NodeInfo child = (NodeInfo)kids.next();
1151            if (child == null) {
1152                break;
1153            }
1154            if (child instanceof StyleElement) {
1155                if (containsInstructions && !((StyleElement)child).isInstruction()
1156                        && !isPermittedChild((StyleElement)child)) {
1157                    ((StyleElement)child).compileError(
1158                            "An " + getDisplayName() + " element must not contain an " +
1159                            child.getDisplayName() + " element", "XTSE0010");
1160                }
1161                ((StyleElement)child).validateSubtree();
1162                lastChild = (StyleElement)child;
1163            }
1164        }
1165        if (lastChild instanceof XSLVariable &&
1166                !(this instanceof XSLStylesheet)) {
1167            lastChild.compileWarning(
1168                    "A variable with no following sibling instructions has no effect",
1169                    SaxonErrorCode.SXWN9001);
1170        }
1171    }
1172
1173    /**
1174     * Specify that certain children are permitted for this element
1175     */

1176
1177    protected boolean isPermittedChild(StyleElement child) {
1178        return false;
1179    }
1180
1181    /**
1182     * Get the principal XSLStylesheet node. This gets the principal style sheet, i.e. the
1183     * one originally loaded, that forms the root of the import/include tree
1184     */

1185
1186    protected XSLStylesheet getPrincipalStylesheet() {
1187        XSLStylesheet sheet = getContainingStylesheet();
1188        while (true) {
1189            XSLStylesheet next = sheet.getImporter();
1190            if (next == null) {
1191                return sheet;
1192            }
1193            sheet = next;
1194        }
1195    }
1196
1197    /**
1198     * Get the PreparedStylesheet object.
1199     *
1200     * @return the PreparedStylesheet to which this stylesheet element belongs
1201     */

1202
1203    public PreparedStylesheet getPreparedStylesheet() {
1204        return getPrincipalStylesheet().getPreparedStylesheet();
1205    }
1206
1207    /**
1208     * Check that the stylesheet element is within a sequence constructor
1209     *
1210     * @throws XPathException
1211     * if not within a sequence constructor
1212     */

1213
1214    public void checkWithinTemplate() throws XPathException {
1215// Parent elements now check their children, not the other way around
1216
// StyleElement parent = (StyleElement)getParent();
1217
// if (!parent.mayContainSequenceConstructor()) {
1218
// compileError("Element must be used only within a sequence constructor", "XT0010");
1219
// }
1220
}
1221
1222    /**
1223     * Check that among the children of this element, any xsl:sort elements precede any other elements
1224     *
1225     * @param sortRequired true if there must be at least one xsl:sort element
1226     * @throws XPathException
1227     * if invalid
1228     */

1229
1230    protected void checkSortComesFirst(boolean sortRequired) throws XPathException {
1231        AxisIterator kids = iterateAxis(Axis.CHILD);
1232        boolean sortFound = false;
1233        boolean nonSortFound = false;
1234        while (true) {
1235            NodeInfo child = (NodeInfo)kids.next();
1236            if (child == null) {
1237                break;
1238            }
1239            if (child instanceof XSLSort) {
1240                if (nonSortFound) {
1241                    ((XSLSort)child).compileError("Within " + getDisplayName() +
1242                            ", xsl:sort elements must come before other instructions", "XTSE0010");
1243                }
1244                sortFound = true;
1245            } else if (child.getNodeKind() == Type.TEXT) {
1246                // with xml:space=preserve, white space nodes may still be there
1247
if (!Whitespace.isWhite(child.getStringValueCS())) {
1248                    nonSortFound = true;
1249                }
1250            } else {
1251                nonSortFound = true;
1252            }
1253        }
1254        if (sortRequired && !sortFound) {
1255            compileError(getDisplayName() + " must have at least one xsl:sort child", "XTSE0010");
1256        }
1257    }
1258
1259    /**
1260     * Convenience method to check that the stylesheet element is at the top level
1261     *
1262     * @throws XPathException
1263     * if not at top level
1264     */

1265
1266    public void checkTopLevel(String JavaDoc errorCode) throws XPathException {
1267        if (errorCode == null) {
1268            errorCode = "XTSE0010";
1269        }
1270        if (!(getParent() instanceof XSLStylesheet)) {
1271            compileError("Element must be used only at top level of stylesheet", errorCode);
1272        }
1273    }
1274
1275    /**
1276     * Convenience method to check that the stylesheet element is empty
1277     *
1278     * @throws XPathException
1279     * if it is not empty
1280     */

1281
1282    public void checkEmpty() throws XPathException {
1283        if (hasChildNodes()) {
1284            compileError("Element must be empty", "XTSE0260");
1285        }
1286    }
1287
1288    /**
1289     * Convenience method to report the absence of a mandatory attribute
1290     *
1291     * @throws XPathException
1292     * if the attribute is missing
1293     */

1294
1295    public void reportAbsence(String JavaDoc attribute)
1296            throws XPathException {
1297        compileError("Element must have a \"" + attribute + "\" attribute", "XTSE0010");
1298    }
1299
1300
1301    /**
1302     * Compile the instruction on the stylesheet tree into an executable instruction
1303     * for use at run-time.
1304     *
1305     * @return either a ComputedExpression, or null. The value null is returned when compiling an instruction
1306     * that returns a no-op, or when compiling a top-level object such as an xsl:template that compiles
1307     * into something other than an instruction.
1308     */

1309
1310    public abstract Expression compile(Executable exec) throws XPathException;
1311
1312    /**
1313     * Compile the children of this instruction on the stylesheet tree, adding the
1314     * subordinate instructions to the parent instruction on the execution tree.
1315     *
1316     * @return the array of children
1317     */

1318
1319    public Expression compileSequenceConstructor(Executable exec, AxisIterator iter, boolean includeParams)
1320            throws XPathException {
1321
1322        int lineNumber = getLineNumber();
1323        NodeInfo node = (NodeInfo)iter.next();
1324        if (node == null) {
1325            return null;
1326        }
1327        if (node instanceof StyleElement) {
1328            lineNumber = node.getLineNumber(); // this is to get a line number for the next text node
1329
}
1330        if (node.getNodeKind() == Type.TEXT) {
1331            // handle literal text nodes by generating an xsl:value-of instruction
1332
ValueOf text = new ValueOf(StringValue.makeStringValue(node.getStringValueCS()), false, false);
1333            text.setLocationId(allocateLocationId(getSystemId(), lineNumber));
1334            Expression tail = compileSequenceConstructor(exec, iter, includeParams);
1335            if (tail == null) {
1336                return text;
1337            } else {
1338                Block e = Block.makeBlock(text, tail);
1339                e.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
1340                return e;
1341            }
1342
1343        } else if (node instanceof XSLVariable) {
1344            Expression var = ((XSLVariable)node).compileLocalVariable(exec);
1345            if (var == null) {
1346                // this can happen if the variable declaration is redundant
1347
return compileSequenceConstructor(exec, iter, includeParams);
1348            } else {
1349                LocalVariable lv = (LocalVariable)var;
1350                Expression tail = compileSequenceConstructor(exec, iter, includeParams);
1351                if (tail == null) {
1352                    // this doesn't happen, because if there are no instructions following
1353
// a variable, we'll have taken the var==null path above
1354
return null;
1355                } else {
1356                    LetExpression let = new LetExpression();
1357                    RangeVariableDeclaration rvar = new RangeVariableDeclaration();
1358                    rvar.setRequiredType(lv.getRequiredType());
1359                    rvar.setNameCode(lv.getNameCode());
1360                    rvar.setVariableName(lv.getVariableName());
1361                    rvar.setReferenceList(((XSLVariable)node).getReferenceList());
1362                    let.setVariableDeclaration(rvar);
1363                    let.setSequence(lv.getSelectExpression());
1364                    //let.setSlotNumber(lv.getSlotNumber());
1365
let.setAction(tail);
1366                    ((XSLVariable)node).fixupBinding(let);
1367                    let.setLocationId(allocateLocationId(node.getSystemId(), node.getLineNumber()));
1368                    if (getConfiguration().getTraceListener() != null) {
1369                        TraceExpression t = new TraceExpression(let);
1370                        t.setConstructType(Location.LET_EXPRESSION);
1371                        t.setObjectNameCode(lv.getNameCode());
1372                        t.setSystemId(node.getSystemId());
1373                        t.setLineNumber(node.getLineNumber());
1374                        return t;
1375                    }
1376                    return let;
1377                }
1378            }
1379
1380
1381        } else if (node instanceof StyleElement) {
1382            StyleElement snode = (StyleElement)node;
1383            if (snode.validationError != null) {
1384                return fallbackProcessing(exec, snode);
1385
1386            } else {
1387                Expression child = snode.compile(exec);
1388                if (child instanceof ComputedExpression) {
1389                    ComputedExpression childi = (ComputedExpression)child;
1390                    childi.setLocationId(allocateLocationId(getSystemId(), snode.getLineNumber()));
1391                }
1392                if (child != null) {
1393                    if (includeParams || !(node instanceof XSLParam)) {
1394                        if (getConfiguration().getTraceListener() != null) {
1395                            TraceWrapper trace = makeTraceInstruction(snode, child);
1396                            child = trace;
1397                        }
1398                    }
1399                }
1400                Expression tail = compileSequenceConstructor(exec, iter, includeParams);
1401                if (tail == null) {
1402                    return child;
1403                } else if (child == null) {
1404                    return tail;
1405                } else {
1406                    //AppendExpression e = new AppendExpression(child, Token.COMMA, tail);
1407
Block e = Block.makeBlock(child, tail);
1408                    e.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
1409                    return e;
1410                }
1411            }
1412        }
1413        return null;
1414    }
1415
1416    /**
1417     * Create a trace instruction to wrap a real instruction
1418     */

1419
1420    protected static TraceWrapper makeTraceInstruction(StyleElement source, Expression child) {
1421        if (child instanceof TraceWrapper) {
1422            return (TraceWrapper)child;
1423            // this can happen, for example, after optimizing a compile-time xsl:if
1424
}
1425
1426        TraceWrapper trace = new TraceInstruction(child, source);
1427        trace.setLocationId(source.allocateLocationId(source.getSystemId(), source.getLineNumber()));
1428        return trace;
1429    }
1430
1431    /**
1432     * Perform fallback processing. Generate fallback code for an extension
1433     * instruction that is not recognized by the implementation.
1434     *
1435     * @param instruction The unknown extension instruction
1436     */

1437
1438    protected Expression fallbackProcessing(Executable exec, StyleElement instruction)
1439            throws XPathException {
1440        // process any xsl:fallback children; if there are none,
1441
// generate code to report the original failure reason
1442
Expression fallback = null;
1443        AxisIterator kids = instruction.iterateAxis(Axis.CHILD);
1444        while (true) {
1445            NodeInfo child = (NodeInfo)kids.next();
1446            if (child == null) {
1447                break;
1448            }
1449            if (child instanceof XSLFallback) {
1450                //fallback.setLocationId(allocateLocationId(getSystemId(), child.getLineNumber()));
1451
//((XSLFallback)child).compileChildren(exec, fallback, true);
1452
Expression b = ((XSLFallback)child).compileSequenceConstructor(exec, child.iterateAxis(Axis.CHILD), true);
1453                if (b == null) {
1454                    b = EmptySequence.getInstance();
1455                }
1456                if (fallback == null) {
1457                    fallback = b;
1458                } else {
1459                    //fallback = new AppendExpression(fallback, Token.COMMA, b);
1460
fallback = Block.makeBlock(fallback, b);
1461                }
1462            }
1463        }
1464        if (fallback != null) {
1465            return fallback;
1466        } else {
1467            DeferredError deferred = new DeferredError(instruction.getNameCode(), instruction.validationError);
1468            deferred.setLocationId(allocateLocationId(getSystemId(), getLineNumber()));
1469            deferred.setParentExpression(this);
1470            instruction.validationError.setLocator(deferred);
1471            return deferred;
1472        }
1473
1474    }
1475
1476    /**
1477     * Allocate a location identifier
1478     */

1479
1480    public int allocateLocationId(String JavaDoc systemId, int lineNumber) {
1481        return getStaticContext().getLocationMap().allocateLocationId(systemId, lineNumber);
1482    }
1483
1484    /**
1485     * Construct sort keys for a SortedIterator
1486     *
1487     * @return an array of SortKeyDefinition objects if there are any sort keys;
1488     * or null if there are none.
1489     */

1490
1491    protected SortKeyDefinition[] makeSortKeys() {
1492        // handle sort keys if any
1493

1494        int numberOfSortKeys = 0;
1495        AxisIterator kids = iterateAxis(Axis.CHILD);
1496        while (true) {
1497            Item child = kids.next();
1498            if (child == null) {
1499                break;
1500            }
1501            if (child instanceof XSLSort) {
1502                numberOfSortKeys++;
1503            }
1504        }
1505
1506        if (numberOfSortKeys > 0) {
1507            SortKeyDefinition[] keys = new SortKeyDefinition[numberOfSortKeys];
1508            kids = iterateAxis(Axis.CHILD);
1509            int k = 0;
1510            while (true) {
1511                NodeInfo child = (NodeInfo)kids.next();
1512                if (child == null) {
1513                    break;
1514                }
1515                if (child instanceof XSLSort) {
1516                    keys[k++] = ((XSLSort)child).getSortKeyDefinition();
1517                }
1518            }
1519            return keys;
1520
1521        } else {
1522            return null;
1523        }
1524    }
1525
1526    /**
1527     * Get the list of attribute-sets associated with this element.
1528     * This is used for xsl:element, xsl:copy, xsl:attribute-set, and on literal
1529     * result elements
1530     *
1531     * @param use the original value of the [xsl:]use-attribute-sets attribute
1532     * @param list an empty list to hold the list of XSLAttributeSet elements in the stylesheet tree.
1533     * Or null, if these are not required.
1534     * @return an array of AttributeList instructions representing the compiled attribute sets
1535     */

1536
1537    protected AttributeSet[] getAttributeSets(String JavaDoc use, List JavaDoc list)
1538            throws XPathException {
1539
1540        if (list == null) {
1541            list = new ArrayList JavaDoc(4);
1542        }
1543
1544        XSLStylesheet stylesheet = getPrincipalStylesheet();
1545        List JavaDoc toplevel = stylesheet.getTopLevel();
1546
1547        StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(use);
1548        while (st.hasMoreTokens()) {
1549            String JavaDoc asetname = st.nextToken();
1550            int fprint;
1551            try {
1552                fprint = makeNameCode(asetname) & 0xfffff;
1553            } catch (NamespaceException err) {
1554                compileError(err.getMessage(), "XTSE0710");
1555                fprint = -1;
1556            } catch (XPathException err) {
1557                compileError(err.getMessage(), "XTSE0710");
1558                fprint = -1;
1559            }
1560            boolean found = false;
1561
1562            // search for the named attribute set, using all of them if there are several with the
1563
// same name
1564

1565            for (int i = 0; i < toplevel.size(); i++) {
1566                if (toplevel.get(i) instanceof XSLAttributeSet) {
1567                    XSLAttributeSet t = (XSLAttributeSet)toplevel.get(i);
1568                    if (t.getAttributeSetFingerprint() == fprint) {
1569                        list.add(t);
1570                        found = true;
1571                    }
1572                }
1573            }
1574
1575            if (!found) {
1576                compileError("No attribute-set exists named " + asetname, "XTSE0710");
1577            }
1578        }
1579
1580        AttributeSet[] array = new AttributeSet[list.size()];
1581        for (int i = 0; i < list.size(); i++) {
1582            XSLAttributeSet aset = (XSLAttributeSet)list.get(i);
1583            aset.incrementReferenceCount();
1584            array[i] = aset.getInstruction();
1585        }
1586        return array;
1587    }
1588
1589    /**
1590     * Get the list of xsl:with-param elements for a calling element (apply-templates,
1591     * call-template, apply-imports, next-match). This method can be used to get either
1592     * the tunnel parameters, or the non-tunnel parameters.
1593     *
1594     * @param tunnel true if the tunnel="yes" parameters are wanted, false to get
1595     * @param caller
1596     */

1597
1598    protected WithParam[] getWithParamInstructions(Executable exec, boolean tunnel, Instruction caller)
1599    throws XPathException {
1600        int count = 0;
1601        AxisIterator kids = iterateAxis(Axis.CHILD);
1602        while (true) {
1603            NodeInfo child = (NodeInfo)kids.next();
1604            if (child == null) {
1605                break;
1606            }
1607            if (child instanceof XSLWithParam) {
1608                XSLWithParam wp = (XSLWithParam)child;
1609                if (wp.isTunnelParam() == tunnel) {
1610                    count++;
1611                }
1612            }
1613        }
1614        WithParam[] array = new WithParam[count];
1615        count = 0;
1616        kids = iterateAxis(Axis.CHILD);
1617        while (true) {
1618            NodeInfo child = (NodeInfo)kids.next();
1619            if (child == null) {
1620                return array;
1621            }
1622            if (child instanceof XSLWithParam) {
1623                XSLWithParam wp = (XSLWithParam)child;
1624                if (wp.isTunnelParam() == tunnel) {
1625                    WithParam p = (WithParam)wp.compile(exec);
1626                    p.setParentExpression(caller);
1627                    array[count++] = p;
1628                }
1629
1630            }
1631        }
1632    }
1633
1634    /**
1635     * Report an invalid value for an optional attribute.
1636     * This first tests whether the instruction is in forwards-compatible
1637     * mode; if so, the invalid value is reported with a warning and ignored. The method then returns null,
1638     * allowing code of the form
1639     * <p>
1640     * <code>problemAtt = reportInvalidAttribute(message)
1641     *
1642     * If not in forwards compatible mode, a static error is thrown.
1643     */

1644
1645    public String JavaDoc reportInvalidAttribute(String JavaDoc message, String JavaDoc errorCode) throws XPathException {
1646        // TODO: this is the beginning of an attempt to implement the rule that in fc mode, invalid values
1647
// of optional attributes are simply ignored. This has not been followed through, and is being discussed
1648
// by the Working Group.
1649
if (forwardsCompatibleModeIsEnabled()) {
1650            String JavaDoc m = message + " (attribute value ignored because in forwards-compatible mode)";
1651            compileWarning(m, errorCode);
1652        } else {
1653            compileError(message, errorCode);
1654        }
1655        return null;
1656    }
1657
1658    /**
1659     * Construct an exception with diagnostic information
1660     */

1661
1662    protected void compileError(TransformerException JavaDoc error)
1663            throws XPathException {
1664
1665        // Set the location of the error if there is not current location information,
1666
// or if the current location information is local to the XPath expression
1667
if (error.getLocator() == null || error.getLocator() instanceof ExpressionLocation) {
1668            error.setLocator(this);
1669        }
1670        PreparedStylesheet pss = getPreparedStylesheet();
1671        try {
1672            if (pss == null) {
1673                // it is null before the stylesheet has been fully built
1674
throw error;
1675            } else {
1676                pss.reportError(error);
1677            }
1678        } catch (TransformerException JavaDoc err2) {
1679            if (err2.getLocator() == null) {
1680                err2.setLocator(this);
1681            }
1682            throw StaticError.makeStaticError(err2);
1683        }
1684    }
1685
1686    protected void compileError(String JavaDoc message)
1687            throws XPathException {
1688        StaticError tce = new StaticError(message);
1689        tce.setLocator(this);
1690        compileError(tce);
1691    }
1692
1693    /**
1694     * Compile time error, specifying an error code
1695     *
1696     * @param message the error message
1697     * @param errorCode the error code. May be null if not known or not defined
1698     * @throws XPathException
1699     *
1700     */

1701
1702    protected void compileError(String JavaDoc message, String JavaDoc errorCode) throws XPathException {
1703        StaticError tce = new StaticError(message);
1704        tce.setErrorCode(errorCode);
1705        tce.setLocator(this);
1706        compileError(tce);
1707    }
1708
1709    protected void undeclaredNamespaceError(String JavaDoc prefix, String JavaDoc errorCode) throws XPathException {
1710        if (errorCode==null) {
1711            errorCode = "XTSE0280";
1712        }
1713        compileError("Undeclared namespace prefix " + Err.wrap(prefix), errorCode);
1714    }
1715
1716    protected void compileWarning(String JavaDoc message, String JavaDoc errorCode)
1717            throws XPathException {
1718        StaticError tce = new StaticError(message);
1719        tce.setErrorCode(errorCode);
1720        tce.setLocator(this);
1721        PreparedStylesheet pss = getPreparedStylesheet();
1722        if (pss != null) {
1723            pss.reportWarning(tce);
1724        }
1725    }
1726
1727    /**
1728     * Construct an exception with diagnostic information
1729     */

1730
1731    protected void issueWarning(TransformerException JavaDoc error) {
1732        if (error.getLocator() == null) {
1733            error.setLocator(this);
1734        }
1735        PreparedStylesheet pss = getPreparedStylesheet();
1736        if (pss != null) {
1737            // it is null before the stylesheet has been fully built - ignore it
1738
pss.reportWarning(error);
1739        }
1740    }
1741
1742    protected void issueWarning(String JavaDoc message, SourceLocator JavaDoc locator) {
1743        TransformerConfigurationException JavaDoc tce =
1744                new TransformerConfigurationException JavaDoc(message);
1745        if (locator == null) {
1746            tce.setLocator(this);
1747        } else {
1748            tce.setLocator(locator);
1749        }
1750        issueWarning(tce);
1751    }
1752
1753    /**
1754     * Test whether this is a top-level element
1755     */

1756
1757    public boolean isTopLevel() {
1758        return (getParent() instanceof XSLStylesheet);
1759    }
1760
1761    /**
1762     * Bind a variable used in this element to the compiled form of the XSLVariable element in which it is
1763     * declared
1764     *
1765     * @param fingerprint The fingerprint of the name of the variable
1766     * @return the XSLVariableDeclaration (that is, an xsl:variable or xsl:param instruction) for the variable
1767     * @throws net.sf.saxon.trans.StaticError if the variable has not been declared
1768     */

1769
1770    public XSLVariableDeclaration bindVariable(int fingerprint) throws StaticError {
1771        XSLVariableDeclaration binding = getVariableBinding(fingerprint);
1772        if (binding == null) {
1773            StaticError err = new StaticError("Variable " + getTargetNamePool().getDisplayName(fingerprint) +
1774                    " has not been declared");
1775            err.setErrorCode("XPST0008");
1776            throw err;
1777        }
1778        return binding;
1779    }
1780
1781    /**
1782     * Bind a variable used in this element to the declaration in the stylesheet
1783     *
1784     * @param fprint The absolute name of the variable (prefixed by namespace URI)
1785     * @return the XSLVariableDeclaration, or null if it has not been declared
1786     */

1787
1788    private XSLVariableDeclaration getVariableBinding(int fprint) {
1789        NodeInfo curr = this;
1790        NodeInfo prev = this;
1791
1792        // first search for a local variable declaration
1793
if (!isTopLevel()) {
1794            AxisIterator preceding = curr.iterateAxis(Axis.PRECEDING_SIBLING);
1795            while (true) {
1796                curr = (NodeInfo)preceding.next();
1797                while (curr == null) {
1798                    curr = prev.getParent();
1799                    while (curr instanceof XSLFallback) {
1800                        // a local variable is not visible within a sibling xsl:fallback element
1801
curr = curr.getParent();
1802                    }
1803                    prev = curr;
1804                    if (curr.getParent() instanceof XSLStylesheet) {
1805                        break; // top level
1806
}
1807                    preceding = curr.iterateAxis(Axis.PRECEDING_SIBLING);
1808                    curr = (NodeInfo)preceding.next();
1809                }
1810                if (curr.getParent() instanceof XSLStylesheet) {
1811                    break;
1812                }
1813                if (curr instanceof XSLVariableDeclaration) {
1814                    XSLVariableDeclaration var = (XSLVariableDeclaration)curr;
1815                    if (var.getVariableFingerprint() == fprint) {
1816                        return var;
1817                    }
1818                }
1819            }
1820        }
1821
1822        // Now check for a global variable
1823
// we rely on the search following the order of decreasing import precedence.
1824

1825        XSLStylesheet root = getPrincipalStylesheet();
1826        XSLVariableDeclaration var = root.getGlobalVariable(fprint);
1827        return var;
1828    }
1829
1830    /**
1831     * List the variables that are in scope for this stylesheet element.
1832     * Designed for a debugger, not used by the processor.
1833     * @return two Enumeration of Strings, the global ones [0] and the local ones [1]
1834     */

1835
1836
1837
1838    /**
1839     * Get a FunctionCall declared using an xsl:function element in the stylesheet
1840     *
1841     * @param fingerprint the fingerprint of the name of the function
1842     * @param arity the number of arguments in the function call. The value -1
1843     * indicates that any arity will do (this is used to support the function-available() function).
1844     * @return the XSLFunction object representing the function declaration
1845     * in the stylesheet, or null if no such function is defined.
1846     */

1847
1848    public XSLFunction getStylesheetFunction(int fingerprint, int arity) {
1849
1850        // we rely on the search following the order of decreasing import precedence.
1851

1852        XSLStylesheet root = getPrincipalStylesheet();
1853        List JavaDoc toplevel = root.getTopLevel();
1854        for (int i = toplevel.size() - 1; i >= 0; i--) {
1855            Object JavaDoc child = toplevel.get(i);
1856            if (child instanceof XSLFunction &&
1857                    ((XSLFunction)child).getFunctionFingerprint() == fingerprint &&
1858                    (arity == -1 || ((XSLFunction)child).getNumberOfArguments() == arity)) {
1859                XSLFunction func = (XSLFunction)child;
1860                return func;
1861            }
1862        }
1863        return null;
1864    }
1865
1866    /**
1867     * Get the type of construct. This will be a constant in
1868     * class {@link Location}. This method is part of the {@link InstructionInfo} interface
1869     */

1870
1871    public int getConstructType() {
1872        return getFingerprint();
1873    }
1874
1875    /**
1876     * Get a name identifying the object of the expression, for example a function name, template name,
1877     * variable name, key name, element name, etc. This is used only where the name is known statically.
1878     * If there is no name, the value will be -1.
1879     */

1880
1881    public int getObjectNameCode() {
1882        return objectNameCode;
1883    }
1884
1885    /**
1886     * Get a fingerprint identifying the object of the expression, for example a function name, template name,
1887     * variable name, key name, element name, etc. This is used only where the name is known statically.
1888     * If there is no name, the value will be -1.
1889     */

1890
1891    public int getObjectFingerprint() {
1892        return (objectNameCode == -1 ? -1 : objectNameCode & 0xfffff);
1893    }
1894
1895    /**
1896     * Set the object name code
1897     */

1898
1899    public void setObjectNameCode(int nameCode) {
1900        objectNameCode = nameCode;
1901    }
1902
1903    /**
1904     * Get the namespace context of the instruction.
1905     */

1906
1907    public NamespaceResolver getNamespaceResolver() {
1908        return makeNamespaceContext();
1909    }
1910
1911    /**
1912     * Get the value of a particular property of the instruction. This is part of the
1913     * {@link InstructionInfo} interface for run-time tracing and debugging. The properties
1914     * available include all the attributes of the source instruction (named by the attribute name):
1915     * these are all provided as string values.
1916     *
1917     * @param name The name of the required property
1918     * @return The value of the requested property, or null if the property is not available
1919     */

1920
1921    public Object JavaDoc getProperty(String JavaDoc name) {
1922        return getAttributeValue(name);
1923    }
1924
1925    /**
1926     * Get an iterator over all the properties available. The values returned by the iterator
1927     * will be of type String, and each string can be supplied as input to the getProperty()
1928     * method to retrieve the value of the property.
1929     */

1930
1931    public Iterator JavaDoc getProperties() {
1932        NamePool pool = getNamePool();
1933        List JavaDoc list = new ArrayList JavaDoc(10);
1934        AxisIterator it = iterateAxis(Axis.ATTRIBUTE);
1935        while (true) {
1936            NodeInfo a = (NodeInfo)it.next();
1937            if (a == null) {
1938                break;
1939            }
1940            list.add(pool.getClarkName(a.getNameCode()));
1941        }
1942        return list.iterator();
1943    }
1944
1945    public String JavaDoc getSystemId(int locationId) {
1946        return getSystemId();
1947    }
1948
1949    public int getLineNumber(int locationId) {
1950        return getLineNumber();
1951    }
1952}
1953
1954//
1955
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1956
// you may not use this file except in compliance with the License. You may obtain a copy of the
1957
// License at http://www.mozilla.org/MPL/
1958
//
1959
// Software distributed under the License is distributed on an "AS IS" basis,
1960
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1961
// See the License for the specific language governing rights and limitations under the License.
1962
//
1963
// The Original Code is: all this file.
1964
//
1965
// The Initial Developer of the Original Code is Michael H. Kay.
1966
//
1967
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1968
//
1969
// Contributor(s):
1970
//
1971
Popular Tags