001: package net.sf.saxon.event;
002:
003: import net.sf.saxon.charcode.UnicodeCharacterSet;
004: import net.sf.saxon.om.XMLChar;
005: import net.sf.saxon.om.FastStringBuffer;
006: import net.sf.saxon.trans.DynamicError;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.tinytree.CharSlice;
009: import net.sf.saxon.value.Whitespace;
010:
011: import javax.xml.transform.OutputKeys;
012: import javax.xml.transform.TransformerException;
013: import javax.xml.transform.TransformerFactory;
014: import javax.xml.transform.Templates;
015: import javax.xml.transform.stream.StreamResult;
016: import javax.xml.transform.stream.StreamSource;
017: import java.util.Stack;
018: import java.io.CharArrayWriter;
019: import java.io.File;
020:
021: /**
022: * XMLEmitter is an Emitter that generates XML output
023: * to a specified destination.
024: */
025:
026: public class XMLEmitter extends Emitter {
027: protected boolean empty = true;
028: protected boolean openStartTag = false;
029: protected boolean declarationIsWritten = false;
030: protected int elementCode;
031:
032: protected boolean preferHex = false;
033: protected boolean undeclareNamespaces = false;
034: private boolean warningIssued = false;
035:
036: // The element stack holds the display names (lexical QNames) of elements that
037: // have been started but not finished. It is used to obtain the element name
038: // for the end tag.
039:
040: protected Stack elementStack = new Stack();
041:
042: // Namecodes in the range 0..2048 are common. So for these codes,
043: // we maintain a direct lookup from the namecode to the display name
044: // that bypasses reference to the namepool
045:
046: private String[] nameLookup = new String[2048];
047:
048: private boolean indenting = false;
049: private int indentSpaces = 3;
050: private String indentChars = "\n ";
051: private int totalAttributeLength = 0;
052: private boolean requireWellFormed = false;
053:
054: static boolean[] specialInText; // lookup table for special characters in text
055: static boolean[] specialInAtt; // lookup table for special characters in attributes
056: // create look-up table for ASCII characters that need special treatment
057:
058: static {
059: specialInText = new boolean[128];
060: for (int i = 0; i <= 31; i++)
061: specialInText[i] = true; // allowed in XML 1.1 as character references
062: for (int i = 32; i <= 127; i++)
063: specialInText[i] = false;
064: specialInText[(char) 0] = true;
065: // used to switch escaping on and off for mapped characters
066: specialInText['\n'] = false;
067: specialInText['\t'] = false;
068: specialInText['\r'] = true;
069: specialInText['<'] = true;
070: specialInText['>'] = true;
071: specialInText['&'] = true;
072:
073: specialInAtt = new boolean[128];
074: for (int i = 0; i <= 15; i++)
075: specialInAtt[i] = true; // allowed in XML 1.1 as character references
076: for (int i = 16; i <= 127; i++)
077: specialInAtt[i] = false;
078: specialInAtt[(char) 0] = true;
079: // used to switch escaping on and off for mapped characters
080: specialInAtt['\r'] = true;
081: specialInAtt['\n'] = true;
082: specialInAtt['\t'] = true;
083: specialInAtt['<'] = true;
084: specialInAtt['>'] = true;
085: specialInAtt['&'] = true;
086: specialInAtt['\"'] = true;
087: }
088:
089: /**
090: * Start of the event stream. Nothing is done at this stage: the opening of the output
091: * file is deferred until some content is written to it.
092: */
093:
094: public void open() throws XPathException {
095: }
096:
097: /**
098: * Start of a document node. Nothing is done at this stage: the opening of the output
099: * file is deferred until some content is written to it.
100: */
101:
102: public void startDocument(int properties) throws XPathException {
103: }
104:
105: /**
106: * Notify the end of a document node
107: */
108:
109: public void endDocument() throws XPathException {
110: if (!elementStack.isEmpty()) {
111: throw new IllegalStateException(
112: "Attempt to end document in serializer when elements are unclosed");
113: }
114: }
115:
116: /**
117: * Do the real work of starting the document. This happens when the first
118: * content is written.
119: * @throws XPathException
120: */
121:
122: protected void openDocument() throws XPathException {
123: if (writer == null) {
124: makeWriter();
125: }
126: if (characterSet == null) {
127: characterSet = UnicodeCharacterSet.getInstance();
128: }
129: String rep = outputProperties
130: .getProperty(SaxonOutputKeys.CHARACTER_REPRESENTATION);
131: if (rep != null) {
132: preferHex = (rep.trim().equalsIgnoreCase("hex"));
133: }
134: rep = outputProperties
135: .getProperty(SaxonOutputKeys.UNDECLARE_PREFIXES);
136: if (rep != null) {
137: undeclareNamespaces = (rep.trim().equalsIgnoreCase("yes"));
138: }
139: writeDeclaration();
140: }
141:
142: /**
143: * Output the XML declaration
144: */
145:
146: public void writeDeclaration() throws XPathException {
147: if (declarationIsWritten)
148: return;
149: declarationIsWritten = true;
150: try {
151: indenting = "yes".equals(outputProperties
152: .getProperty(OutputKeys.INDENT));
153: String s = outputProperties
154: .getProperty(SaxonOutputKeys.INDENT_SPACES);
155: if (s != null) {
156: try {
157: indentSpaces = Integer.parseInt(s.trim());
158: } catch (NumberFormatException err) {
159: }
160: }
161:
162: String byteOrderMark = outputProperties
163: .getProperty(SaxonOutputKeys.BYTE_ORDER_MARK);
164:
165: if ("yes".equals(byteOrderMark)
166: && "UTF-8".equalsIgnoreCase(outputProperties
167: .getProperty(OutputKeys.ENCODING))) {
168: // For UTF-16, Java outputs a BOM whether we like it or not
169: writer.write('\uFEFF');
170: }
171:
172: String omitXMLDeclaration = outputProperties
173: .getProperty(OutputKeys.OMIT_XML_DECLARATION);
174: if (omitXMLDeclaration == null) {
175: omitXMLDeclaration = "no";
176: }
177:
178: String version = outputProperties
179: .getProperty(OutputKeys.VERSION);
180: if (version == null) {
181: version = getConfiguration().getNameChecker()
182: .getXMLVersion();
183: } else {
184: if (!version.equals("1.0") && !version.equals("1.1")) {
185: DynamicError err = new DynamicError(
186: "XML version must be 1.0 or 1.1");
187: err.setErrorCode("SESU0006");
188: throw err;
189: }
190: if (!version.equals("1.0")
191: && omitXMLDeclaration.equals("yes")
192: && outputProperties
193: .getProperty(OutputKeys.DOCTYPE_SYSTEM) != null) {
194: DynamicError err = new DynamicError(
195: "Values of 'version', 'omit-xml-declaration', and 'doctype-system' conflict");
196: err.setErrorCode("SEPM0009");
197: throw err;
198: }
199: }
200:
201: if (version.equals("1.0") && undeclareNamespaces) {
202: DynamicError err = new DynamicError(
203: "Cannot undeclare namespaces with XML version 1.0");
204: err.setErrorCode("SEPM0010");
205: throw err;
206: }
207:
208: String encoding = outputProperties
209: .getProperty(OutputKeys.ENCODING);
210: if (encoding == null || encoding.equalsIgnoreCase("utf8")) {
211: encoding = "UTF-8";
212: }
213:
214: String standalone = outputProperties
215: .getProperty(OutputKeys.STANDALONE);
216: if ("omit".equals(standalone)) {
217: standalone = null;
218: }
219:
220: if (standalone != null) {
221: requireWellFormed = true;
222: if (omitXMLDeclaration.equals("yes")) {
223: DynamicError err = new DynamicError(
224: "Values of 'standalone' and 'omit-xml-declaration' conflict");
225: err.setErrorCode("SEPM0009");
226: throw err;
227: }
228: }
229:
230: if (omitXMLDeclaration.equals("no")) {
231: writer.write("<?xml version=\""
232: + version
233: + "\" "
234: + "encoding=\""
235: + encoding
236: + '\"'
237: + (standalone != null ? " standalone=\""
238: + standalone + '\"' : "") + "?>");
239: // no longer write a newline character: it's wrong if the output is an
240: // external general parsed entity
241: }
242: } catch (java.io.IOException err) {
243: throw new DynamicError(err);
244: }
245: }
246:
247: /**
248: * Output the document type declaration
249: */
250:
251: protected void writeDocType(String type, String systemId,
252: String publicId) throws XPathException {
253: try {
254: if (declarationIsWritten && !indenting) {
255: // don't add a newline if indenting, because the indenter will already have done so
256: writer.write("\n");
257: }
258: writer.write("<!DOCTYPE " + type + '\n');
259: if (systemId != null && publicId == null) {
260: writer.write(" SYSTEM \"" + systemId + "\">\n");
261: } else if (systemId == null && publicId != null) { // handles the HTML case
262: writer.write(" PUBLIC \"" + publicId + "\">\n");
263: } else {
264: writer.write(" PUBLIC \"" + publicId + "\" \""
265: + systemId + "\">\n");
266: }
267: } catch (java.io.IOException err) {
268: throw new DynamicError(err);
269: }
270: }
271:
272: /**
273: * End of the document. Close the output stream.
274: */
275:
276: public void close() throws XPathException {
277: try {
278: if (writer != null) {
279: writer.flush();
280: }
281: } catch (java.io.IOException err) {
282: throw new DynamicError(err);
283: }
284: }
285:
286: /**
287: * Start of an element. Output the start tag, escaping special characters.
288: */
289:
290: public void startElement(int nameCode, int typeCode,
291: int locationId, int properties) throws XPathException {
292: if (empty) {
293: openDocument();
294: } else if (requireWellFormed && elementStack.isEmpty()) {
295: DynamicError err = new DynamicError(
296: "When 'standalone' or 'doctype-system' is specified, the document must be well-formed; "
297: + "but this document contains more than one top-level element");
298: err.setErrorCode("SEPM0004");
299: throw err;
300: }
301: String displayName = null;
302:
303: // See if we've seen this name before
304: if (nameCode < 2048) {
305: displayName = nameLookup[nameCode];
306: }
307:
308: // Otherwise, look it up in the namepool and check that it's encodable
309: if (displayName == null) {
310: displayName = namePool.getDisplayName(nameCode);
311: if (nameCode < 2048) {
312: nameLookup[nameCode] = displayName;
313: }
314: int badchar = testCharacters(displayName);
315: if (badchar != 0) {
316: DynamicError err = new DynamicError(
317: "Element name contains a character (decimal + "
318: + badchar
319: + ") not available in the selected encoding");
320: err.setErrorCode("SERE0008");
321: throw err;
322: }
323: }
324:
325: elementStack.push(displayName);
326: elementCode = nameCode;
327:
328: try {
329: if (empty) {
330: String systemId = outputProperties
331: .getProperty(OutputKeys.DOCTYPE_SYSTEM);
332: String publicId = outputProperties
333: .getProperty(OutputKeys.DOCTYPE_PUBLIC);
334: if (systemId != null) {
335: requireWellFormed = true;
336: writeDocType(displayName, systemId, publicId);
337: }
338: empty = false;
339: }
340: if (openStartTag) {
341: closeStartTag();
342: }
343: writer.write('<');
344: writer.write(displayName);
345: openStartTag = true;
346: totalAttributeLength = 0;
347:
348: } catch (java.io.IOException err) {
349: throw new DynamicError(err);
350: }
351: }
352:
353: public void namespace(int namespaceCode, int properties)
354: throws XPathException {
355: try {
356: String nsprefix = namePool
357: .getPrefixFromNamespaceCode(namespaceCode);
358: String nsuri = namePool
359: .getURIFromNamespaceCode(namespaceCode);
360:
361: int len = nsuri.length() + nsprefix.length() + 8;
362: String sep = " ";
363: if (indenting && (totalAttributeLength + len) > 80
364: && totalAttributeLength != 0) {
365: sep = getAttributeIndentString();
366: }
367: totalAttributeLength += len;
368:
369: if (nsprefix.equals("")) {
370: writer.write(sep);
371: writeAttribute(elementCode, "xmlns", nsuri, 0);
372: } else if (nsprefix.equals("xml")) {
373: return;
374: } else {
375: int badchar = testCharacters(nsprefix);
376: if (badchar != 0) {
377: DynamicError err = new DynamicError(
378: "Namespace prefix contains a character (decimal + "
379: + badchar
380: + ") not available in the selected encoding");
381: err.setErrorCode("SERE0008");
382: throw err;
383: }
384: if (undeclareNamespaces || !nsuri.equals("")) {
385: writer.write(sep);
386: writeAttribute(elementCode, "xmlns:" + nsprefix,
387: nsuri, 0);
388: }
389: }
390: } catch (java.io.IOException err) {
391: throw new DynamicError(err);
392: }
393: }
394:
395: public void attribute(int nameCode, int typeCode,
396: CharSequence value, int locationId, int properties)
397: throws XPathException {
398: String displayName = null;
399:
400: // See if we've seen this name before
401: if (nameCode < 2048) {
402: displayName = nameLookup[nameCode];
403: }
404:
405: // Otherwise, look it up in the namepool and check that it's encodable
406: if (displayName == null) {
407: displayName = namePool.getDisplayName(nameCode);
408: if (nameCode < 2048) {
409: nameLookup[nameCode] = displayName;
410: }
411: int badchar = testCharacters(displayName);
412: if (badchar != 0) {
413: DynamicError err = new DynamicError(
414: "Attribute name contains a character (decimal + "
415: + badchar
416: + ") not available in the selected encoding");
417: err.setErrorCode("SERE0008");
418: throw err;
419: }
420: }
421:
422: int len = displayName.length() + value.length() + 4;
423: String sep = " ";
424: if (indenting && (totalAttributeLength + len) > 80
425: && totalAttributeLength != 0) {
426: sep = getAttributeIndentString();
427: }
428: totalAttributeLength += len;
429:
430: try {
431: writer.write(sep);
432: writeAttribute(elementCode, displayName, value, properties);
433:
434: } catch (java.io.IOException err) {
435: throw new DynamicError(err);
436: }
437: }
438:
439: private String getAttributeIndentString() {
440: int indent = (elementStack.size() - 1) * indentSpaces
441: + ((String) elementStack.peek()).length() + 3;
442: while (indent >= indentChars.length()) {
443: indentChars += " ";
444: }
445: return indentChars.substring(0, indent);
446: }
447:
448: public void startContent() throws XPathException {
449: // don't add ">" to the start tag until we know whether the element has content
450: }
451:
452: public void closeStartTag() throws XPathException {
453: try {
454: if (openStartTag) {
455: writer.write('>');
456: openStartTag = false;
457: }
458: } catch (java.io.IOException err) {
459: throw new DynamicError(err);
460: }
461: }
462:
463: /**
464: * Close an empty element tag. (This is overridden in XHTMLEmitter).
465: */
466:
467: protected String emptyElementTagCloser(String displayName,
468: int nameCode) {
469: return "/>";
470: }
471:
472: /**
473: * Write attribute name=value pair.
474: * @param elCode The element name is not used in this version of the
475: * method, but is used in the HTML subclass.
476: * @param attname The attribute name, which has already been validated to ensure
477: * it can be written in this encoding
478: * @param value The value of the attribute
479: * @param properties Any special properties of the attribute
480: */
481:
482: protected void writeAttribute(int elCode, String attname,
483: CharSequence value, int properties) throws XPathException {
484: try {
485: String val = value.toString();
486: writer.write(attname);
487: if ((properties & ReceiverOptions.NO_SPECIAL_CHARS) != 0) {
488: writer.write('=');
489: writer.write('"');
490: writer.write(val);
491: writer.write('"');
492: } else if ((properties & ReceiverOptions.USE_NULL_MARKERS) != 0) {
493: // null (0) characters will be used before and after any section of
494: // the value where escaping is to be disabled
495: writer.write('=');
496: char delimiter = (val.indexOf('"') >= 0 ? '\'' : '"');
497: writer.write(delimiter);
498: writeEscape(value, true);
499: writer.write(delimiter);
500: } else {
501: writer.write("=\"");
502: writeEscape(value, true);
503: writer.write('\"');
504: }
505: } catch (java.io.IOException err) {
506: throw new DynamicError(err);
507: }
508: }
509:
510: /**
511: * Test that all characters in a name are supported in the target encoding.
512: * @return zero if all the characters are available, or the value of the
513: * first offending character if not
514: */
515:
516: protected int testCharacters(CharSequence chars)
517: throws XPathException {
518: for (int i = 0; i < chars.length(); i++) {
519: char c = chars.charAt(i);
520: if (c > 127) {
521: if (XMLChar.isHighSurrogate(c)) {
522: int cc = XMLChar.supplemental(c, chars.charAt(++i));
523: if (!characterSet.inCharset(cc)) {
524: return cc;
525: }
526: } else if (!characterSet.inCharset(c)) {
527: return c;
528: }
529: }
530: }
531: return 0;
532: }
533:
534: /**
535: * End of an element.
536: */
537:
538: public void endElement() throws XPathException {
539: String displayName = (String) elementStack.pop();
540: try {
541: if (openStartTag) {
542: writer.write(emptyElementTagCloser(displayName,
543: elementCode));
544: openStartTag = false;
545: } else {
546: writer.write("</");
547: writer.write(displayName);
548: writer.write('>');
549: }
550: } catch (java.io.IOException err) {
551: throw new DynamicError(err);
552: }
553: }
554:
555: /**
556: * Character data.
557: */
558:
559: public void characters(CharSequence chars, int locationId,
560: int properties) throws XPathException {
561: if (empty) {
562: openDocument();
563: if (!Whitespace.isWhite(chars)) {
564: if (requireWellFormed
565: || outputProperties
566: .getProperty(OutputKeys.DOCTYPE_SYSTEM) != null) {
567: DynamicError err = new DynamicError(
568: "When 'standalone' or 'doctype-system' is specified, the document must be well-formed; "
569: + "but this document contains a top-level text node");
570: err.setErrorCode("SEPM0004");
571: throw err;
572: }
573: }
574: }
575:
576: if (requireWellFormed && elementStack.isEmpty()
577: && !Whitespace.isWhite(chars)) {
578: DynamicError err = new DynamicError(
579: "When 'standalone' or 'doctype-system' is specified, the document must be well-formed; "
580: + "but this document contains a top-level text node");
581: err.setErrorCode("SEPM0004");
582: throw err;
583: }
584:
585: try {
586: if (openStartTag) {
587: closeStartTag();
588: }
589:
590: if ((properties & ReceiverOptions.NO_SPECIAL_CHARS) != 0) {
591: writeCharSequence(chars);
592: } else if ((properties & ReceiverOptions.DISABLE_ESCAPING) == 0) {
593: writeEscape(chars, false);
594: } else {
595: // disable-output-escaping="yes"
596: if (testCharacters(chars) == 0) {
597: writeCharSequence(chars);
598: } else {
599: // Recoverable error: using disable output escaping with characters
600: // that are not available in the target encoding
601: if (!warningIssued) {
602: try {
603: getPipelineConfiguration()
604: .getErrorListener()
605: .warning(
606: new TransformerException(
607: "disable-output-escaping is ignored for characters "
608: + "not available in the chosen encoding"));
609: } catch (TransformerException e) {
610: throw DynamicError.makeDynamicError(e);
611: }
612: warningIssued = true;
613: }
614: writeEscape(chars, false);
615: }
616: }
617: } catch (java.io.IOException err) {
618: throw new DynamicError(err);
619: }
620: }
621:
622: /**
623: * Write a CharSequence: various implementations
624: */
625:
626: public void writeCharSequence(CharSequence s)
627: throws java.io.IOException {
628: if (s instanceof String) {
629: writer.write((String) s);
630: } else if (s instanceof CharSlice) {
631: ((CharSlice) s).write(writer);
632: } else if (s instanceof FastStringBuffer) {
633: ((FastStringBuffer) s).write(writer);
634: } else {
635: writer.write(s.toString());
636: }
637: }
638:
639: /**
640: * Handle a processing instruction.
641: */
642:
643: public void processingInstruction(String target, CharSequence data,
644: int locationId, int properties) throws XPathException {
645: if (empty) {
646: openDocument();
647: }
648: try {
649: if (openStartTag) {
650: closeStartTag();
651: }
652: writer.write("<?" + target
653: + (data.length() > 0 ? ' ' + data.toString() : "")
654: + "?>");
655: } catch (java.io.IOException err) {
656: throw new DynamicError(err);
657: }
658: }
659:
660: /**
661: * Write contents of array to current writer, after escaping special characters.
662: * This method converts the XML special characters (such as < and &) into their
663: * predefined entities.
664: * @param chars The character sequence containing the string
665: * @param inAttribute Set to true if the text is in an attribute value
666: */
667:
668: protected void writeEscape(final CharSequence chars,
669: final boolean inAttribute) throws java.io.IOException,
670: XPathException {
671: int segstart = 0;
672: boolean disabled = false;
673: final boolean[] specialChars = (inAttribute ? specialInAtt
674: : specialInText);
675:
676: while (segstart < chars.length()) {
677: int i = segstart;
678:
679: // find a maximal sequence of "ordinary" characters
680: while (i < chars.length()) {
681: final char c = chars.charAt(i);
682: if (c < 127) {
683: if (specialChars[c]) {
684: break;
685: } else {
686: i++;
687: }
688: } else if (c < 160) {
689: break;
690: } else if (XMLChar.isHighSurrogate(c)) {
691: break;
692: } else if (!characterSet.inCharset(c)) {
693: break;
694: } else {
695: i++;
696: }
697: }
698:
699: // if this was the whole string write it out and exit
700: if (i >= chars.length()) {
701: if (segstart == 0) {
702: writeCharSequence(chars);
703: } else {
704: writeCharSequence(chars.subSequence(segstart, i));
705: }
706: return;
707: }
708:
709: // otherwise write out this sequence
710: if (i > segstart) {
711: writeCharSequence(chars.subSequence(segstart, i));
712: }
713:
714: // examine the special character that interrupted the scan
715: final char c = chars.charAt(i);
716: if (c == 0) {
717: // used to switch escaping on and off
718: disabled = !disabled;
719: } else if (disabled) {
720: writer.write(c);
721: } else if (c >= 127 && c < 160) {
722: // XML 1.1 requires these characters to be written as character references
723: outputCharacterReference(c);
724: } else if (c >= 160) {
725: if (XMLChar.isHighSurrogate(c)) {
726: char d = chars.charAt(++i);
727: int charval = XMLChar.supplemental(c, d);
728: if (characterSet.inCharset(charval)) {
729: writer.write(c);
730: writer.write(d);
731: } else {
732: outputCharacterReference(charval);
733: }
734: } else {
735: // process characters not available in the current encoding
736: outputCharacterReference(c);
737: }
738:
739: } else {
740:
741: // process special ASCII characters
742:
743: if (c == '<') {
744: writer.write("<");
745: } else if (c == '>') {
746: writer.write(">");
747: } else if (c == '&') {
748: writer.write("&");
749: } else if (c == '\"') {
750: writer.write(""");
751: } else if (c == '\n') {
752: writer.write("
");
753: } else if (c == '\r') {
754: writer.write("
");
755: } else if (c == '\t') {
756: writer.write("	");
757: } else {
758: // C0 control characters
759: outputCharacterReference(c);
760: }
761: }
762: segstart = ++i;
763: }
764: }
765:
766: /**
767: * Output a decimal or hexadecimal character reference
768: */
769:
770: private char[] charref = new char[10];
771:
772: protected void outputCharacterReference(int charval)
773: throws java.io.IOException {
774: if (preferHex) {
775: int o = 0;
776: charref[o++] = '&';
777: charref[o++] = '#';
778: charref[o++] = 'x';
779: String code = Integer.toHexString(charval);
780: int len = code.length();
781: for (int k = 0; k < len; k++) {
782: charref[o++] = code.charAt(k);
783: }
784: charref[o++] = ';';
785: writer.write(charref, 0, o);
786: } else {
787: int o = 0;
788: charref[o++] = '&';
789: charref[o++] = '#';
790: String code = Integer.toString(charval);
791: int len = code.length();
792: for (int k = 0; k < len; k++) {
793: charref[o++] = code.charAt(k);
794: }
795: charref[o++] = ';';
796: writer.write(charref, 0, o);
797: }
798: }
799:
800: /**
801: * Handle a comment.
802: */
803:
804: public void comment(CharSequence chars, int locationId,
805: int properties) throws XPathException {
806: if (empty) {
807: openDocument();
808: }
809: try {
810: if (openStartTag) {
811: closeStartTag();
812: }
813: writer.write("<!--");
814: writer.write(chars.toString());
815: writer.write("-->");
816: } catch (java.io.IOException err) {
817: throw new DynamicError(err);
818: }
819: }
820:
821: public static void main(String[] params) throws Exception {
822: StreamResult iStreamResult = new StreamResult(
823: new CharArrayWriter());
824: XMLEmitter iResult = new XMLEmitter();
825: iResult.setStreamResult(iStreamResult);
826:
827: StreamSource iSource = new StreamSource(new File(
828: "c:\\temp\\test.xml"));
829:
830: System.setProperty("javax.xml.transform.TransformerFactory",
831: "net.sf.saxon.TransformerFactoryImpl");
832: TransformerFactory iTfactory = TransformerFactory.newInstance();
833: Templates iTemplates = iTfactory.newTemplates(new StreamSource(
834: new File("c:\\temp\\test.xsl")));
835: iTemplates.newTransformer().transform(iSource, iResult);
836:
837: }
838:
839: }
840:
841: //
842: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
843: // you may not use this file except in compliance with the License. You may obtain a copy of the
844: // License at http://www.mozilla.org/MPL/
845: //
846: // Software distributed under the License is distributed on an "AS IS" basis,
847: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
848: // See the License for the specific language governing rights and limitations under the License.
849: //
850: // The Original Code is: all this file.
851: //
852: // The Initial Developer of the Original Code is Michael H. Kay.
853: //
854: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
855: //
856: // Contributor(s): none.
857: //
|