KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > instruct > FixedAttribute


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.Controller;
3 import net.sf.saxon.Err;
4 import net.sf.saxon.event.ReceiverOptions;
5 import net.sf.saxon.event.SequenceReceiver;
6 import net.sf.saxon.expr.*;
7 import net.sf.saxon.om.Item;
8 import net.sf.saxon.om.NamePool;
9 import net.sf.saxon.om.Orphan;
10 import net.sf.saxon.om.Validation;
11 import net.sf.saxon.pattern.NodeKindTest;
12 import net.sf.saxon.style.StandardNames;
13 import net.sf.saxon.trace.InstructionInfo;
14 import net.sf.saxon.trace.Location;
15 import net.sf.saxon.trans.DynamicError;
16 import net.sf.saxon.trans.StaticError;
17 import net.sf.saxon.trans.XPathException;
18 import net.sf.saxon.type.*;
19 import net.sf.saxon.value.AtomicValue;
20 import net.sf.saxon.value.StringValue;
21
22 import java.io.PrintStream JavaDoc;
23
24 /**
25  * An instruction derived from an xsl:attribute element in stylesheet, or from
26  * an attribute constructor in XQuery. This version deals only with attributes
27  * whose name is known at compile time. It is also used for attributes of
28  * literal result elements. The value of the attribute is in general computed
29  * at run-time.
30 */

