1 package net.sf.saxon.instruct; 2 3 import net.sf.saxon.Controller; 4 import net.sf.saxon.OutputURIResolver; 5 import net.sf.saxon.event.SaxonOutputKeys; 6 import net.sf.saxon.event.SequenceReceiver; 7 import net.sf.saxon.event.StandardOutputResolver; 8 import net.sf.saxon.expr.*; 9 import net.sf.saxon.om.*; 10 import net.sf.saxon.pattern.NoNodeTest; 11 import net.sf.saxon.style.StandardNames; 12 import net.sf.saxon.trans.DynamicError; 13 import net.sf.saxon.trans.XPathException; 14 import net.sf.saxon.trans.SaxonErrorCode; 15 import net.sf.saxon.type.ItemType; 16 import net.sf.saxon.type.SchemaType; 17 import net.sf.saxon.value.Value; 18 19 import javax.xml.transform.OutputKeys ; 20 import javax.xml.transform.Result ; 21 import javax.xml.transform.TransformerException ; 22 import javax.xml.transform.dom.DOMResult ; 23 import javax.xml.transform.sax.SAXResult ; 24 import javax.xml.transform.stream.StreamResult ; 25 import java.io.PrintStream ; 26 import java.io.File ; 27 import java.util.*; 28 29 41 42 public class ResultDocument extends Instruction { 43 44 private Expression href; 45 private Expression content; 46 private Properties outputProperties; 47 private String baseURI; private int validationAction; 49 private SchemaType schemaType; 50 private HashMap serializationAttributes; 51 private NamespaceResolver nsResolver; 52 53 public ResultDocument(Properties outputProperties, Expression href, 55 String baseURI, 56 int validationAction, 57 SchemaType schemaType, 58 HashMap serializationAttributes, NamespaceResolver nsResolver) { 60 this.outputProperties = outputProperties; 61 this.href = href; 62 this.baseURI = baseURI; 63 this.validationAction = validationAction; 64 this.schemaType = schemaType; 65 this.serializationAttributes = serializationAttributes; 66 this.nsResolver = nsResolver; 67 adoptChildExpression(href); 68 for (Iterator it = serializationAttributes.values().iterator(); it.hasNext();) { 69 adoptChildExpression((Expression) it.next()); 70 } 71 } 72 73 76 77 public void setContent(Expression content) { 78 this.content = content; 79 adoptChildExpression(content); 80 } 81 82 89 90 public Expression simplify(StaticContext env) throws XPathException { 91 content = content.simplify(env); 92 if (href != null) { 93 href = href.simplify(env); 94 } 95 for (Iterator it = serializationAttributes.keySet().iterator(); it.hasNext();) { 96 Object key = it.next(); 97 Expression value = (Expression)serializationAttributes.get(key); 98 if (!(value instanceof Value)) { 99 value = value.simplify(env); 100 serializationAttributes.put(key, value); 101 } 102 } 103 return this; 104 } 105 106 public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException { 107 content = content.typeCheck(env, contextItemType); 108 adoptChildExpression(content); 109 if (href != null) { 110 href = href.typeCheck(env, contextItemType); 111 adoptChildExpression(href); 112 } 113 for (Iterator it = serializationAttributes.keySet().iterator(); it.hasNext();) { 114 Object key = it.next(); 115 Expression value = (Expression)serializationAttributes.get(key); 116 if (!(value instanceof Value)) { 117 value = value.typeCheck(env, contextItemType); 118 adoptChildExpression(value); 119 serializationAttributes.put(key, value); 120 } 121 } 122 return this; 123 } 124 125 public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException { 126 content = content.optimize(opt, env, contextItemType); 127 adoptChildExpression(content); 128 if (href != null) { 129 href = href.optimize(opt, env, contextItemType); 130 adoptChildExpression(href); 131 } 132 for (Iterator it = serializationAttributes.keySet().iterator(); it.hasNext();) { 133 Object key = it.next(); 134 Expression value = (Expression)serializationAttributes.get(key); 135 if (!(value instanceof Value)) { 136 value = value.optimize(opt, env, contextItemType); 137 adoptChildExpression(value); 138 serializationAttributes.put(key, value); 139 } 140 } 141 return this; 142 } 143 144 149 150 protected void promoteInst(PromotionOffer offer) throws XPathException { 151 content = doPromotion(content, offer); 152 if (href != null) { 153 href = doPromotion(href, offer); 154 } 155 for (Iterator it = serializationAttributes.keySet().iterator(); it.hasNext();) { 156 Object key = it.next(); 157 Expression value = (Expression)serializationAttributes.get(key); 158 if (!(value instanceof Value)) { 159 value = doPromotion(value, offer); 160 serializationAttributes.put(key, value); 161 } 162 } 163 } 164 165 169 170 public int getInstructionNameCode() { 171 return StandardNames.XSL_RESULT_DOCUMENT; 172 } 173 174 179 180 public ItemType getItemType() { 181 return NoNodeTest.getInstance(); 182 } 183 184 185 186 191 192 public Iterator iterateSubExpressions() { 193 ArrayList list = new ArrayList(6); 194 list.add(content); 195 if (href != null) { 196 list.add(href); 197 } 198 for (Iterator it = serializationAttributes.values().iterator(); it.hasNext();) { 199 list.add(it.next()); 200 } 201 return list.iterator(); 202 } 203 204 public TailCall processLeavingTail(XPathContext context) throws XPathException { 205 Controller controller = context.getController(); 206 XPathContext c2 = context.newMinorContext(); 207 c2.setOrigin(this); 208 209 Result result; 210 OutputURIResolver resolver = null; 211 212 if (href == null) { 213 result = controller.getPrincipalResult(); 214 } else { 215 try { 216 String base = controller.getBaseOutputURI(); 217 if (base == null && controller.getConfiguration().isAllowExternalFunctions()) { 218 base = new File (System.getProperty("user.dir")).toURI().toString(); 221 } 222 223 resolver = controller.getOutputURIResolver(); 224 225 String hrefValue = href.evaluateAsString(context); 226 result = resolver.resolve(hrefValue, base); 227 if (result == null) { 228 resolver = StandardOutputResolver.getInstance(); 229 result = resolver.resolve(hrefValue, base); 230 } 231 } catch (TransformerException e) { 232 throw DynamicError.makeDynamicError(e); 233 } 234 } 235 236 if (!controller.checkUniqueOutputDestination(result.getSystemId())) { 237 DynamicError err = new DynamicError("Cannot write more than one result document to the same URI: " + 238 result.getSystemId()); 239 err.setXPathContext(context); 240 err.setErrorCode("XTDE1490"); 241 throw err; 242 } 243 244 boolean timing = controller.getConfiguration().isTiming(); 245 if (timing) { 246 String dest = result.getSystemId(); 247 if (dest == null) { 248 if (result instanceof StreamResult ) { 249 dest = "anonymous output stream"; 250 } else if (result instanceof SAXResult ) { 251 dest = "SAX2 ContentHandler"; 252 } else if (result instanceof DOMResult ) { 253 dest = "DOM tree"; 254 } else { 255 dest = result.getClass().getName(); 256 } 257 } 258 System.err.println("Writing to " + dest); 259 } 260 261 Properties props = outputProperties; 262 if (serializationAttributes.size() > 0) { 263 props = new Properties(outputProperties); 264 final NamePool namePool = context.getController().getNamePool(); 265 for (Iterator it = serializationAttributes.keySet().iterator(); it.hasNext();) { 266 Integer key = (Integer ) it.next(); 267 Expression exp = (Expression) serializationAttributes.get(key); 268 String value = exp.evaluateAsString(context); 269 try { 270 setSerializationProperty(props, key.intValue(), value, namePool, nsResolver); 271 } catch (DynamicError e) { 272 if (NamespaceConstant.SAXON.equals(e.getErrorCodeNamespace()) && 273 "warning".equals(e.getErrorCodeLocalPart())) { 274 try { 275 context.getController().getErrorListener().warning(e); 276 } catch (TransformerException e2) { 277 throw DynamicError.makeDynamicError(e2); 278 } 279 } else { 280 e.setXPathContext(context); 281 e.setLocator(getSourceLocator()); 282 throw e; 283 } 284 } 285 } 286 } 287 String nextInChain = outputProperties.getProperty(SaxonOutputKeys.NEXT_IN_CHAIN); 288 if (nextInChain != null) { 289 try { 290 result = controller.prepareNextStylesheet(nextInChain, baseURI, result); 291 } catch (TransformerException e) { 292 throw DynamicError.makeDynamicError(e); 293 } 294 } 295 296 300 c2.changeOutputDestination(props, 301 result, 302 true, 303 validationAction, 304 schemaType); 305 SequenceReceiver out = c2.getReceiver(); 306 307 out.startDocument(0); 308 content.process(c2); 309 out.endDocument(); 310 out.close(); 311 if (resolver != null) { 312 try { 313 resolver.close(result); 314 } catch (TransformerException e) { 315 throw DynamicError.makeDynamicError(e); 316 } 317 } 318 return null; 319 } 320 321 324 325 public static void setSerializationProperty(Properties details, int fp, 326 String value, NamePool pool, 327 NamespaceResolver nsResolver) 328 throws XPathException { 329 String lname = pool.getLocalName(fp); 330 String uri = pool.getURI(fp); 331 if (uri.equals("")) { 332 if (lname.equals(StandardNames.METHOD)) { 333 if (value.equals("xml") || value.equals("html") || 334 value.equals("text") || value.equals("xhtml")) { 335 details.put(OutputKeys.METHOD, value); 336 } else { 337 String [] parts; 338 try { 339 parts = Name.getQNameParts(value); 340 String prefix = parts[0]; 341 if (prefix.equals("")) { 342 DynamicError err = new DynamicError("method must be xml, html, xhtml, or text, or a prefixed name"); 343 err.setErrorCode("XTSE1570"); 344 throw err; 345 } else { 346 String muri = nsResolver.getURIForPrefix(prefix, false); 347 if (muri==null) { 348 DynamicError err = new DynamicError("Namespace prefix '" + prefix + "' has not been declared"); 349 err.setErrorCode("XTSE1570"); 350 throw err; 351 } 352 details.put(OutputKeys.METHOD, '{' + muri + '}' + parts[1]); 353 } 354 } catch (QNameException e) { 355 DynamicError err = new DynamicError("Invalid method name. " + e.getMessage()); 356 err.setErrorCode("XTSE1570"); 357 throw err; 358 } 359 } 360 } else 361 362 if (lname.equals(StandardNames.OUTPUT_VERSION)) { 363 details.put(OutputKeys.VERSION, value); 364 } else 365 366 if (lname.equals("byte-order-mark")) { 367 if (value.equals("yes") || value.equals("no")) { 368 details.put(SaxonOutputKeys.BYTE_ORDER_MARK, value); 369 } else { 370 DynamicError err = new DynamicError("byte-order-mark value must be 'yes' or 'no'"); 371 err.setErrorCode("XTDE0030"); 372 throw err; 373 } 374 } else 375 376 if (lname.equals(StandardNames.INDENT)) { 377 if (value.equals("yes") || value.equals("no")) { 378 details.put(OutputKeys.INDENT, value); 379 } else { 380 DynamicError err = new DynamicError("indent must be 'yes' or 'no'"); 381 err.setErrorCode("XTDE0030"); 382 throw err; 383 } 384 } else 385 386 if (lname.equals(StandardNames.ENCODING)) { 387 details.put(OutputKeys.ENCODING, value); 388 } else 389 390 if (lname.equals(StandardNames.MEDIA_TYPE)) { 391 details.put(OutputKeys.MEDIA_TYPE, value); 392 } else 393 394 if (lname.equals(StandardNames.DOCTYPE_SYSTEM)) { 395 details.put(OutputKeys.DOCTYPE_SYSTEM, value); 396 } else 397 398 if (lname.equals(StandardNames.DOCTYPE_PUBLIC)) { 399 details.put(OutputKeys.DOCTYPE_PUBLIC, value); 400 } else 401 402 if (lname.equals(StandardNames.OMIT_XML_DECLARATION)) { 403 if (value.equals("yes") || value.equals("no")) { 404 details.put(OutputKeys.OMIT_XML_DECLARATION, value); 405 } else { 406 DynamicError err = new DynamicError("omit-xml-declaration attribute must be 'yes' or 'no'"); 407 err.setErrorCode("XTDE0030"); 408 throw err; 409 } 410 } else 411 412 if (lname.equals(StandardNames.STANDALONE)) { 413 if (value.equals("yes") || value.equals("no") || value.equals("omit")) { 414 details.put(OutputKeys.STANDALONE, value); 415 DynamicError err = new DynamicError("standalone attribute must be 'yes' or 'no' or 'omit'"); 416 err.setErrorCode("XTDE0030"); 417 throw err; 418 } 419 } else 420 421 if (lname.equals(StandardNames.CDATA_SECTION_ELEMENTS)) { 422 String existing = details.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS); 423 if (existing == null) { 424 existing = ""; 425 } 426 String s = ""; 427 StringTokenizer st = new StringTokenizer(value); 428 while (st.hasMoreTokens()) { 429 String displayname = st.nextToken(); 430 try { 431 String [] parts = Name.getQNameParts(displayname); 432 String muri = nsResolver.getURIForPrefix(parts[0], true); 433 if (muri==null) { 434 DynamicError err = new DynamicError("Namespace prefix '" + parts[0] + "' has not been declared"); 435 err.setErrorCode("XT0030"); 436 throw err; 437 } 438 s += " {" + muri + '}' + parts[1]; 439 } catch (QNameException err) { 440 DynamicError e = new DynamicError("Invalid CDATA element name. " + err.getMessage()); 441 e.setErrorCode("XTDE0030"); 442 throw e; 443 } 444 445 details.put(OutputKeys.CDATA_SECTION_ELEMENTS, existing + s); 446 } 447 } else 448 449 if (lname.equals(StandardNames.USE_CHARACTER_MAPS)) { 450 String existing = details.getProperty(SaxonOutputKeys.USE_CHARACTER_MAPS); 451 if (existing == null) { 452 existing = ""; 453 } 454 details.put(SaxonOutputKeys.USE_CHARACTER_MAPS, existing + value); 455 } else 456 457 458 if (lname.equals(StandardNames.UNDECLARE_PREFIXES)) { 459 if (value.equals("yes") || value.equals("no")) { 460 details.put(SaxonOutputKeys.UNDECLARE_PREFIXES, value); 461 } else { 462 DynamicError err = new DynamicError("undeclare-namespaces value must be 'yes' or 'no'"); 463 err.setErrorCode("XTDE0030"); 464 throw err; 465 } 466 } else 467 468 if (lname.equals(StandardNames.INCLUDE_CONTENT_TYPE)) { 469 if (value.equals("yes") || value.equals("no")) { 470 details.put(SaxonOutputKeys.INCLUDE_CONTENT_TYPE, value); 471 } else { 472 DynamicError err = new DynamicError("include-content-type attribute must be 'yes' or 'no'"); 473 err.setErrorCode("XTDE0030"); 474 throw err; 475 } 476 } else 477 478 if (lname.equals(StandardNames.ESCAPE_URI_ATTRIBUTES)) { 479 if (value.equals("yes") || value.equals("no")) { 480 details.put(SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES, value); 481 } else { 482 DynamicError err = new DynamicError("escape-uri-attributes value must be 'yes' or 'no'"); 483 err.setErrorCode("XTDE0030"); 484 throw err; 485 } 486 } else 487 488 if (lname.equals(StandardNames.NORMALIZATION_FORM)) { 489 if (value.equals("NFC") || value.equals("NFD") || 490 value.equals("NFKC") || value.equals("NFKD")) { 491 details.put(SaxonOutputKeys.NORMALIZATION_FORM, value); 492 } else if (value.equals("none")) { 493 } else { 495 DynamicError err = new DynamicError("escape-uri-attributes value must be 'yes' or 'no'"); 496 err.setErrorCode("XTDE0030"); 497 throw err; 498 } 499 } 500 501 } else if (uri.equals(NamespaceConstant.SAXON)) { 502 503 if (lname.equals("character-representation")) { 504 details.put(SaxonOutputKeys.CHARACTER_REPRESENTATION, value); 505 } else 506 507 if (lname.equals("indent-spaces")) { 508 try { 509 Integer.parseInt(value); 510 details.put(OutputKeys.INDENT, "yes"); 511 details.put(SaxonOutputKeys.INDENT_SPACES, value); 512 } catch (NumberFormatException err) { 513 DynamicError e = new DynamicError("saxon:indent-spaces must be an integer"); 514 e.setErrorCode(NamespaceConstant.SAXON, SaxonErrorCode.SXWN9002); 515 throw e; 516 } 517 } else 518 519 if (lname.equals("next-in-chain")) { 520 DynamicError e = new DynamicError("saxon:next-in-chain value cannot be specified dynamically"); 521 e.setErrorCode(NamespaceConstant.SAXON, SaxonErrorCode.SXWN9004); 522 throw e; 523 } else 524 525 if (lname.equals("require-well-formed")) { 526 if (value.equals("yes") || value.equals("no")) { 527 details.put(SaxonOutputKeys.REQUIRE_WELL_FORMED, value); 528 } else { 529 DynamicError e = new DynamicError("saxon:require-well-formed value must be 'yes' or 'no'"); 530 e.setErrorCode(NamespaceConstant.SAXON, SaxonErrorCode.SXWN9003); 531 throw e; 532 } 533 } 534 535 } else { 536 537 details.put('{' + uri + '}' + lname, value); 539 } 540 541 } 542 543 550 551 public void display(int level, NamePool pool, PrintStream out) { 552 out.println(ExpressionTool.indent(level) + "result-document"); 553 content.display(level + 1, pool, out); 554 } 555 } 556 557 | Popular Tags |