1 package com.icl.saxon.output; 2 import com.icl.saxon.*; 3 import com.icl.saxon.charcode.*; 4 import com.icl.saxon.om.NamePool; 5 import com.icl.saxon.om.NodeInfo; 6 import com.icl.saxon.om.DocumentInfo; 7 import com.icl.saxon.om.Builder; 8 import com.icl.saxon.tree.AttributeCollection; 9 import com.icl.saxon.tree.TreeBuilder; 10 import com.icl.saxon.tree.DocumentImpl; 11 import com.icl.saxon.tinytree.TinyBuilder; 12 import org.xml.sax.Attributes ; 14 import org.w3c.dom.Node ; 15 import org.w3c.dom.Document ; 16 import java.util.Properties ; 17 import javax.xml.transform.TransformerException ; 18 import javax.xml.transform.Result ; 19 import javax.xml.transform.OutputKeys ; 20 import javax.xml.transform.stream.StreamResult ; 21 import javax.xml.transform.dom.DOMResult ; 22 import javax.xml.transform.sax.SAXResult ; 23 import java.io.*; 24 25 31 32 33 34 public class GeneralOutputter extends Outputter { 35 36 private NamePool namePool; 37 private Properties outputProperties; 38 private Writer writer; 39 private OutputStream outputStream; 40 private boolean closeAfterUse = false; 41 42 private int pendingStartTag = -1; 43 private AttributeCollection pendingAttList; 44 45 private int[] pendingNSList = new int[20]; 46 private int pendingNSListSize = 0; 47 48 private boolean suppressAttributes = false; 49 50 public GeneralOutputter(NamePool pool) { 51 namePool = pool; 52 pendingAttList = new AttributeCollection(namePool, 10); 53 } 54 55 61 62 public void setOutputDestination(Properties props, Result result) 63 throws TransformerException { 64 setOutputProperties(props); 65 66 Emitter emitter = makeEmitter(props, result); 67 emitter.setNamePool(namePool); 68 emitter.setOutputProperties(props); 69 70 setEmitter(emitter); 71 72 open(); 73 } 74 75 80 81 public static String urlToFileName(String base) { 82 if(null != base) { 83 if (base.startsWith("file:////")) { 84 base = base.substring(7); 85 } else if (base.startsWith("file:///")) { 86 base = base.substring(6); 87 } else if (base.startsWith("file://")) { 88 base = base.substring(5); } else if (base.startsWith("file:/")) { 90 base = base.substring(5); 91 } else if (base.startsWith("file:")) { 92 base = base.substring(4); 93 } if (base.startsWith("file:\\\\\\\\")) { 94 base = base.substring(7); 95 } else if (base.startsWith("file:\\\\\\")) { 96 base = base.substring(6); 97 } else if (base.startsWith("file:\\\\")) { 98 base = base.substring(5); 99 } else if (base.startsWith("file:\\")) { 100 base = base.substring(5); 101 } 102 } 103 if (File.separatorChar != '/') { 104 base = base.replace('/', File.separatorChar); 105 } 106 return base; 107 } 108 109 112 113 public static FileOutputStream makeFileOutputStream( String baseURI, 114 String fileName, 115 boolean mkdirs) 116 throws TransformerException 117 { 118 try { 119 File file = new File(fileName); 120 121 if (!file.isAbsolute()) { 122 String base = urlToFileName(baseURI); 123 if(null != base) { 124 File baseFile = new File(base); 125 file = new File(baseFile.getParent(), fileName); 126 } 127 } 128 129 if (mkdirs) { 130 String dirStr = file.getParent(); 131 if((null != dirStr) && (dirStr.length() > 0)) { 132 File dir = new File(dirStr); 133 dir.mkdirs(); 134 } 135 } 136 137 FileOutputStream ostream = new FileOutputStream(file); 138 return ostream; 139 } catch (Exception err) { 140 throw new TransformerException ("Failed to create output file", err); 141 } 142 } 143 144 145 149 150 public Emitter makeEmitter(Properties props, Result result) 151 throws TransformerException { 152 153 Emitter emitter; 154 if (result instanceof DOMResult ) { 155 Node resultNode = ((DOMResult )result).getNode(); 156 if (resultNode!=null) { 157 if (resultNode instanceof NodeInfo) { 158 if (resultNode instanceof DocumentInfo) { 160 DocumentInfo doc = (DocumentInfo)resultNode; 161 if (resultNode.getFirstChild() != null) { 162 throw new TransformerException ("Target document must be empty"); 163 } else { 164 Builder builder; 165 if (doc instanceof DocumentImpl) { 166 builder = new TreeBuilder(); 167 } else { 168 builder = new TinyBuilder(); 169 } 170 builder.setRootNode(doc); 171 builder.setSystemId(result.getSystemId()); 172 builder.setNamePool(namePool); 173 emitter = builder; 174 } 175 } else { 176 throw new TransformerException ("Cannot add to an existing Saxon document"); 177 } 178 } else { 179 emitter = new DOMEmitter(); 181 ((DOMEmitter)emitter).setNode(resultNode); 182 } 183 } else { 184 TinyBuilder builder = new TinyBuilder(); 186 builder.setSystemId(result.getSystemId()); 187 builder.setNamePool(namePool); 188 builder.createDocument(); 189 Document resultDoc = (Document )builder.getCurrentDocument(); 190 ((DOMResult )result).setNode(resultDoc); 191 emitter = builder; 192 } 193 } else if (result instanceof SAXResult ) { 194 SAXResult sr = (SAXResult )result; 195 ContentHandlerProxy proxy = new ContentHandlerProxy(); 196 proxy.setUnderlyingContentHandler(sr.getHandler()); 197 if (sr.getLexicalHandler() != null) { 198 proxy.setLexicalHandler(sr.getLexicalHandler()); 199 } 200 emitter = proxy; 201 202 } else if (result instanceof Emitter) { 203 emitter = (Emitter)result; 204 205 } else if (result instanceof StreamResult ) { 206 207 String method = props.getProperty(OutputKeys.METHOD); 208 if (method==null) { 209 emitter = new UncommittedEmitter(); 210 211 } else if (method.equals("html")) { 212 emitter = new HTMLEmitter(); 213 if (!"no".equals(props.getProperty(OutputKeys.INDENT))) { 214 HTMLIndenter in = new HTMLIndenter(); 215 in.setUnderlyingEmitter(emitter); 216 emitter=in; 217 } 218 219 } else if (method.equals("xml")) { 220 emitter = new XMLEmitter(); 221 if ("yes".equals(props.getProperty(OutputKeys.INDENT))) { 222 XMLIndenter in = new XMLIndenter(); 223 in.setUnderlyingEmitter(emitter); 224 emitter=in; 225 } 226 String cdataElements = props.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS); 227 if (cdataElements!=null && cdataElements.length()>0) { 228 CDATAFilter filter = new CDATAFilter(); 229 filter.setUnderlyingEmitter(emitter); 230 emitter=filter; 231 } 232 } else if (method.equals("text")) { 233 emitter = new TEXTEmitter(); 234 235 } else { 236 int brace = method.indexOf('}'); 238 String localName = method.substring(brace+1); 239 int colon = localName.indexOf(':'); 240 localName = localName.substring(colon+1); 241 242 if (localName.equals("fop")) { 243 emitter = Emitter.makeEmitter("com.icl.saxon.fop.FOPEmitter"); 246 } else if (localName.equals("xhtml")) { 247 emitter = new XHTMLEmitter(); 248 if ("yes".equals(props.getProperty(OutputKeys.INDENT))) { 249 HTMLIndenter in = new HTMLIndenter(); 250 in.setUnderlyingEmitter(emitter); 251 emitter=in; 252 } 253 String cdataElements = props.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS); 254 if (cdataElements!=null && cdataElements.length()>0) { 255 CDATAFilter filter = new CDATAFilter(); 256 filter.setUnderlyingEmitter(emitter); 257 emitter=filter; 258 } 259 } else { 260 emitter = Emitter.makeEmitter(localName); 261 } 262 } 263 if (emitter.usesWriter()) { 264 writer = getStreamWriter((StreamResult )result, props); 265 emitter.setWriter(writer); 266 } else { 267 outputStream = getOutputStream((StreamResult )result, props); 268 emitter.setOutputStream(outputStream); 269 } 270 271 } else { 272 throw new IllegalArgumentException ("Unknown type of Result: " + result.getClass()); 273 } 274 275 NamespaceEmitter ne = new NamespaceEmitter(); 277 ne.setUnderlyingEmitter(emitter); 278 emitter = ne; 279 return emitter; 280 } 281 282 285 286 private Writer getStreamWriter(StreamResult result, Properties props) 287 throws TransformerException { 288 289 closeAfterUse = false; 290 Writer writer = result.getWriter(); 291 if (writer==null) { 292 OutputStream outputStream = ((StreamResult )result).getOutputStream(); 293 if (outputStream == null) { 294 String systemId = ((StreamResult )result).getSystemId(); 295 if (systemId == null) { 296 outputStream = System.out; 297 } else { 298 outputStream = makeFileOutputStream("", urlToFileName(systemId), true); 299 closeAfterUse = true; 300 } 301 } 302 303 CharacterSet charSet = CharacterSetFactory.getCharacterSet(props); 304 305 String encoding = props.getProperty(OutputKeys.ENCODING); 306 if (encoding==null) encoding = "UTF8"; 307 if (encoding.equalsIgnoreCase("utf-8")) encoding = "UTF8"; 308 310 if (charSet instanceof PluggableCharacterSet) { 311 encoding = ((PluggableCharacterSet)charSet).getEncodingName(); 312 } 313 314 while (true) { 315 try { 316 writer = new BufferedWriter( 317 new OutputStreamWriter( 318 outputStream, encoding)); 319 break; 320 } catch (Exception err) { 321 if (encoding.equalsIgnoreCase("UTF8")) { 322 throw new TransformerException ("Failed to create a UTF8 output writer"); 323 } 324 System.err.println("Encoding " + encoding + " is not supported: using UTF8"); 325 encoding = "UTF8"; 326 charSet = new UnicodeCharacterSet(); 327 props.put(OutputKeys.ENCODING, "utf-8"); 328 } 329 } 330 } else { 331 335 if (writer instanceof OutputStreamWriter) { 336 String enc = ((OutputStreamWriter)writer).getEncoding(); 337 props.put(OutputKeys.ENCODING, enc); 339 } 340 } 341 return writer; 342 } 343 344 347 348 private OutputStream getOutputStream(StreamResult result, Properties props) 349 throws TransformerException { 350 351 closeAfterUse = false; 352 353 OutputStream outputStream = ((StreamResult )result).getOutputStream(); 354 if (outputStream == null) { 355 String systemId = ((StreamResult )result).getSystemId(); 356 if (systemId == null) { 357 outputStream = System.out; 358 } else { 359 outputStream = makeFileOutputStream("", urlToFileName(systemId), true); 360 closeAfterUse = true; 361 } 362 } 363 364 if (outputStream==null) { 365 throw new TransformerException ("This output method requires a binary output destination"); 366 } 367 368 return outputStream; 369 } 370 371 372 375 376 private void setEmitter(Emitter handler) { 377 this.emitter = handler; 378 } 379 380 public void reset() throws TransformerException { 381 if (pendingStartTag != -1) flushStartTag(); 382 } 383 384 private void setOutputProperties(Properties details) throws TransformerException { 385 outputProperties = details; 386 } 387 388 public Properties getOutputProperties() { 389 return outputProperties; 390 } 391 392 398 399 char[] charbuffer = new char[1024]; 400 public void write(String s) throws TransformerException { 401 if (pendingStartTag != -1) flushStartTag(); 402 emitter.setEscaping(false); 403 int len = s.length(); 404 if (len>charbuffer.length) { 405 charbuffer = new char[len]; 406 } 407 s.getChars(0, len, charbuffer, 0); 408 emitter.characters(charbuffer, 0, len); 409 emitter.setEscaping(true); 410 } 411 412 419 420 public void writeContent(String s) throws TransformerException { 421 if (s==null) return; 422 int len = s.length(); 423 if (len>charbuffer.length) { 424 charbuffer = new char[len]; 425 } 426 s.getChars(0, len, charbuffer, 0); 427 writeContent(charbuffer, 0, len); 428 } 429 430 439 440 public void writeContent(char[] chars, int start, int length) throws TransformerException { 441 if (length==0) return; 443 if (pendingStartTag != -1) { 444 flushStartTag(); 445 } 446 emitter.characters(chars, start, length); 447 } 448 449 458 459 public void writeContent(StringBuffer chars, int start, int len) throws TransformerException { 460 if (len==0) return; 462 if (pendingStartTag != -1) { 463 flushStartTag(); 464 } 465 if (len>charbuffer.length) { 466 charbuffer = new char[len]; 467 } 468 chars.getChars(start, start+len, charbuffer, 0); 469 emitter.characters(charbuffer, 0, len); 470 } 471 472 478 479 public void writeStartTag(int nameCode) throws TransformerException { 480 482 if (nameCode==-1) { 483 suppressAttributes = true; 484 return; 485 } else { 486 suppressAttributes = false; 487 } 488 489 if (pendingStartTag != -1) flushStartTag(); 490 pendingAttList.clear(); 491 pendingNSListSize = 0; 492 pendingStartTag = nameCode; 493 494 } 498 499 506 507 public int checkAttributePrefix(int nameCode) throws TransformerException { 508 int nscode = namePool.allocateNamespaceCode(nameCode); 509 for (int i=0; i<pendingNSListSize; i++) { 510 if ((nscode>>16) == (pendingNSList[i]>>16)) { 511 if ((nscode & 0xffff) == (pendingNSList[i] & 0xffff)) { 513 return nameCode; } else { 516 String prefix = getSubstitutePrefix(nscode); 517 int newCode = namePool.allocate( 518 prefix, 519 namePool.getURI(nameCode), 520 namePool.getLocalName(nameCode)); 521 writeNamespaceDeclaration(namePool.allocateNamespaceCode(newCode)); 522 return newCode; 523 } 524 } 525 } 526 writeNamespaceDeclaration(nscode); 528 return nameCode; 529 } 530 531 541 542 public void writeNamespaceDeclaration(int nscode) 543 throws TransformerException { 544 545 if (suppressAttributes) return; 546 547 if (pendingStartTag==-1) { 549 throw new TransformerException ("Cannot write a namespace declaration when there is no open start tag"); 550 } 551 552 555 557 for (int i=0; i<pendingNSListSize; i++) { 558 if ((nscode>>16) == (pendingNSList[i]>>16)) { 559 return; 561 } 562 } 563 564 566 if (pendingNSListSize+1 > pendingNSList.length) { 567 int[] newlist = new int[pendingNSListSize * 2]; 568 System.arraycopy(pendingNSList, 0, newlist, 0, pendingNSListSize); 569 pendingNSList = newlist; 570 } 571 pendingNSList[pendingNSListSize++] = nscode; 572 } 573 574 578 579 public void copyNamespaceNode(int nscode) throws TransformerException { 580 if (pendingStartTag==-1) { 581 throw new TransformerException ("Cannot copy a namespace node when there is no containing element node"); 582 } 583 if (pendingAttList.getLength()>0) { 584 throw new TransformerException ("Cannot copy a namespace node to an element after attributes have been added"); 585 } 586 587 for (int i=0; i<pendingNSListSize; i++) { 589 if ((nscode>>16) == (pendingNSList[i]>>16)) { 590 if (nscode==pendingNSList[i]) { return; } else { 594 throw new TransformerException ("Cannot create two namespace nodes with the same name"); 596 } 597 } 598 } 599 writeNamespaceDeclaration(nscode); 600 } 601 602 608 609 private String getSubstitutePrefix(int nscode) { 610 String prefix = namePool.getPrefixFromNamespaceCode(nscode); 611 return prefix + "." + (nscode&0xffff); 612 } 613 614 618 619 public boolean thereIsAnOpenStartTag() { 620 return (pendingStartTag != -1); 621 } 622 623 633 634 public void writeAttribute(int nameCode, String value) throws TransformerException { 635 writeAttribute(nameCode, value, false); 636 } 637 638 652 653 public void writeAttribute(int nameCode, String value, boolean noEscape) throws TransformerException { 654 655 if (suppressAttributes) return; 656 657 if (pendingStartTag==-1) { 659 throw new TransformerException ("Cannot write an attribute when there is no open start tag"); 660 } 661 662 pendingAttList.setAttribute(nameCode, 663 (noEscape ? "NO-ESC" : "CDATA"), value); 665 666 } 667 668 669 673 674 public void writeEndTag(int nameCode) throws TransformerException { 675 if (pendingStartTag != -1) { 677 flushStartTag(); 678 } 679 680 emitter.endElement(nameCode); 682 } 683 684 687 688 public void writeComment(String comment) throws TransformerException { 689 if (pendingStartTag != -1) flushStartTag(); 690 emitter.comment(comment.toCharArray(), 0, comment.length()); 691 } 692 693 696 697 public void writePI(String target, String data) throws TransformerException { 698 if (pendingStartTag != -1) flushStartTag(); 699 emitter.processingInstruction(target, data); 700 } 701 702 705 706 public void close() throws TransformerException { 707 emitter.endDocument(); 709 if (closeAfterUse) { 710 try { 711 if (writer != null) { 712 writer.close(); 713 } 714 if (outputStream != null) { 715 outputStream.close(); 716 } 717 } catch (java.io.IOException err) { 718 throw new TransformerException (err); 719 } 720 } 721 } 722 723 726 727 protected void flushStartTag() throws TransformerException { 728 emitter.startElement(pendingStartTag, pendingAttList, 729 pendingNSList, pendingNSListSize); 730 pendingNSListSize = 0; 731 pendingStartTag = -1; 732 733 } 734 735 } 736 737 | Popular Tags |