1 package net.sf.saxon.instruct; 2 import net.sf.saxon.Controller; 3 import net.sf.saxon.Err; 4 import net.sf.saxon.Configuration; 5 import net.sf.saxon.event.ReceiverOptions; 6 import net.sf.saxon.event.SequenceReceiver; 7 import net.sf.saxon.expr.*; 8 import net.sf.saxon.om.*; 9 import net.sf.saxon.pattern.NodeKindTest; 10 import net.sf.saxon.style.StandardNames; 11 import net.sf.saxon.trans.DynamicError; 12 import net.sf.saxon.trans.StaticError; 13 import net.sf.saxon.trans.XPathException; 14 import net.sf.saxon.type.*; 15 import net.sf.saxon.value.QNameValue; 16 import net.sf.saxon.value.SequenceType; 17 import net.sf.saxon.value.StringValue; 18 19 import java.io.PrintStream ; 20 import java.util.ArrayList ; 21 import java.util.Iterator ; 22 23 27 28 public final class Attribute extends SimpleNodeConstructor { 29 30 private Expression attributeName; 31 private Expression namespace=null; 32 private NamespaceResolver nsContext; 33 private SimpleType schemaType; 34 private int annotation; 35 private int validationAction; 36 private boolean allowNameAsQName; 37 private int options; 38 39 51 52 public Attribute (Expression attributeName, 53 Expression namespace, 54 NamespaceResolver nsContext, 55 int validationAction, 56 SimpleType schemaType, 57 int annotation, 58 boolean allowNameAsQName) { 59 this.attributeName = attributeName; 60 this.namespace = namespace; 61 this.nsContext = nsContext; 62 this.schemaType = schemaType; 63 if (annotation == -1) { 64 this.annotation = StandardNames.XDT_UNTYPED_ATOMIC; 65 } else { 66 this.annotation = annotation; 67 } 68 this.validationAction = validationAction; 69 this.options = 0; 70 this.allowNameAsQName = allowNameAsQName; 71 adoptChildExpression(attributeName); 72 adoptChildExpression(namespace); 73 } 74 75 79 80 public void setRejectDuplicates() { 81 this.options |= ReceiverOptions.REJECT_DUPLICATES; 82 } 83 84 87 88 public int getInstructionNameCode() { 89 return StandardNames.XSL_ATTRIBUTE; 90 } 91 92 public ItemType getItemType() { 93 return NodeKindTest.ATTRIBUTE; 94 } 95 96 public int getCardinality() { 97 return StaticProperty.EXACTLY_ONE; 98 } 99 100 107 108 public int computeSpecialProperties() { 109 return super.computeSpecialProperties() | 110 StaticProperty.SINGLE_DOCUMENT_NODESET; 111 } 112 113 114 public Expression simplify(StaticContext env) throws XPathException { 115 attributeName = attributeName.simplify(env); 116 if (namespace!=null) { 117 namespace = namespace.simplify(env); 118 } 119 return super.simplify(env); 120 } 121 122 public void localTypeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 123 attributeName = attributeName.typeCheck(env, contextItemType); 124 adoptChildExpression(attributeName); 125 126 RoleLocator role = new RoleLocator(RoleLocator.INSTRUCTION, "attribute/name", 0, null); 127 role.setSourceLocator(this); 128 129 if (allowNameAsQName) { 130 attributeName = TypeChecker.staticTypeCheck(attributeName, 132 SequenceType.SINGLE_ATOMIC, false, role, env); 133 } else { 134 attributeName = TypeChecker.staticTypeCheck(attributeName, 135 SequenceType.SINGLE_STRING, false, role, env); 136 } 137 138 if (namespace != null) { 139 namespace.typeCheck(env, contextItemType); 140 adoptChildExpression(namespace); 141 142 role = new RoleLocator(RoleLocator.INSTRUCTION, "attribute/namespace", 0, null); 143 role.setSourceLocator(this); 144 namespace = TypeChecker.staticTypeCheck( 145 namespace, SequenceType.SINGLE_STRING, false, role, env); 146 } 147 } 148 149 153 154 public Iterator iterateSubExpressions() { 155 ArrayList list = new ArrayList (10); 156 if (select != null) { 157 list.add(select); 158 } 159 list.add(attributeName); 160 if (namespace != null) { 161 list.add(namespace); 162 } 163 return list.iterator(); 164 } 165 166 178 179 protected void promoteInst(PromotionOffer offer) throws XPathException { 180 attributeName = doPromotion(attributeName, offer); 181 if (namespace != null) { 182 namespace = doPromotion(namespace, offer); 183 } 184 super.promoteInst(offer); 185 } 186 187 194 195 public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException { 196 if (parentType instanceof SimpleType) { 197 StaticError err = new StaticError( 198 "Attributes are not permitted here: the containing element is of simple type " + 199 parentType.getDescription()); 200 err.setIsTypeError(true); 201 err.setLocator(this); 202 throw err; 203 } 204 } 205 206 211 212 public TailCall processLeavingTail(XPathContext context) throws XPathException 213 { 214 Controller controller = context.getController(); 215 int nameCode = evaluateNameCode(context); 216 if (nameCode == -1) { 217 return null; 218 } 219 SequenceReceiver out = context.getReceiver(); 220 int opt = options; 221 int ann = annotation; 222 223 227 String value = expandChildren(context).toString(); 228 if (schemaType != null) { 229 try { 231 XPathException err = schemaType.validateContent(value, DummyNamespaceResolver.getInstance(), context); 232 if (err != null) { 233 throw new ValidationException("Attribute value " + Err.wrap(value, Err.VALUE) + 234 " does not match the required type " + 235 schemaType.getDescription() + ". " + 236 err.getMessage()); 237 } 238 } catch (UnresolvedReferenceException ure) { 239 throw new ValidationException(ure); 240 } 241 } else if (validationAction==Validation.STRICT || 242 validationAction==Validation.LAX) { 243 try { 244 ann = controller.getConfiguration().validateAttribute( 245 nameCode, value, validationAction); 246 } catch (ValidationException e) { 247 DynamicError err = DynamicError.makeDynamicError(e); 248 err.setErrorCode(e.getErrorCodeLocalPart()); 249 err.setXPathContext(context); 250 err.setLocator(this); 251 err.setIsTypeError(true); 252 throw err; 253 } 254 } 255 try { 256 out.attribute(nameCode, ann, value, locationId, opt); 257 } catch (XPathException err) { 258 throw dynamicError(this, err, context); 259 } 260 261 return null; 262 } 263 264 protected int evaluateNameCode(XPathContext context) throws XPathException, XPathException { 265 Controller controller = context.getController(); 266 NamePool pool = controller.getNamePool(); 267 268 Item nameValue = attributeName.evaluateItem(context); 269 270 String prefix = null; 271 String localName = null; 272 273 if (nameValue instanceof StringValue) { 274 CharSequence rawName = nameValue.getStringValueCS(); 276 try { 277 String [] parts = Name.getQNameParts(rawName); 278 prefix = parts[0]; 279 localName = parts[1]; 280 } catch (QNameException err) { 281 DynamicError err1 = new DynamicError("Invalid attribute name: " + rawName, this); 282 err1.setErrorCode("XTDE0850"); 283 err1.setXPathContext(context); 284 throw dynamicError(this, err1, context); 285 } 286 if (rawName.equals("xmlns")) { 287 if (namespace==null) { 288 DynamicError err = new DynamicError("Invalid attribute name: " + rawName, this); 289 if (context.getController().getExecutable().getHostLanguage() == Configuration.XQUERY) { 290 err.setErrorCode("XQDY0044"); 291 } else { 292 err.setErrorCode("XTDE0855"); 293 } 294 err.setXPathContext(context); 295 throw dynamicError(this, err, context); 296 } 297 } 298 if (prefix.equals("xmlns")) { 299 if (namespace==null) { 300 DynamicError err = new DynamicError("Invalid attribute name: " + rawName, this); 301 if (context.getController().getExecutable().getHostLanguage() == Configuration.XQUERY) { 302 err.setErrorCode("XQDY0044"); 303 } else { 304 err.setErrorCode("XTDE0860"); 305 } 306 err.setXPathContext(context); 307 throw dynamicError(this, err, context); 308 } else { 309 prefix = ""; 311 } 312 } 313 314 } else if (nameValue instanceof QNameValue) { 315 localName = ((QNameValue)nameValue).getLocalName(); 317 String namespaceURI = ((QNameValue)nameValue).getNamespaceURI(); 318 if (namespaceURI == null) { 319 namespaceURI = ""; 320 } 321 namespace = new StringValue(namespaceURI); 322 if (namespaceURI.equals("")) { 323 prefix = ""; 324 } else { 325 prefix = ((QNameValue)nameValue).getPrefix(); 326 } 328 329 } 330 331 String uri; 332 333 if (namespace==null) { 334 if ("".equals(prefix)) { 335 uri = ""; 336 } else { 337 uri = nsContext.getURIForPrefix(prefix, false); 338 if (uri==null) { 339 DynamicError err = new DynamicError("Undeclared prefix in attribute name: " + prefix, this); 340 err.setErrorCode("XTDE0860"); 341 err.setXPathContext(context); 342 throw dynamicError(this, err, context); 343 } 344 } 345 346 } else { 347 348 350 uri = namespace.evaluateAsString(context); 351 if ("".equals(uri)) { 352 prefix = ""; 355 356 } else { 357 if ("".equals(prefix)) { 360 prefix = pool.suggestPrefixForURI(uri); 361 if (prefix == null) { 362 prefix = "ns0"; 363 } 365 } 366 } 367 } 368 369 return pool.allocate(prefix, uri, localName); 370 } 371 372 375 376 public void display(int level, NamePool pool, PrintStream out) { 377 out.println(ExpressionTool.indent(level) + "attribute "); 378 out.println(ExpressionTool.indent(level+1) + "name"); 379 attributeName.display(level+2, pool, out); 380 super.display(level+1, pool, out); 381 } 382 } 383 384 | Popular Tags |