KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > event > TypeCheckingFilter


1 package net.sf.saxon.event;
2
3 import net.sf.saxon.expr.Token;
4 import net.sf.saxon.expr.RoleLocator;
5 import net.sf.saxon.expr.ExpressionLocation;
6 import net.sf.saxon.om.Item;
7 import net.sf.saxon.om.NamePool;
8 import net.sf.saxon.pattern.CombinedNodeTest;
9 import net.sf.saxon.pattern.ContentTypeTest;
10 import net.sf.saxon.pattern.NameTest;
11 import net.sf.saxon.pattern.NodeKindTest;
12 import net.sf.saxon.trans.XPathException;
13 import net.sf.saxon.trans.DynamicError;
14 import net.sf.saxon.type.ItemType;
15 import net.sf.saxon.type.Type;
16 import net.sf.saxon.value.Value;
17 import net.sf.saxon.value.Cardinality;
18
19 import java.util.HashSet JavaDoc;
20
21 /**
22  * A filter on the push pipeline that performs type checking, both of the item type and the
23  * cardinality.
24  * <p>
25  * Note that the TypeCheckingFilter cannot currently check document node tests of the form
26  * document-node(element(X,Y)), so it is not invoked in such cases. This isn't a big problem, because most
27  * instructions that return document nodes materialize them anyway.
28  */

