1 package net.sf.saxon.instruct; 2 3 import net.sf.saxon.Controller; 4 import net.sf.saxon.pattern.NodeKindTest; 5 import net.sf.saxon.pattern.ContentTypeTest; 6 import net.sf.saxon.event.*; 7 import net.sf.saxon.expr.*; 8 import net.sf.saxon.om.*; 9 import net.sf.saxon.style.StandardNames; 10 import net.sf.saxon.trans.DynamicError; 11 import net.sf.saxon.trans.XPathException; 12 import net.sf.saxon.type.*; 13 import net.sf.saxon.value.AtomicValue; 14 import net.sf.saxon.value.Value; 15 16 import java.io.PrintStream ; 17 import java.util.Iterator ; 18 19 20 23 24 public class CopyOf extends Instruction implements MappingFunction { 25 26 private Expression select; 27 private boolean copyNamespaces; 28 private int validation; 29 private SchemaType schemaType; 30 private boolean requireDocumentOrElement = false; 31 private boolean rejectDuplicateAttributes; 32 private boolean readOnce = false; 33 34 public CopyOf(Expression select, 35 boolean copyNamespaces, 36 int validation, 37 SchemaType schemaType, boolean rejectDuplicatAttributes) { 38 this.select = select; 39 this.copyNamespaces = copyNamespaces; 40 this.validation = validation; 41 this.schemaType = schemaType; 42 this.rejectDuplicateAttributes = rejectDuplicatAttributes; 43 adoptChildExpression(select); 44 } 45 46 public void setReadOnce(boolean b) { 47 readOnce = b; 48 } 49 50 54 55 public final boolean createsNewNodes() { 56 return !Type.isSubType(select.getItemType(), Type.ANY_ATOMIC_TYPE); 57 } 58 59 62 63 public int getInstructionNameCode() { 64 return StandardNames.XSL_COPY_OF; 65 } 66 67 71 public void setRequireDocumentOrElement(boolean requireDocumentOrElement) { 72 this.requireDocumentOrElement = requireDocumentOrElement; 73 } 74 75 80 81 public int getImplementationMethod() { 82 return ITERATE_METHOD | PROCESS_METHOD; 83 } 84 85 90 91 public TailCall processLeavingTail(XPathContext context) throws XPathException { 92 93 Controller controller = context.getController(); 94 SequenceReceiver out = context.getReceiver(); 95 96 int whichNamespaces = (copyNamespaces ? NodeInfo.ALL_NAMESPACES : NodeInfo.NO_NAMESPACES); 97 98 SequenceIterator iter = select.iterate(context); 99 while (true) { 100 101 102 Item item = iter.next(); 103 if (item == null) { 104 break; 105 } 106 if (item instanceof NodeInfo) { 107 NodeInfo source = (NodeInfo) item; 108 int kind = source.getNodeKind(); 109 if (requireDocumentOrElement && 110 !(kind == Type.ELEMENT || kind == Type.DOCUMENT)) { 111 DynamicError e = new DynamicError( 112 "Operand of validate expression must be a document or element node" 113 ); 114 e.setXPathContext(context); 115 e.setErrorCode("XQTY0030"); 116 throw e; 117 } 118 switch (kind) { 119 120 case Type.ELEMENT: 121 122 Receiver eval = controller.getConfiguration().getElementValidator( 123 out, source.getNameCode(), locationId, 124 schemaType, validation, 125 controller.getNamePool() 126 ); 127 source.copy(eval, whichNamespaces, true, locationId); 128 break; 129 130 case Type.ATTRIBUTE: 131 try { 132 copyAttribute(source, schemaType, validation, this, context, rejectDuplicateAttributes); 133 } catch (NoOpenStartTagException err) { 134 DynamicError e = new DynamicError(err.getMessage()); 135 e.setLocator(this); 136 e.setXPathContext(context); 137 e.setErrorCode(err.getErrorCodeLocalPart()); 138 throw dynamicError(this, e, context); 139 } 140 break; 141 case Type.TEXT: 142 out.characters(source.getStringValueCS(), locationId, 0); 143 break; 144 145 case Type.PROCESSING_INSTRUCTION: 146 out.processingInstruction(source.getDisplayName(), source.getStringValueCS(), locationId, 0); 147 break; 148 149 case Type.COMMENT: 150 out.comment(source.getStringValueCS(), locationId, 0); 151 break; 152 153 case Type.NAMESPACE: 154 try { 155 source.copy(out, NodeInfo.NO_NAMESPACES, false, locationId); 156 } catch (NoOpenStartTagException err) { 157 DynamicError e = new DynamicError(err.getMessage()); 158 e.setXPathContext(context); 159 e.setErrorCode(err.getErrorCodeLocalPart()); 160 throw dynamicError(this, e, context); 162 } 163 break; 164 165 case Type.DOCUMENT: 166 Receiver val = controller.getConfiguration(). 167 getDocumentValidator(out, 168 source.getBaseURI(), 169 controller.getNamePool(), 170 validation, schemaType); 171 val.setPipelineConfiguration(out.getPipelineConfiguration()); 172 source.copy(val, whichNamespaces, true, locationId); 174 break; 176 177 default: 178 throw new IllegalArgumentException ("Unknown node kind " + source.getNodeKind()); 179 } 180 181 } else { 182 out.append(item, locationId, NodeInfo.ALL_NAMESPACES); 183 } 184 } 185 return null; 186 } 187 188 protected static void copyAttribute(NodeInfo source, 189 SchemaType schemaType, 190 int validation, 191 Instruction instruction, 192 XPathContext context, 193 boolean rejectDuplicates) 194 throws XPathException { 195 int nameCode = source.getNameCode(); 196 int annotation = -1; 197 int opt = 0; 198 if (rejectDuplicates) { 199 opt |= ReceiverOptions.REJECT_DUPLICATES; 200 } 201 CharSequence value = source.getStringValueCS(); 202 if (schemaType != null) { 203 if (schemaType.isSimpleType()) { 204 if (((SimpleType)schemaType).isNamespaceSensitive()) { 205 DynamicError err = new DynamicError("Cannot create a parentless attribute whose " + 206 "type is namespace-sensitive (such as xs:QName)"); 207 err.setErrorCode( "XTTE1545"); 208 err.setXPathContext(context); 209 err.setLocator(instruction); 210 throw err; 211 } 212 try { 213 XPathException err = ((SimpleType) schemaType).validateContent( 214 value, DummyNamespaceResolver.getInstance(), context); 215 if (err != null) { 216 throw new ValidationException("Attribute being copied does not match the required type. " + 217 err.getMessage()); 218 } 219 annotation = schemaType.getFingerprint(); 220 } catch (UnresolvedReferenceException ure) { 221 throw new ValidationException(ure); 222 } 223 } else { 224 DynamicError e = new DynamicError("Cannot validate an attribute against a complex type"); 225 e.setXPathContext(context); 226 e.setErrorCode("XTSE1530"); 227 throw e; 228 } 229 } else if (validation == Validation.STRICT || 230 validation == Validation.LAX) { 231 try { 232 annotation = context.getController().getConfiguration().validateAttribute( 233 nameCode, value, validation); 234 } catch (ValidationException e) { 235 DynamicError err = DynamicError.makeDynamicError(e); 236 err.setErrorCode(e.getErrorCodeLocalPart()); 237 err.setXPathContext(context); 238 err.setLocator(instruction); 239 err.setIsTypeError(true); 240 throw err; 241 } 242 243 } else if (validation == Validation.PRESERVE) { 244 annotation = source.getTypeAnnotation(); 245 } 246 247 context.getReceiver().attribute(nameCode, annotation, value, instruction.getLocationId(), opt); 248 } 249 250 public Expression simplify(StaticContext env) throws XPathException { 251 select = select.simplify(env); 252 return this; 253 } 254 255 public ItemType getItemType() { 256 if (schemaType != null) { 257 ItemType in = select.getItemType(); 258 int e = Type.relationship(in, NodeKindTest.ELEMENT); 259 if (e == Type.SAME_TYPE || e == Type.SUBSUMED_BY) { 260 return new ContentTypeTest(Type.ELEMENT, schemaType, getExecutable().getConfiguration()); 261 } 262 int a = Type.relationship(in, NodeKindTest.ATTRIBUTE); 263 if (a == Type.SAME_TYPE || a == Type.SUBSUMED_BY) { 264 return new ContentTypeTest(Type.ATTRIBUTE, schemaType, getExecutable().getConfiguration()); 265 } 266 } 267 return select.getItemType(); 268 } 269 270 public int getCardinality() { 271 return select.getCardinality(); 272 } 273 274 public int getDependencies() { 275 return select.getDependencies(); 276 } 277 278 protected void promoteInst(PromotionOffer offer) throws XPathException { 279 select = doPromotion(select, offer); 280 } 281 282 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 283 select = select.typeCheck(env, contextItemType); 284 adoptChildExpression(select); 285 return this; 286 } 287 288 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 289 select = select.optimize(opt, env, contextItemType); 290 adoptChildExpression(select); 291 if (readOnce) { 292 Expression optcopy = opt.optimizeCopy(select); 293 if (optcopy != null) { 294 return optcopy; 295 } 296 } 297 return this; 298 } 299 300 307 308 public void display(int level, NamePool pool, PrintStream out) { 309 out.println(ExpressionTool.indent(level) + "copyOf " + 310 ("validation=" + Validation.toString(validation))); 311 select.display(level + 1, pool, out); 312 } 313 314 public Iterator iterateSubExpressions() { 315 return new MonoIterator(select); 316 } 317 318 324 325 public Item evaluateItem(XPathContext context) throws XPathException { 326 return super.evaluateItem(context); 327 } 328 329 public SequenceIterator iterate(XPathContext context) throws XPathException { 330 if (validation==Validation.PRESERVE && schemaType==null && copyNamespaces) { 331 return new MappingIterator(select.iterate(context), this, context); 333 } 334 Controller controller = context.getController(); 335 XPathContext c2 = context.newMinorContext(); 336 c2.setOrigin(this); 337 SequenceOutputter out = new SequenceOutputter(); 338 out.setPipelineConfiguration(controller.makePipelineConfiguration()); 339 c2.setReceiver(out); 340 try { 341 process(c2); 342 return Value.getIterator(out.getSequence()); 343 } catch (XPathException err) { 344 if (err instanceof ValidationException) { 345 ((ValidationException) err).setSourceLocator(this); 346 ((ValidationException) err).setSystemId(getSystemId()); 347 } 348 if (err.getLocator() == null) { 349 err.setLocator(this); 350 } 351 throw err; 352 } 353 } 354 355 358 359 370 371 public Object map(Item item, XPathContext context) throws XPathException { 372 if (item instanceof AtomicValue) { 373 return item; 374 } 375 VirtualCopy vc = VirtualCopy.makeVirtualCopy((NodeInfo)item, (NodeInfo)item); 376 int documentNumber = 377 context.getController().getConfiguration().getDocumentNumberAllocator().allocateDocumentNumber(); 378 vc.setDocumentNumber(documentNumber); 379 return vc; 380 } 381 382 } 383 384 | Popular Tags |