0001: /*
0002: * Copyright 1999-2004 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: /*
0017: * $Id: ToUnknownStream.java,v 1.12 2005/04/07 04:29:03 minchau Exp $
0018: */
0019: package org.apache.xml.serializer;
0020:
0021: import java.io.IOException;
0022: import java.io.OutputStream;
0023: import java.io.Writer;
0024: import java.util.Properties;
0025: import java.util.Vector;
0026:
0027: import javax.xml.transform.SourceLocator;
0028: import javax.xml.transform.Transformer;
0029:
0030: import org.w3c.dom.Node;
0031: import org.xml.sax.Attributes;
0032: import org.xml.sax.ContentHandler;
0033: import org.xml.sax.Locator;
0034: import org.xml.sax.SAXException;
0035:
0036: /**
0037: *This class wraps another SerializationHandler. The wrapped object will either
0038: * handler XML or HTML, which is not known until a little later when the first XML
0039: * tag is seen. If the first tag is <html> then the wrapped object is an HTML
0040: * handler, otherwise it is an XML handler.
0041: *
0042: * This class effectively caches the first few calls to it then passes them
0043: * on to the wrapped handler (once it exists). After that subsequent calls a
0044: * simply passed directly to the wrapped handler.
0045: *
0046: * The user of this class doesn't know if the output is ultimatley XML or HTML.
0047: *
0048: * This class is not a public API, it is public because it is used within Xalan.
0049: * @xsl.usage internal
0050: */
0051: public final class ToUnknownStream extends SerializerBase {
0052:
0053: /**
0054: * The wrapped handler, initially XML but possibly switched to HTML
0055: */
0056: private SerializationHandler m_handler;
0057:
0058: /**
0059: * A String with no characters
0060: */
0061: private static final String EMPTYSTRING = "";
0062:
0063: /**
0064: * true if the underlying handler (XML or HTML) is fully initialized
0065: */
0066: private boolean m_wrapped_handler_not_initialized = false;
0067:
0068: /**
0069: * the prefix of the very first tag in the document
0070: */
0071: private String m_firstElementPrefix;
0072: /**
0073: * the element name (including any prefix) of the very first tag in the document
0074: */
0075: private String m_firstElementName;
0076:
0077: /**
0078: * the namespace URI associated with the first element
0079: */
0080: private String m_firstElementURI;
0081:
0082: /**
0083: * the local name (no prefix) associated with the first element
0084: */
0085: private String m_firstElementLocalName = null;
0086:
0087: /**
0088: * true if the first tag has been emitted to the wrapped handler
0089: */
0090: private boolean m_firstTagNotEmitted = true;
0091:
0092: /**
0093: * A collection of namespace URI's (only for first element).
0094: * _namespacePrefix has the matching prefix for these URI's
0095: */
0096: private Vector m_namespaceURI = null;
0097: /**
0098: * A collection of namespace Prefix (only for first element)
0099: * _namespaceURI has the matching URIs for these prefix'
0100: */
0101: private Vector m_namespacePrefix = null;
0102:
0103: /**
0104: * true if startDocument() was called before the underlying handler
0105: * was initialized
0106: */
0107: private boolean m_needToCallStartDocument = false;
0108: /**
0109: * true if setVersion() was called before the underlying handler
0110: * was initialized
0111: */
0112: private boolean m_setVersion_called = false;
0113: /**
0114: * true if setDoctypeSystem() was called before the underlying handler
0115: * was initialized
0116: */
0117: private boolean m_setDoctypeSystem_called = false;
0118: /**
0119: * true if setDoctypePublic() was called before the underlying handler
0120: * was initialized
0121: */
0122: private boolean m_setDoctypePublic_called = false;
0123: /**
0124: * true if setMediaType() was called before the underlying handler
0125: * was initialized
0126: */
0127: private boolean m_setMediaType_called = false;
0128:
0129: /**
0130: * Default constructor.
0131: * Initially this object wraps an XML Stream object, so _handler is never null.
0132: * That may change later to an HTML Stream object.
0133: */
0134: public ToUnknownStream() {
0135: m_handler = new ToXMLStream();
0136: }
0137:
0138: /**
0139: * @see Serializer#asContentHandler()
0140: * @return the wrapped XML or HTML handler
0141: */
0142: public ContentHandler asContentHandler() throws IOException {
0143: /* don't return the real handler ( m_handler ) because
0144: * that would expose the real handler to the outside.
0145: * Keep m_handler private so it can be internally swapped
0146: * to an HTML handler.
0147: */
0148: return this ;
0149: }
0150:
0151: /**
0152: * @see SerializationHandler#close()
0153: */
0154: public void close() {
0155: m_handler.close();
0156: }
0157:
0158: /**
0159: * @see Serializer#getOutputFormat()
0160: * @return the properties of the underlying handler
0161: */
0162: public Properties getOutputFormat() {
0163: return m_handler.getOutputFormat();
0164: }
0165:
0166: /**
0167: * @see Serializer#getOutputStream()
0168: * @return the OutputStream of the underlying XML or HTML handler
0169: */
0170: public OutputStream getOutputStream() {
0171: return m_handler.getOutputStream();
0172: }
0173:
0174: /**
0175: * @see Serializer#getWriter()
0176: * @return the Writer of the underlying XML or HTML handler
0177: */
0178: public Writer getWriter() {
0179: return m_handler.getWriter();
0180: }
0181:
0182: /**
0183: * passes the call on to the underlying HTML or XML handler
0184: * @see Serializer#reset()
0185: * @return ???
0186: */
0187: public boolean reset() {
0188: return m_handler.reset();
0189: }
0190:
0191: /**
0192: * Converts the DOM node to output
0193: * @param node the DOM node to transform to output
0194: * @see DOMSerializer#serialize(Node)
0195: *
0196: */
0197: public void serialize(Node node) throws IOException {
0198: if (m_firstTagNotEmitted) {
0199: flush();
0200: }
0201: m_handler.serialize(node);
0202: }
0203:
0204: /**
0205: * @see SerializationHandler#setEscaping(boolean)
0206: */
0207: public boolean setEscaping(boolean escape) throws SAXException {
0208: return m_handler.setEscaping(escape);
0209: }
0210:
0211: /**
0212: * Set the properties of the handler
0213: * @param format the output properties to set
0214: * @see Serializer#setOutputFormat(Properties)
0215: */
0216: public void setOutputFormat(Properties format) {
0217: m_handler.setOutputFormat(format);
0218: }
0219:
0220: /**
0221: * Sets the output stream to write to
0222: * @param output the OutputStream to write to
0223: * @see Serializer#setOutputStream(OutputStream)
0224: */
0225: public void setOutputStream(OutputStream output) {
0226: m_handler.setOutputStream(output);
0227: }
0228:
0229: /**
0230: * Sets the writer to write to
0231: * @param writer the writer to write to
0232: * @see Serializer#setWriter(Writer)
0233: */
0234: public void setWriter(Writer writer) {
0235: m_handler.setWriter(writer);
0236: }
0237:
0238: /**
0239: * Adds an attribute to the currenly open tag
0240: * @param uri the URI of a namespace
0241: * @param localName the attribute name, without prefix
0242: * @param rawName the attribute name, with prefix (if any)
0243: * @param type the type of the attribute, typically "CDATA"
0244: * @param value the value of the parameter
0245: * @param XSLAttribute true if this attribute is coming from an xsl:attribute element
0246: * @see ExtendedContentHandler#addAttribute(String, String, String, String, String)
0247: */
0248: public void addAttribute(String uri, String localName,
0249: String rawName, String type, String value,
0250: boolean XSLAttribute) throws SAXException {
0251: if (m_firstTagNotEmitted) {
0252: flush();
0253: }
0254: m_handler.addAttribute(uri, localName, rawName, type, value,
0255: XSLAttribute);
0256: }
0257:
0258: /**
0259: * Adds an attribute to the currenly open tag
0260: * @param rawName the attribute name, with prefix (if any)
0261: * @param value the value of the parameter
0262: * @see ExtendedContentHandler#addAttribute(String, String)
0263: */
0264: public void addAttribute(String rawName, String value) {
0265: if (m_firstTagNotEmitted) {
0266: flush();
0267: }
0268: m_handler.addAttribute(rawName, value);
0269:
0270: }
0271:
0272: /**
0273: * Adds a unique attribute to the currenly open tag
0274: */
0275: public void addUniqueAttribute(String rawName, String value,
0276: int flags) throws SAXException {
0277: if (m_firstTagNotEmitted) {
0278: flush();
0279: }
0280: m_handler.addUniqueAttribute(rawName, value, flags);
0281:
0282: }
0283:
0284: /**
0285: * Converts the String to a character array and calls the SAX method
0286: * characters(char[],int,int);
0287: *
0288: * @see ExtendedContentHandler#characters(String)
0289: */
0290: public void characters(String chars) throws SAXException {
0291: final int length = chars.length();
0292: if (length > m_charsBuff.length) {
0293: m_charsBuff = new char[length * 2 + 1];
0294: }
0295: chars.getChars(0, length, m_charsBuff, 0);
0296: this .characters(m_charsBuff, 0, length);
0297: }
0298:
0299: /**
0300: * Pass the call on to the underlying handler
0301: * @see ExtendedContentHandler#endElement(String)
0302: */
0303: public void endElement(String elementName) throws SAXException {
0304: if (m_firstTagNotEmitted) {
0305: flush();
0306: }
0307: m_handler.endElement(elementName);
0308: }
0309:
0310: /**
0311: * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
0312: * @param prefix The prefix that maps to the URI
0313: * @param uri The URI for the namespace
0314: */
0315: public void startPrefixMapping(String prefix, String uri)
0316: throws SAXException {
0317: this .startPrefixMapping(prefix, uri, true);
0318: }
0319:
0320: /**
0321: * This method is used when a prefix/uri namespace mapping
0322: * is indicated after the element was started with a
0323: * startElement() and before and endElement().
0324: * startPrefixMapping(prefix,uri) would be used before the
0325: * startElement() call.
0326: * @param uri the URI of the namespace
0327: * @param prefix the prefix associated with the given URI.
0328: *
0329: * @see ExtendedContentHandler#namespaceAfterStartElement(String, String)
0330: */
0331: public void namespaceAfterStartElement(String prefix, String uri)
0332: throws SAXException {
0333: // hack for XSLTC with finding URI for default namespace
0334: if (m_firstTagNotEmitted && m_firstElementURI == null
0335: && m_firstElementName != null) {
0336: String prefix1 = getPrefixPart(m_firstElementName);
0337: if (prefix1 == null && EMPTYSTRING.equals(prefix)) {
0338: // the elements URI is not known yet, and it
0339: // doesn't have a prefix, and we are currently
0340: // setting the uri for prefix "", so we have
0341: // the uri for the element... lets remember it
0342: m_firstElementURI = uri;
0343: }
0344: }
0345: startPrefixMapping(prefix, uri, false);
0346: }
0347:
0348: public boolean startPrefixMapping(String prefix, String uri,
0349: boolean shouldFlush) throws SAXException {
0350: boolean pushed = false;
0351: if (m_firstTagNotEmitted) {
0352: if (m_firstElementName != null && shouldFlush) {
0353: /* we've already seen a startElement, and this is a prefix mapping
0354: * for the up coming element, so flush the old element
0355: * then send this event on its way.
0356: */
0357: flush();
0358: pushed = m_handler.startPrefixMapping(prefix, uri,
0359: shouldFlush);
0360: } else {
0361: if (m_namespacePrefix == null) {
0362: m_namespacePrefix = new Vector();
0363: m_namespaceURI = new Vector();
0364: }
0365: m_namespacePrefix.addElement(prefix);
0366: m_namespaceURI.addElement(uri);
0367:
0368: if (m_firstElementURI == null) {
0369: if (prefix.equals(m_firstElementPrefix))
0370: m_firstElementURI = uri;
0371: }
0372: }
0373:
0374: } else {
0375: pushed = m_handler.startPrefixMapping(prefix, uri,
0376: shouldFlush);
0377: }
0378: return pushed;
0379: }
0380:
0381: /**
0382: * This method cannot be cached because default is different in
0383: * HTML and XML (we need more than a boolean).
0384: */
0385:
0386: public void setVersion(String version) {
0387: m_handler.setVersion(version);
0388:
0389: // Cache call to setVersion()
0390: // super.setVersion(version);
0391: m_setVersion_called = true;
0392: }
0393:
0394: /**
0395: * @see org.xml.sax.ContentHandler#startDocument()
0396: */
0397: public void startDocument() throws SAXException {
0398: m_needToCallStartDocument = true;
0399: }
0400:
0401: public void startElement(String qName) throws SAXException {
0402: this .startElement(null, null, qName, null);
0403: }
0404:
0405: public void startElement(String namespaceURI, String localName,
0406: String qName) throws SAXException {
0407: this .startElement(namespaceURI, localName, qName, null);
0408: }
0409:
0410: public void startElement(String namespaceURI, String localName,
0411: String elementName, Attributes atts) throws SAXException {
0412: /* we are notified of the start of an element */
0413: if (m_firstTagNotEmitted) {
0414: /* we have not yet sent the first element on its way */
0415: if (m_firstElementName != null) {
0416: /* this is not the first element, but a later one.
0417: * But we have the old element pending, so flush it out,
0418: * then send this one on its way.
0419: */
0420: flush();
0421: m_handler.startElement(namespaceURI, localName,
0422: elementName, atts);
0423: } else {
0424: /* this is the very first element that we have seen,
0425: * so save it for flushing later. We may yet get to know its
0426: * URI due to added attributes.
0427: */
0428:
0429: m_wrapped_handler_not_initialized = true;
0430: m_firstElementName = elementName;
0431:
0432: // null if not known
0433: m_firstElementPrefix = getPrefixPartUnknown(elementName);
0434:
0435: // null if not known
0436: m_firstElementURI = namespaceURI;
0437:
0438: // null if not known
0439: m_firstElementLocalName = localName;
0440:
0441: if (m_tracer != null)
0442: firePseudoElement(elementName);
0443:
0444: /* we don't want to call our own addAttributes, which
0445: * merely delegates to the wrapped handler, but we want to
0446: * add these attributes to m_attributes. So me must call super.
0447: * addAttributes() In this case m_attributes is only used for the
0448: * first element, after that this class totally delegates to the
0449: * wrapped handler which is either XML or HTML.
0450: */
0451: if (atts != null)
0452: super .addAttributes(atts);
0453:
0454: // if there are attributes, then lets make the flush()
0455: // call the startElement on the handler and send the
0456: // attributes on their way.
0457: if (atts != null)
0458: flush();
0459:
0460: }
0461: } else {
0462: // this is not the first element, but a later one, so just
0463: // send it on its way.
0464: m_handler.startElement(namespaceURI, localName,
0465: elementName, atts);
0466: }
0467: }
0468:
0469: /**
0470: * Pass the call on to the underlying handler
0471: * @see ExtendedLexicalHandler#comment(String)
0472: */
0473: public void comment(String comment) throws SAXException {
0474: if (m_firstTagNotEmitted && m_firstElementName != null) {
0475: emitFirstTag();
0476: } else if (m_needToCallStartDocument) {
0477: m_handler.startDocument();
0478: m_needToCallStartDocument = false;
0479: }
0480:
0481: m_handler.comment(comment);
0482: }
0483:
0484: /**
0485: * Pass the call on to the underlying handler
0486: * @see XSLOutputAttributes#getDoctypePublic()
0487: */
0488: public String getDoctypePublic() {
0489:
0490: return m_handler.getDoctypePublic();
0491: }
0492:
0493: /**
0494: * Pass the call on to the underlying handler
0495: * @see XSLOutputAttributes#getDoctypeSystem()
0496: */
0497: public String getDoctypeSystem() {
0498: return m_handler.getDoctypeSystem();
0499: }
0500:
0501: /**
0502: * Pass the call on to the underlying handler
0503: * @see XSLOutputAttributes#getEncoding()
0504: */
0505: public String getEncoding() {
0506: return m_handler.getEncoding();
0507: }
0508:
0509: /**
0510: * Pass the call on to the underlying handler
0511: * @see XSLOutputAttributes#getIndent()
0512: */
0513: public boolean getIndent() {
0514: return m_handler.getIndent();
0515: }
0516:
0517: /**
0518: * Pass the call on to the underlying handler
0519: * @see XSLOutputAttributes#getIndentAmount()
0520: */
0521: public int getIndentAmount() {
0522: return m_handler.getIndentAmount();
0523: }
0524:
0525: /**
0526: * Pass the call on to the underlying handler
0527: * @see XSLOutputAttributes#getMediaType()
0528: */
0529: public String getMediaType() {
0530: return m_handler.getMediaType();
0531: }
0532:
0533: /**
0534: * Pass the call on to the underlying handler
0535: * @see XSLOutputAttributes#getOmitXMLDeclaration()
0536: */
0537: public boolean getOmitXMLDeclaration() {
0538: return m_handler.getOmitXMLDeclaration();
0539: }
0540:
0541: /**
0542: * Pass the call on to the underlying handler
0543: * @see XSLOutputAttributes#getStandalone()
0544: */
0545: public String getStandalone() {
0546: return m_handler.getStandalone();
0547: }
0548:
0549: /**
0550: * Pass the call on to the underlying handler
0551: * @see XSLOutputAttributes#getVersion()
0552: */
0553: public String getVersion() {
0554: return m_handler.getVersion();
0555: }
0556:
0557: /**
0558: * @see XSLOutputAttributes#setDoctype(String, String)
0559: */
0560: public void setDoctype(String system, String pub) {
0561: m_handler.setDoctypePublic(pub);
0562: m_handler.setDoctypeSystem(system);
0563: }
0564:
0565: /**
0566: * Set the doctype in the underlying XML handler. Remember that this method
0567: * was called, just in case we need to transfer this doctype to an HTML handler
0568: * @param doctype the public doctype to set
0569: * @see XSLOutputAttributes#setDoctypePublic(String)
0570: */
0571: public void setDoctypePublic(String doctype) {
0572: m_handler.setDoctypePublic(doctype);
0573: m_setDoctypePublic_called = true;
0574: }
0575:
0576: /**
0577: * Set the doctype in the underlying XML handler. Remember that this method
0578: * was called, just in case we need to transfer this doctype to an HTML handler
0579: * @param doctype the system doctype to set
0580: * @see XSLOutputAttributes#setDoctypeSystem(String)
0581: */
0582: public void setDoctypeSystem(String doctype) {
0583: m_handler.setDoctypeSystem(doctype);
0584: m_setDoctypeSystem_called = true;
0585: }
0586:
0587: /**
0588: * Pass the call on to the underlying handler
0589: * @see XSLOutputAttributes#setEncoding(String)
0590: */
0591: public void setEncoding(String encoding) {
0592: m_handler.setEncoding(encoding);
0593: }
0594:
0595: /**
0596: * Pass the call on to the underlying handler
0597: * @see XSLOutputAttributes#setIndent(boolean)
0598: */
0599: public void setIndent(boolean indent) {
0600: m_handler.setIndent(indent);
0601: }
0602:
0603: /**
0604: * Pass the call on to the underlying handler
0605: */
0606: public void setIndentAmount(int value) {
0607: m_handler.setIndentAmount(value);
0608: }
0609:
0610: /**
0611: * @see XSLOutputAttributes#setMediaType(String)
0612: */
0613: public void setMediaType(String mediaType) {
0614: m_handler.setMediaType(mediaType);
0615: m_setMediaType_called = true;
0616: }
0617:
0618: /**
0619: * Pass the call on to the underlying handler
0620: * @see XSLOutputAttributes#setOmitXMLDeclaration(boolean)
0621: */
0622: public void setOmitXMLDeclaration(boolean b) {
0623: m_handler.setOmitXMLDeclaration(b);
0624: }
0625:
0626: /**
0627: * Pass the call on to the underlying handler
0628: * @see XSLOutputAttributes#setStandalone(String)
0629: */
0630: public void setStandalone(String standalone) {
0631: m_handler.setStandalone(standalone);
0632: }
0633:
0634: /**
0635: * @see XSLOutputAttributes#setVersion(String)
0636: */
0637:
0638: /**
0639: * Pass the call on to the underlying handler
0640: * @see org.xml.sax.ext.DeclHandler#attributeDecl(String, String, String, String, String)
0641: */
0642: public void attributeDecl(String arg0, String arg1, String arg2,
0643: String arg3, String arg4) throws SAXException {
0644: m_handler.attributeDecl(arg0, arg1, arg2, arg3, arg4);
0645: }
0646:
0647: /**
0648: * Pass the call on to the underlying handler
0649: * @see org.xml.sax.ext.DeclHandler#elementDecl(String, String)
0650: */
0651: public void elementDecl(String arg0, String arg1)
0652: throws SAXException {
0653: if (m_firstTagNotEmitted) {
0654: emitFirstTag();
0655: }
0656: m_handler.elementDecl(arg0, arg1);
0657: }
0658:
0659: /**
0660: * Pass the call on to the underlying handler
0661: * @see org.xml.sax.ext.DeclHandler#externalEntityDecl(String, String, String)
0662: */
0663: public void externalEntityDecl(String name, String publicId,
0664: String systemId) throws SAXException {
0665: if (m_firstTagNotEmitted) {
0666: flush();
0667: }
0668: m_handler.externalEntityDecl(name, publicId, systemId);
0669: }
0670:
0671: /**
0672: * Pass the call on to the underlying handler
0673: * @see org.xml.sax.ext.DeclHandler#internalEntityDecl(String, String)
0674: */
0675: public void internalEntityDecl(String arg0, String arg1)
0676: throws SAXException {
0677: if (m_firstTagNotEmitted) {
0678: flush();
0679: }
0680: m_handler.internalEntityDecl(arg0, arg1);
0681: }
0682:
0683: /**
0684: * Pass the call on to the underlying handler
0685: * @see org.xml.sax.ContentHandler#characters(char[], int, int)
0686: */
0687: public void characters(char[] characters, int offset, int length)
0688: throws SAXException {
0689: if (m_firstTagNotEmitted) {
0690: flush();
0691: }
0692:
0693: m_handler.characters(characters, offset, length);
0694:
0695: }
0696:
0697: /**
0698: * Pass the call on to the underlying handler
0699: * @see org.xml.sax.ContentHandler#endDocument()
0700: */
0701: public void endDocument() throws SAXException {
0702: if (m_firstTagNotEmitted) {
0703: flush();
0704: }
0705:
0706: m_handler.endDocument();
0707:
0708: }
0709:
0710: /**
0711: * Pass the call on to the underlying handler
0712: * @see org.xml.sax.ContentHandler#endElement(String, String, String)
0713: */
0714: public void endElement(String namespaceURI, String localName,
0715: String qName) throws SAXException {
0716: if (m_firstTagNotEmitted) {
0717: flush();
0718: if (namespaceURI == null && m_firstElementURI != null)
0719: namespaceURI = m_firstElementURI;
0720:
0721: if (localName == null && m_firstElementLocalName != null)
0722: localName = m_firstElementLocalName;
0723: }
0724:
0725: m_handler.endElement(namespaceURI, localName, qName);
0726: }
0727:
0728: /**
0729: * Pass the call on to the underlying handler
0730: * @see org.xml.sax.ContentHandler#endPrefixMapping(String)
0731: */
0732: public void endPrefixMapping(String prefix) throws SAXException {
0733: m_handler.endPrefixMapping(prefix);
0734: }
0735:
0736: /**
0737: * Pass the call on to the underlying handler
0738: * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
0739: */
0740: public void ignorableWhitespace(char[] ch, int start, int length)
0741: throws SAXException {
0742: if (m_firstTagNotEmitted) {
0743: flush();
0744: }
0745: m_handler.ignorableWhitespace(ch, start, length);
0746: }
0747:
0748: /**
0749: * Pass the call on to the underlying handler
0750: * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
0751: */
0752: public void processingInstruction(String target, String data)
0753: throws SAXException {
0754: if (m_firstTagNotEmitted) {
0755: flush();
0756: }
0757:
0758: m_handler.processingInstruction(target, data);
0759: }
0760:
0761: /**
0762: * Pass the call on to the underlying handler
0763: * @see org.xml.sax.ContentHandler#setDocumentLocator(Locator)
0764: */
0765: public void setDocumentLocator(Locator locator) {
0766: m_handler.setDocumentLocator(locator);
0767: }
0768:
0769: /**
0770: * Pass the call on to the underlying handler
0771: * @see org.xml.sax.ContentHandler#skippedEntity(String)
0772: */
0773: public void skippedEntity(String name) throws SAXException {
0774: m_handler.skippedEntity(name);
0775: }
0776:
0777: /**
0778: * Pass the call on to the underlying handler
0779: * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
0780: */
0781: public void comment(char[] ch, int start, int length)
0782: throws SAXException {
0783: if (m_firstTagNotEmitted) {
0784: flush();
0785: }
0786:
0787: m_handler.comment(ch, start, length);
0788: }
0789:
0790: /**
0791: * Pass the call on to the underlying handler
0792: * @see org.xml.sax.ext.LexicalHandler#endCDATA()
0793: */
0794: public void endCDATA() throws SAXException {
0795:
0796: m_handler.endCDATA();
0797: }
0798:
0799: /**
0800: * Pass the call on to the underlying handler
0801: * @see org.xml.sax.ext.LexicalHandler#endDTD()
0802: */
0803: public void endDTD() throws SAXException {
0804:
0805: m_handler.endDTD();
0806: }
0807:
0808: /**
0809: * Pass the call on to the underlying handler
0810: * @see org.xml.sax.ext.LexicalHandler#endEntity(String)
0811: */
0812: public void endEntity(String name) throws SAXException {
0813: if (m_firstTagNotEmitted) {
0814: emitFirstTag();
0815: }
0816: m_handler.endEntity(name);
0817: }
0818:
0819: /**
0820: * Pass the call on to the underlying handler
0821: * @see org.xml.sax.ext.LexicalHandler#startCDATA()
0822: */
0823: public void startCDATA() throws SAXException {
0824: m_handler.startCDATA();
0825: }
0826:
0827: /**
0828: * Pass the call on to the underlying handler
0829: * @see org.xml.sax.ext.LexicalHandler#startDTD(String, String, String)
0830: */
0831: public void startDTD(String name, String publicId, String systemId)
0832: throws SAXException {
0833: m_handler.startDTD(name, publicId, systemId);
0834: }
0835:
0836: /**
0837: * Pass the call on to the underlying handler
0838: * @see org.xml.sax.ext.LexicalHandler#startEntity(String)
0839: */
0840: public void startEntity(String name) throws SAXException {
0841: m_handler.startEntity(name);
0842: }
0843:
0844: /**
0845: * Initialize the wrapped output stream (XML or HTML).
0846: * If the stream handler should be HTML, then replace the XML handler with
0847: * an HTML handler. After than send the starting method calls that were cached
0848: * to the wrapped handler.
0849: *
0850: */
0851: private void initStreamOutput() throws SAXException {
0852:
0853: // Try to rule out if this is an not to be an HTML document based on prefix
0854: boolean firstElementIsHTML = isFirstElemHTML();
0855:
0856: if (firstElementIsHTML) {
0857: // create an HTML output handler, and initialize it
0858:
0859: // keep a reference to the old handler, ... it will soon be gone
0860: SerializationHandler oldHandler = m_handler;
0861:
0862: /* We have to make sure we get an output properties with the proper
0863: * defaults for the HTML method. The easiest way to do this is to
0864: * have the OutputProperties class do it.
0865: */
0866:
0867: Properties htmlProperties = OutputPropertiesFactory
0868: .getDefaultMethodProperties(Method.HTML);
0869: Serializer serializer = SerializerFactory
0870: .getSerializer(htmlProperties);
0871:
0872: // The factory should be returning a ToStream
0873: // Don't know what to do if it doesn't
0874: // i.e. the user has over-ridden the content-handler property
0875: // for html
0876: m_handler = (SerializationHandler) serializer;
0877: //m_handler = new ToHTMLStream();
0878:
0879: Writer writer = oldHandler.getWriter();
0880:
0881: if (null != writer)
0882: m_handler.setWriter(writer);
0883: else {
0884: OutputStream os = oldHandler.getOutputStream();
0885:
0886: if (null != os)
0887: m_handler.setOutputStream(os);
0888: }
0889:
0890: // need to copy things from the old handler to the new one here
0891:
0892: // if (_setVersion_called)
0893: // {
0894: m_handler.setVersion(oldHandler.getVersion());
0895: // }
0896: // if (_setDoctypeSystem_called)
0897: // {
0898: m_handler.setDoctypeSystem(oldHandler.getDoctypeSystem());
0899: // }
0900: // if (_setDoctypePublic_called)
0901: // {
0902: m_handler.setDoctypePublic(oldHandler.getDoctypePublic());
0903: // }
0904: // if (_setMediaType_called)
0905: // {
0906: m_handler.setMediaType(oldHandler.getMediaType());
0907: // }
0908:
0909: m_handler.setTransformer(oldHandler.getTransformer());
0910: }
0911:
0912: /* Now that we have a real wrapped handler (XML or HTML) lets
0913: * pass any cached calls to it
0914: */
0915: // Call startDocument() if necessary
0916: if (m_needToCallStartDocument) {
0917: m_handler.startDocument();
0918: m_needToCallStartDocument = false;
0919: }
0920:
0921: // the wrapped handler is now fully initialized
0922: m_wrapped_handler_not_initialized = false;
0923: }
0924:
0925: private void emitFirstTag() throws SAXException {
0926: if (m_firstElementName != null) {
0927: if (m_wrapped_handler_not_initialized) {
0928: initStreamOutput();
0929: m_wrapped_handler_not_initialized = false;
0930: }
0931: // Output first tag
0932: m_handler.startElement(m_firstElementURI, null,
0933: m_firstElementName, m_attributes);
0934: // don't need the collected attributes of the first element anymore.
0935: m_attributes = null;
0936:
0937: // Output namespaces of first tag
0938: if (m_namespacePrefix != null) {
0939: final int n = m_namespacePrefix.size();
0940: for (int i = 0; i < n; i++) {
0941: final String prefix = (String) m_namespacePrefix
0942: .elementAt(i);
0943: final String uri = (String) m_namespaceURI
0944: .elementAt(i);
0945: m_handler.startPrefixMapping(prefix, uri, false);
0946: }
0947: m_namespacePrefix = null;
0948: m_namespaceURI = null;
0949: }
0950: m_firstTagNotEmitted = false;
0951: }
0952: }
0953:
0954: /**
0955: * Utility function for calls to local-name().
0956: *
0957: * Don't want to override static function on SerializerBase
0958: * So added Unknown suffix to method name.
0959: */
0960: private String getLocalNameUnknown(String value) {
0961: int idx = value.lastIndexOf(':');
0962: if (idx >= 0)
0963: value = value.substring(idx + 1);
0964: idx = value.lastIndexOf('@');
0965: if (idx >= 0)
0966: value = value.substring(idx + 1);
0967: return (value);
0968: }
0969:
0970: /**
0971: * Utility function to return prefix
0972: *
0973: * Don't want to override static function on SerializerBase
0974: * So added Unknown suffix to method name.
0975: */
0976: private String getPrefixPartUnknown(String qname) {
0977: final int index = qname.indexOf(':');
0978: return (index > 0) ? qname.substring(0, index) : EMPTYSTRING;
0979: }
0980:
0981: /**
0982: * Determine if the firts element in the document is <html> or <HTML>
0983: * This uses the cached first element name, first element prefix and the
0984: * cached namespaces from previous method calls
0985: *
0986: * @return true if the first element is an opening <html> tag
0987: */
0988: private boolean isFirstElemHTML() {
0989: boolean isHTML;
0990:
0991: // is the first tag html, not considering the prefix ?
0992: isHTML = getLocalNameUnknown(m_firstElementName)
0993: .equalsIgnoreCase("html");
0994:
0995: // Try to rule out if this is not to be an HTML document based on URI
0996: if (isHTML && m_firstElementURI != null
0997: && !EMPTYSTRING.equals(m_firstElementURI)) {
0998: // the <html> element has a non-trivial namespace
0999: isHTML = false;
1000: }
1001: // Try to rule out if this is an not to be an HTML document based on prefix
1002: if (isHTML && m_namespacePrefix != null) {
1003: /* the first element has a name of "html", but lets check the prefix.
1004: * If the prefix points to a namespace with a URL that is not ""
1005: * then the doecument doesn't start with an <html> tag, and isn't html
1006: */
1007: final int max = m_namespacePrefix.size();
1008: for (int i = 0; i < max; i++) {
1009: final String prefix = (String) m_namespacePrefix
1010: .elementAt(i);
1011: final String uri = (String) m_namespaceURI.elementAt(i);
1012:
1013: if (m_firstElementPrefix != null
1014: && m_firstElementPrefix.equals(prefix)
1015: && !EMPTYSTRING.equals(uri)) {
1016: // The first element has a prefix, so it can't be <html>
1017: isHTML = false;
1018: break;
1019: }
1020: }
1021:
1022: }
1023: return isHTML;
1024: }
1025:
1026: /**
1027: * @see Serializer#asDOMSerializer()
1028: */
1029: public DOMSerializer asDOMSerializer() throws IOException {
1030: return m_handler.asDOMSerializer();
1031: }
1032:
1033: /**
1034: * @param URI_and_localNames Vector a list of pairs of URI/localName
1035: * specified in the cdata-section-elements attribute.
1036: * @see SerializationHandler#setCdataSectionElements(java.util.Vector)
1037: */
1038: public void setCdataSectionElements(Vector URI_and_localNames) {
1039: m_handler.setCdataSectionElements(URI_and_localNames);
1040: }
1041:
1042: /**
1043: * @see ExtendedContentHandler#addAttributes(org.xml.sax.Attributes)
1044: */
1045: public void addAttributes(Attributes atts) throws SAXException {
1046: m_handler.addAttributes(atts);
1047: }
1048:
1049: /**
1050: * Get the current namespace mappings.
1051: * Simply returns the mappings of the wrapped handler.
1052: * @see ExtendedContentHandler#getNamespaceMappings()
1053: */
1054: public NamespaceMappings getNamespaceMappings() {
1055: NamespaceMappings mappings = null;
1056: if (m_handler != null) {
1057: mappings = m_handler.getNamespaceMappings();
1058: }
1059: return mappings;
1060: }
1061:
1062: /**
1063: * @see SerializationHandler#flushPending()
1064: */
1065: public void flushPending() throws SAXException {
1066:
1067: flush();
1068:
1069: m_handler.flushPending();
1070: }
1071:
1072: private void flush() {
1073: try {
1074: if (m_firstTagNotEmitted) {
1075: emitFirstTag();
1076: }
1077: if (m_needToCallStartDocument) {
1078: m_handler.startDocument();
1079: m_needToCallStartDocument = false;
1080: }
1081: } catch (SAXException e) {
1082: throw new RuntimeException(e.toString());
1083: }
1084:
1085: }
1086:
1087: /**
1088: * @see ExtendedContentHandler#getPrefix
1089: */
1090: public String getPrefix(String namespaceURI) {
1091: return m_handler.getPrefix(namespaceURI);
1092: }
1093:
1094: /**
1095: * @see ExtendedContentHandler#entityReference(java.lang.String)
1096: */
1097: public void entityReference(String entityName) throws SAXException {
1098: m_handler.entityReference(entityName);
1099: }
1100:
1101: /**
1102: * @see ExtendedContentHandler#getNamespaceURI(java.lang.String, boolean)
1103: */
1104: public String getNamespaceURI(String qname, boolean isElement) {
1105: return m_handler.getNamespaceURI(qname, isElement);
1106: }
1107:
1108: public String getNamespaceURIFromPrefix(String prefix) {
1109: return m_handler.getNamespaceURIFromPrefix(prefix);
1110: }
1111:
1112: public void setTransformer(Transformer t) {
1113: m_handler.setTransformer(t);
1114: if ((t instanceof SerializerTrace)
1115: && (((SerializerTrace) t).hasTraceListeners())) {
1116: m_tracer = (SerializerTrace) t;
1117: } else {
1118: m_tracer = null;
1119: }
1120: }
1121:
1122: public Transformer getTransformer() {
1123: return m_handler.getTransformer();
1124: }
1125:
1126: /**
1127: * @see SerializationHandler#setContentHandler(org.xml.sax.ContentHandler)
1128: */
1129: public void setContentHandler(ContentHandler ch) {
1130: m_handler.setContentHandler(ch);
1131: }
1132:
1133: /**
1134: * This method is used to set the source locator, which might be used to
1135: * generated an error message.
1136: * @param locator the source locator
1137: *
1138: * @see ExtendedContentHandler#setSourceLocator(javax.xml.transform.SourceLocator)
1139: */
1140: public void setSourceLocator(SourceLocator locator) {
1141: m_handler.setSourceLocator(locator);
1142: }
1143:
1144: protected void firePseudoElement(String elementName) {
1145:
1146: if (m_tracer != null) {
1147: StringBuffer sb = new StringBuffer();
1148:
1149: sb.append('<');
1150: sb.append(elementName);
1151:
1152: // convert the StringBuffer to a char array and
1153: // emit the trace event that these characters "might"
1154: // be written
1155: char ch[] = sb.toString().toCharArray();
1156: m_tracer.fireGenerateEvent(
1157: SerializerTrace.EVENTTYPE_OUTPUT_PSEUDO_CHARACTERS,
1158: ch, 0, ch.length);
1159: }
1160: }
1161: }
|