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 ; 23 24 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 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 65 66 public int getInstructionNameCode() { 67 return StandardNames.XSL_ATTRIBUTE; 68 } 69 73 74 public void setRejectDuplicates() { 75 this.options |= ReceiverOptions.REJECT_DUPLICATES; 76 } 77 78 82 83 public void setNoSpecialChars() { 84 this.options |= ReceiverOptions.NO_SPECIAL_CHARS; 85 } 86 87 94 public void setSelect(Expression select) throws StaticError { 95 super.setSelect(select); 96 97 if (select instanceof AtomicValue && schemaType != null && !schemaType.isNamespaceSensitive()) { 99 CharSequence 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 (select instanceof StringValue) { 113 boolean special = false; 114 CharSequence 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 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 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 } catch (XPathException e) { 190 if (e.getLocator() == null || e.getLocator() == e) { 191 e.setLocator(this); 192 } 193 throw e; 194 } 195 } 196 197 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 214 String value = expandChildren(context).toString(); 215 if (schemaType != null) { 216 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 286 287 public void display(int level, NamePool pool, PrintStream 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 | Popular Tags |