29
30 public class TypeCheckingFilter extends ProxyReceiver {
31
32     private ItemType itemType;
33     private int cardinality;
34     private RoleLocator role;
35     private int count = 0;
36     private int level = 0;
37     private HashSet JavaDoc checkedElements = new HashSet JavaDoc(10);
38         // used to avoid repeated checking when a template creates large numbers of elements of the same type
39

40     public void setRequiredType(ItemType type, int cardinality, RoleLocator role) {
41         this.itemType = type;
42         this.cardinality = cardinality;
43         this.role = role;
44     }
45
46     /**
47      * Notify an attribute. Attributes are notified after the startElement event, and before any
48      * children. Namespaces and attributes may be intermingled.
49      *
50      * @param nameCode The name of the attribute, as held in the name pool
51      * @param typeCode The type of the attribute, as held in the name pool
52      * @param properties Bit significant value. The following bits are defined:
53      * <dd>DISABLE_ESCAPING</dd> <dt>Disable escaping for this attribute</dt>
54      * <dd>NO_SPECIAL_CHARACTERS</dd> <dt>Attribute value contains no special characters</dt>
55      * @throws IllegalStateException: attempt to output an attribute when there is no open element
56      * start tag
57      */

58
59     public void attribute(int nameCode, int typeCode, CharSequence JavaDoc value, int locationId, int properties) throws XPathException {
60         if (level == 0) {
61             if (++count == 2) {
62                 checkAllowsMany(locationId);
63             }
64             ItemType type = new CombinedNodeTest(
65                     new NameTest(Type.ATTRIBUTE, nameCode, getNamePool()),
66                     Token.INTERSECT,
67                     new ContentTypeTest(Type.ATTRIBUTE, getConfiguration().getSchemaType(typeCode), getConfiguration()));
68             checkItemType(type, locationId);
69         }
70         super.attribute(nameCode, typeCode, value, locationId, properties);
71     }
72
73     /**
74      * Character data
75      */

76
77     public void characters(CharSequence JavaDoc chars, int locationId, int properties) throws XPathException {
78         if (level == 0) {
79             if (++count == 2) {
80                 checkAllowsMany(locationId);
81             }
82             ItemType type = NodeKindTest.TEXT;
83             checkItemType(type, locationId);
84         }
85         super.characters(chars, locationId, properties);
86     }
87
88     /**
89      * Output a comment
90      */

91
92     public void comment(CharSequence JavaDoc chars, int locationId, int properties) throws XPathException {
93         if (level == 0) {
94             if (++count == 2) {
95                 checkAllowsMany(locationId);
96             }
97             ItemType type = NodeKindTest.COMMENT;
98             checkItemType(type, locationId);
99         }
100         super.comment(chars, locationId, properties); //To change body of overridden methods use File | Settings | File Templates.
101
}
102
103     /**
104      * Notify a namespace. Namespaces are notified <b>after</b> the startElement event, and before
105      * any children for the element. The namespaces that are reported are only required
106      * to include those that are different from the parent element; however, duplicates may be reported.
107      * A namespace must not conflict with any namespaces already used for element or attribute names.
108      *
109      * @param namespaceCode an integer: the top half is a prefix code, the bottom half a URI code.
110      * These may be translated into an actual prefix and URI using the name pool. A prefix code of
111      * zero represents the empty prefix (that is, the default namespace). A URI code of zero represents
112      * a URI of "", that is, a namespace undeclaration.
113      * @throws IllegalStateException: attempt to output a namespace when there is no open element
114      * start tag
115      */

116
117     public void namespace(int namespaceCode, int properties) throws XPathException {
118         if (level == 0) {
119             if (++count == 2) {
120                 checkAllowsMany(0);
121             }
122             ItemType type = NodeKindTest.NAMESPACE;
123             checkItemType(type, 0);
124         }
125         super.namespace(namespaceCode, properties); //To change body of overridden methods use File | Settings | File Templates.
126
}
127
128     /**
129      * Processing Instruction
130      */

131
132     public void processingInstruction(String JavaDoc target, CharSequence JavaDoc data, int locationId, int properties) throws XPathException {
133         if (level == 0) {
134             if (++count == 2) {
135                 checkAllowsMany(locationId);
136             }
137             ItemType type = NodeKindTest.PROCESSING_INSTRUCTION;
138             checkItemType(type, locationId);
139         }
140         super.processingInstruction(target, data, locationId, properties);
141     }
142
143     /**
144      * Start of a document node.
145      */

146
147     public void startDocument(int properties) throws XPathException {
148         if (level == 0) {
149             if (++count == 2) {
150                 checkAllowsMany(0);
151             }
152             ItemType type = NodeKindTest.DOCUMENT;
153             checkItemType(type, 0);
154         }
155         level++;
156         super.startDocument(properties);
157     }
158
159     /**
160      * Notify the start of an element
161      *
162      * @param nameCode integer code identifying the name of the element within the name pool.
163      * @param typeCode integer code identifying the element's type within the name pool.
164      * @param properties properties of the element node
165      */

166
167     public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException {
168         if (level == 0) {
169             if (++count == 1) {
170                 // don't bother with any caching on the first item, it will often be the only one
171
ItemType type = new CombinedNodeTest(
172                         new NameTest(Type.ELEMENT, nameCode, getNamePool()),
173                         Token.INTERSECT,
174                         new ContentTypeTest(Type.ELEMENT, getConfiguration().getSchemaType(typeCode), getConfiguration()));
175                 checkItemType(type, locationId);
176             } else {
177                 if (count == 2) {
178                     checkAllowsMany(locationId);
179                 }
180                 Long JavaDoc key = new Long JavaDoc(((long)(nameCode&NamePool.FP_MASK))<<32 | (long)(typeCode&NamePool.FP_MASK));
181                 if (!checkedElements.contains(key)) {
182                     ItemType type = new CombinedNodeTest(
183                             new NameTest(Type.ELEMENT, nameCode, getNamePool()),
184                             Token.INTERSECT,
185                             new ContentTypeTest(Type.ELEMENT, getConfiguration().getSchemaType(typeCode), getConfiguration()));
186                     checkItemType(type, locationId);
187                     checkedElements.add(key);
188                 }
189             }
190         }
191         level++;
192         super.startElement(nameCode, typeCode, locationId, properties);
193     }
194
195     /**
196      * Notify the end of a document node
197      */

198
199     public void endDocument() throws XPathException {
200         level--;
201         super.endDocument();
202     }
203
204     /**
205      * End of element
206      */

207
208     public void endElement() throws XPathException {
209         level--;
210         super.endElement();
211     }
212
213     /**
214      * End of event stream
215      */

216
217     public void close() throws XPathException {
218         if (count == 0 && !Cardinality.allowsZero(cardinality)) {
219             DynamicError err = new DynamicError(
220                         "An empty sequence is not allowed as the " +
221                         role.getMessage());
222             String JavaDoc errorCode = role.getErrorCode();
223             err.setErrorCode(errorCode);
224             if (!"XPDY0050".equals(errorCode)) {
225                 err.setIsTypeError(true);
226             }
227             throw err;
228         }
229         // don't pass on the close event
230
}
231
232     /**
233      * Output an item (atomic value or node) to the sequence
234      */

235
236     public void append(Item item, int locationId, int copyNamespaces) throws XPathException {
237         if (level == 0) {
238             if (++count == 2) {
239                 checkAllowsMany(locationId);
240             }
241             checkItemType(Value.asValue(item).getItemType(), locationId);
242         }
243         if (nextReceiver instanceof SequenceReceiver) {
244             ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces);
245         } else {
246             super.append(item, locationId, copyNamespaces);
247         }
248     }
249
250     private void checkItemType(ItemType type, int locationId) throws DynamicError {
251         if (!Type.isSubType(type, itemType)) {
252             String JavaDoc message = role.composeErrorMessage(itemType, type, getNamePool());
253             String JavaDoc errorCode = role.getErrorCode();
254             DynamicError err = new DynamicError(message);
255             err.setErrorCode(errorCode);
256             if (!"XPDY0050".equals(errorCode)) {
257                 err.setIsTypeError(true);
258             }
259             err.setLocator(ExpressionLocation.getSourceLocator(locationId,
260                     getPipelineConfiguration().getLocationProvider()));
261             throw err;
262         }
263     }
264
265     private void checkAllowsMany(int locationId) throws XPathException {
266         if (!Cardinality.allowsMany(cardinality)) {
267             DynamicError err = new DynamicError(
268                         "A sequence of more than one item is not allowed as the " +
269                         role.getMessage());
270             String JavaDoc errorCode = role.getErrorCode();
271             err.setErrorCode(errorCode);
272             if (!"XPDY0050".equals(errorCode)) {
273                 err.setIsTypeError(true);
274             }
275             err.setLocator(ExpressionLocation.getSourceLocator(locationId,
276                     getPipelineConfiguration().getLocationProvider()));
277             throw err;
278         }
279     }
280
281
282
283 }
284
285 //
286
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
287
// you may not use this file except in compliance with the License. You may obtain a copy of the
288
// License at http://www.mozilla.org/MPL/
289
//
290
// Software distributed under the License is distributed on an "AS IS" basis,
291
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
292
// See the License for the specific language governing rights and limitations under the License.
293
//
294
// The Original Code is: all this file.
295
//
296
// The Initial Developer of the Original Code is Michael H. Kay.
297
//
298
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
299
//
300
// Contributor(s): none.
301
//
302
Popular Tags