31
32 public final class FixedAttribute extends SimpleNodeConstructor {
33
34     private int nameCode;
35     private SimpleType schemaType;
36     private int annotation;
37     private int options;
38     private int validationAction;
39
40     /**
41     * Construct an Attribute instruction
42     * @param nameCode Represents the attribute name
43     * @param annotation Integer code identifying the type named in the <code>type</code> attribute
44     * of the instruction - zero if the attribute was not present
45     */

46
47     public FixedAttribute ( int nameCode,
48                              int validationAction,
49                              SimpleType schemaType,
50                              int annotation ) {
51         this.nameCode = nameCode;
52         this.schemaType = schemaType;
53         if (annotation == -1) {
54             this.annotation = StandardNames.XDT_UNTYPED_ATOMIC;
55         } else {
56             this.annotation = annotation;
57         }
58         this.validationAction = validationAction;
59         this.options = 0;
60     }
61
62     /**
63      * Get the name of this instruction (return 'xsl:attribute')
64      */

65
66     public int getInstructionNameCode() {
67         return StandardNames.XSL_ATTRIBUTE;
68     }
69     /**
70      * Indicate that two attributes with the same name are not acceptable.
71      * (This option is set in XQuery, but not in XSLT)
72      */

73
74     public void setRejectDuplicates() {
75         this.options |= ReceiverOptions.REJECT_DUPLICATES;
76     }
77
78     /**
79      * Indicate that the attribute value contains no special characters that
80      * might need escaping
81      */

82
83     public void setNoSpecialChars() {
84         this.options |= ReceiverOptions.NO_SPECIAL_CHARS;
85     }
86
87     /**
88      * Set the expression defining the value of the attribute. If this is a constant, and if
89      * validation against a schema type was requested, the validation is done immediately.
90      * @param select The expression defining the content of the attribute
91      * @throws StaticError if the expression is a constant, and validation is requested, and
92      * the constant doesn't match the required type.
93      */

94     public void setSelect(Expression select) throws StaticError {
95         super.setSelect(select);
96
97         // Attempt early validation if possible
98
if (select instanceof AtomicValue && schemaType != null && !schemaType.isNamespaceSensitive()) {
99             CharSequence JavaDoc value = ((AtomicValue)select).getStringValueCS();
100             XPathException err = schemaType.validateContent(
101                     value, DummyNamespaceResolver.getInstance(), getExecutable().getConfiguration());
102             if (err != null) {
103                 throw new StaticError("Attribute value " + Err.wrap(value, Err.VALUE) +
104                                                " does not the match the required type " +
105                                                schemaType.getDescription() + ". " +
106                                                err.getMessage());
107             }
108         }
109
110         // If value is fixed, test whether there are any special characters that might need to be
111
// escaped when the time comes for serialization
112
if (select instanceof StringValue) {
113             boolean special = false;
114             CharSequence JavaDoc val = ((StringValue)select).getStringValueCS();
115             for (int k=0; k<val.length(); k++) {
116                 char c = val.charAt(k);
117                 if ((int)c<33 || (int)c>126 ||
118                          c=='<' || c=='>' || c=='&' || c=='\"') {
119                     special = true;
120                     break;
121                  }
122             }
123             if (!special) {
124                 this.options |= ReceiverOptions.NO_SPECIAL_CHARS;
125             }
126         }
127     }
128
129     public InstructionInfo getInstructionInfo() {
130         InstructionDetails details = (InstructionDetails)super.getInstructionInfo();
131         details.setConstructType(Location.LITERAL_RESULT_ATTRIBUTE);
132         details.setObjectNameCode(nameCode);
133         return details;
134     }
135
136     public ItemType getItemType() {
137         return NodeKindTest.ATTRIBUTE;
138     }
139
140     public int getCardinality() {
141         return StaticProperty.EXACTLY_ONE;
142     }
143
144
145     public void localTypeCheck(StaticContext env, ItemType contextItemType) {
146     }
147
148     protected int evaluateNameCode(XPathContext context) {
149         return nameCode;
150     }
151
152     /**
153      * Check that any elements and attributes constructed or returned by this expression are acceptable
154      * in the content model of a given complex type. It's always OK to say yes, since the check will be
155      * repeated at run-time. The process of checking element and attribute constructors against the content
156      * model of a complex type also registers the type of content expected of those constructors, so the
157      * static validation can continue recursively.
158      */

159
160     public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException {
161         if (parentType instanceof SimpleType) {
162              StaticError err = new StaticError("Attribute " + env.getNamePool().getDisplayName(nameCode) +
163                     " is not permitted in the content model of the simple type " + parentType.getDescription());
164             err.setIsTypeError(true);
165             err.setLocator(this);
166             throw err;
167         }
168         SchemaType type;
169         try {
170             type = ((ComplexType)parentType).getAttributeUseType(nameCode & 0xfffff);
171         } catch (SchemaException e) {
172             throw new StaticError(e);
173         }
174         if (type == null) {
175             StaticError err = new StaticError("Attribute " + env.getNamePool().getDisplayName(nameCode) +
176                     " is not permitted in the content model of the complex type " + parentType.getDescription());
177             // TODO: it might be allowed in a type derived by extension (see corresponding code in FixedElement)
178
err.setIsTypeError(true);
179             err.setLocator(this);
180             throw err;
181         }
182         if (type instanceof AnyType) {
183             return;
184         }
185
186         try {
187             select.checkPermittedContents(type, env, true);
188             // TODO: does this allow for the fact that the content will be atomized?
189
} catch (XPathException e) {
190             if (e.getLocator() == null || e.getLocator() == e) {
191                 e.setLocator(this);
192             }
193             throw e;
194         }
195     }
196
197     /**
198     * Process this instruction
199     * @param context the dynamic context of the transformation
200     * @return a TailCall to be executed by the caller, always null for this instruction
201     */

202
203     public TailCall processLeavingTail(XPathContext context) throws XPathException
204     {
205         Controller controller = context.getController();
206         SequenceReceiver out = context.getReceiver();
207         int opt = options;
208         int ann = annotation;
209
210         // we may need to change the namespace prefix if the one we chose is
211
// already in use with a different namespace URI: this is done behind the scenes
212
// by the Outputter
213

214         String JavaDoc value = expandChildren(context).toString();
215         if (schemaType != null) {
216             // test whether the value actually conforms to the given type
217
XPathException err = schemaType.validateContent(value, DummyNamespaceResolver.getInstance(), context);
218             if (err != null) {
219                 ValidationException verr = new ValidationException(
220                         "Attribute value " + Err.wrap(value, Err.VALUE) +
221                         " does not the match the required type " +
222                         schemaType.getDescription() + ". " + err.getMessage());
223                 verr.setLocator(this);
224                 throw verr;
225             }
226         } else if (validationAction==Validation.STRICT ||
227                 validationAction==Validation.LAX) {
228             try {
229                 ann = controller.getConfiguration().validateAttribute(
230                         nameCode, value, validationAction);
231             } catch (ValidationException e) {
232                 DynamicError err = DynamicError.makeDynamicError(e);
233                 err.setErrorCode(e.getErrorCodeLocalPart());
234                 err.setXPathContext(context);
235                 err.setLocator(this);
236                 err.setIsTypeError(true);
237                 throw err;
238             }
239         }
240         try {
241             out.attribute(nameCode, ann, value, locationId, opt);
242         } catch (XPathException err) {
243             throw dynamicError(this, err, context);
244         }
245
246         return null;
247     }
248
249     public Item evaluateItem(XPathContext context) throws XPathException {
250         Orphan o = (Orphan)super.evaluateItem(context);
251         if (schemaType != null) {
252             XPathException err = schemaType.validateContent(
253                     o.getStringValueCS(), DummyNamespaceResolver.getInstance(), context);
254             if (err != null) {
255                 throw new ValidationException("Attribute value " + Err.wrap(o.getStringValueCS(), Err.VALUE) +
256                                            " does not the match the required type " +
257                                            schemaType.getDescription() + ". " +
258                                            err.getMessage());
259             }
260             o.setTypeAnnotation(schemaType.getFingerprint());
261             if (schemaType.isNamespaceSensitive()) {
262                 throw new DynamicError("Cannot validate a parentless attribute whose content is namespace-sensitive");
263             }
264         } else if (validationAction==Validation.STRICT ||
265                 validationAction==Validation.LAX) {
266             try {
267                 int ann = context.getController().getConfiguration().validateAttribute(
268                         nameCode, o.getStringValueCS(), validationAction);
269                 o.setTypeAnnotation(ann);
270             } catch (ValidationException e) {
271                 DynamicError err = DynamicError.makeDynamicError(e);
272                 err.setErrorCode(e.getErrorCodeLocalPart());
273                 err.setXPathContext(context);
274                 err.setLocator(this);
275                 err.setIsTypeError(true);
276                 throw err;
277             }
278         }
279
280         return o;
281     }
282
283      /**
284      * Display this instruction as an expression, for diagnostics
285      */

286
287     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
288         out.println(ExpressionTool.indent(level) + "attribute ");
289         out.println(ExpressionTool.indent(level+1) + "name " +
290                 (pool==null ? nameCode+"" : pool.getDisplayName(nameCode)));
291         super.display(level+1, pool, out);
292     }
293 }
294
295 //
296
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
297
// you may not use this file except in compliance with the License. You may obtain a copy of the
298
// License at http://www.mozilla.org/MPL/
299
//
300
// Software distributed under the License is distributed on an "AS IS" basis,
301
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
302
// See the License for the specific language governing rights and limitations under the License.
303
//
304
// The Original Code is: all this file.
305
//
306
// The Initial Developer of the Original Code is Michael H. Kay.
307
//
308
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
309
//
310
// Contributor(s): none.
311
//
312
Popular Tags