1 /*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5 /*
6 * Licensed to the Apache Software Foundation (ASF) under one
7 * or more contributor license agreements. See the NOTICE file
8 * distributed with this work for additional information
9 * regarding copyright ownership. The ASF licenses this file
10 * to you under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22 /*
23 * $Id: ToHTMLStream.java,v 1.2.4.1 2005/09/15 08:15:26 suresh_emailid Exp $
24 */
25 package com.sun.org.apache.xml.internal.serializer;
26
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.io.UnsupportedEncodingException;
30 import java.util.Properties;
31
32 import javax.xml.transform.Result;
33
34 import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
35 import com.sun.org.apache.xml.internal.serializer.utils.Utils;
36 import org.xml.sax.Attributes;
37 import org.xml.sax.SAXException;
38
39 /**
40 * This serializer takes a series of SAX or
41 * SAX-like events and writes its output
42 * to the given stream.
43 *
44 * This class is not a public API, it is public
45 * because it is used from another package.
46 *
47 * @xsl.usage internal
48 */
49 public final class ToHTMLStream extends ToStream
50 {
51
52 /** This flag is set while receiving events from the DTD */
53 protected boolean m_inDTD = false;
54
55 /** True if the current element is a block element. (seems like
56 * this needs to be a stack. -sb). */
57 private boolean m_inBlockElem = false;
58
59 /**
60 * Map that tells which XML characters should have special treatment, and it
61 * provides character to entity name lookup.
62 */
63 private static final CharInfo m_htmlcharInfo =
64 // new CharInfo(CharInfo.HTML_ENTITIES_RESOURCE);
65 CharInfo.getCharInfoInternal(CharInfo.HTML_ENTITIES_RESOURCE, Method.HTML);
66
67 /** A digital search trie for fast, case insensitive lookup of ElemDesc objects. */
68 static final Trie m_elementFlags = new Trie();
69
70 static {
71 initTagReference(m_elementFlags);
72 }
73 static void initTagReference(Trie m_elementFlags) {
74
75 // HTML 4.0 loose DTD
76 m_elementFlags.put("BASEFONT", new ElemDesc(0 | ElemDesc.EMPTY));
77 m_elementFlags.put(
706 catch(IOException e)
707 {
708 throw new SAXException(e);
709 }
710 }
711 }
712
713 m_needToOutputDocTypeDecl = false;
714 }
715
716 /**
717 * Receive notification of the end of a document.
718 *
719 * @throws org.xml.sax.SAXException Any SAX exception, possibly
720 * wrapping another exception.
721 *
722 * @throws org.xml.sax.SAXException
723 */
724 public final void endDocument() throws org.xml.sax.SAXException
725 {
726
727 flushPending();
728 if (m_doIndent && !m_isprevtext)
729 {
730 try
731 {
732 outputLineSep();
733 }
734 catch(IOException e)
735 {
736 throw new SAXException(e);
737 }
738 }
739
740 flushWriter();
741 if (m_tracer != null)
742 super.fireEndDoc();
743 }
744
745 /**
746 * Receive notification of the beginning of an element.
747 *
748 *
749 * @param namespaceURI
750 * @param localName
751 * @param name The element type name.
752 * @param atts The attributes attached to the element, if any.
753 * @throws org.xml.sax.SAXException Any SAX exception, possibly
754 * wrapping another exception.
755 * @see #endElement
756 * @see org.xml.sax.AttributeList
757 */
758 public void startElement(
759 String namespaceURI,
760 String localName,
761 String name,
762 Attributes atts)
763 throws org.xml.sax.SAXException
764 {
765
766 ElemContext elemContext = m_elemContext;
767
768 // clean up any pending things first
769 if (elemContext.m_startTagOpen)
770 {
771 closeStartTag();
772 elemContext.m_startTagOpen = false;
773 }
774 else if (m_cdataTagOpen)
775 {
776 closeCDATA();
777 m_cdataTagOpen = false;
778 }
779 else if (m_needToCallStartDocument)
780 {
781 startDocumentInternal();
782 m_needToCallStartDocument = false;
783 }
784
785
786 // if this element has a namespace then treat it like XML
787 if (null != namespaceURI && namespaceURI.length() > 0)
788 {
789 super.startElement(namespaceURI, localName, name, atts);
790
791 return;
792 }
793
794 try
795 {
796 // getElemDesc2(name) is faster than getElemDesc(name)
797 ElemDesc elemDesc = getElemDesc2(name);
798 int elemFlags = elemDesc.getFlags();
799
800 // deal with indentation issues first
801 if (m_doIndent)
802 {
803
804 boolean isBlockElement = (elemFlags & ElemDesc.BLOCK) != 0;
805 if (m_ispreserve)
806 m_ispreserve = false;
807 else if (
808 (null != elemContext.m_elementName)
809 && (!m_inBlockElem
810 || isBlockElement) /* && !isWhiteSpaceSensitive */
811 )
812 {
813 m_startNewLine = true;
814
815 indent();
816
817 }
818 m_inBlockElem = !isBlockElement;
819 }
820
821 // save any attributes for later processing
822 if (atts != null)
823 addAttributes(atts);
824
825 m_isprevtext = false;
826 final java.io.Writer writer = m_writer;
827 writer.write('<');
828 writer.write(name);
829
830
831
832 if (m_tracer != null)
833 firePseudoAttributes();
834
835 if ((elemFlags & ElemDesc.EMPTY) != 0)
836 {
837 // an optimization for elements which are expected
838 // to be empty.
839 m_elemContext = elemContext.push();
840 /* XSLTC sometimes calls namespaceAfterStartElement()
841 * so we need to remember the name
842 */
843 m_elemContext.m_elementName = name;
844 m_elemContext.m_elementDesc = elemDesc;
845 return;
846 }
847 else
848 {
849 elemContext = elemContext.push(namespaceURI,localName,name);
850 m_elemContext = elemContext;
851 elemContext.m_elementDesc = elemDesc;
852 elemContext.m_isRaw = (elemFlags & ElemDesc.RAW) != 0;
853 }
854
855
856 if ((elemFlags & ElemDesc.HEADELEM) != 0)
857 {
858 // This is the <HEAD> element, do some special processing
859 closeStartTag();
860 elemContext.m_startTagOpen = false;
861 if (!m_omitMetaTag)
862 {
863 if (m_doIndent)
864 indent();
865 writer.write(
866 "<META http-equiv=\"Content-Type\" content=\"text/html; charset=");
867 String encoding = getEncoding();
868 String encode = Encodings.getMimeEncoding(encoding);
869 writer.write(encode);
870 writer.write("\">");
871 }
872 }
876 throw new SAXException(e);
877 }
878 }
879
880 /**
881 * Receive notification of the end of an element.
882 *
883 *
884 * @param namespaceURI
885 * @param localName
886 * @param name The element type name
887 * @throws org.xml.sax.SAXException Any SAX exception, possibly
888 * wrapping another exception.
889 */
890 public final void endElement(
891 final String namespaceURI,
892 final String localName,
893 final String name)
894 throws org.xml.sax.SAXException
895 {
896 // deal with any pending issues
897 if (m_cdataTagOpen)
898 closeCDATA();
899
900 // if the element has a namespace, treat it like XML, not HTML
901 if (null != namespaceURI && namespaceURI.length() > 0)
902 {
903 super.endElement(namespaceURI, localName, name);
904
905 return;
906 }
907
908 try
909 {
910
911 ElemContext elemContext = m_elemContext;
912 final ElemDesc elemDesc = elemContext.m_elementDesc;
913 final int elemFlags = elemDesc.getFlags();
914 final boolean elemEmpty = (elemFlags & ElemDesc.EMPTY) != 0;
915
916 // deal with any indentation issues
917 if (m_doIndent)
918 {
919 final boolean isBlockElement = (elemFlags&ElemDesc.BLOCK) != 0;
920 boolean shouldIndent = false;
921
922 if (m_ispreserve)
923 {
924 m_ispreserve = false;
925 }
926 else if (m_doIndent && (!m_inBlockElem || isBlockElement))
927 {
928 m_startNewLine = true;
929 shouldIndent = true;
930 }
931 if (!elemContext.m_startTagOpen && shouldIndent)
932 indent(elemContext.m_currentElemDepth - 1);
933 m_inBlockElem = !isBlockElement;
934 }
935
936 final java.io.Writer writer = m_writer;
937 if (!elemContext.m_startTagOpen)
938 {
939 writer.write("</");
940 writer.write(name);
941 writer.write('>');
942 }
943 else
944 {
945 // the start-tag open when this method was called,
946 // so we need to process it now.
947
948 if (m_tracer != null)
949 super.fireStartElem(name);
950
951 // the starting tag was still open when we received this endElement() call
952 // so we need to process any gathered attributes NOW, before they go away.
953 int nAttrs = m_attributes.getLength();
957 // clear attributes object for re-use with next element
958 m_attributes.clear();
959 }
960 if (!elemEmpty)
961 {
962 // As per Dave/Paul recommendation 12/06/2000
963 // if (shouldIndent)
964 // writer.write('>');
965 // indent(m_currentIndent);
966
967 writer.write("></");
968 writer.write(name);
969 writer.write('>');
970 }
971 else
972 {
973 writer.write('>');
974 }
975 }
976
977 // clean up because the element has ended
978 if ((elemFlags & ElemDesc.WHITESPACESENSITIVE) != 0)
979 m_ispreserve = true;
980 m_isprevtext = false;
981
982 // fire off the end element event
983 if (m_tracer != null)
984 super.fireEndElem(name);
985
986 // OPTIMIZE-EMPTY
987 if (elemEmpty)
988 {
989 // a quick exit if the HTML element had no children.
990 // This block of code can be removed if the corresponding block of code
991 // in startElement() also labeled with "OPTIMIZE-EMPTY" is also removed
992 m_elemContext = elemContext.m_prev;
993 return;
994 }
995
996 // some more clean because the element has ended.
1494
1495 if (m_elemContext.m_isRaw)
1496 {
1497 try
1498 {
1499 if (m_elemContext.m_startTagOpen)
1500 {
1501 closeStartTag();
1502 m_elemContext.m_startTagOpen = false;
1503 }
1504 m_ispreserve = true;
1505
1506 // With m_ispreserve just set true it looks like shouldIndent()
1507 // will always return false, so drop any possible indentation.
1508 // if (shouldIndent())
1509 // indent();
1510
1511 // writer.write("<![CDATA[");
1512 // writer.write(chars, start, length);
1513 writeNormalizedChars(chars, start, length, false, m_lineSepUse);
1514
1515 // writer.write("]]>");
1516
1517 // time to generate characters event
1518 if (m_tracer != null)
1519 super.fireCharEvent(chars, start, length);
1520
1521 return;
1522 }
1523 catch (IOException ioe)
1524 {
1525 throw new org.xml.sax.SAXException(
1526 Utils.messages.createMessage(
1527 MsgKey.ER_OIERROR,
1528 null),
1529 ioe);
1530 //"IO error", ioe);
1531 }
1532 }
1533 else
1534 {
1549 * <p>The application must not attempt to read from the array
1550 * outside of the specified range.</p>
1551 *
1552 * <p>Note that some parsers will report whitespace using the
1553 * ignorableWhitespace() method rather than this one (validating
1554 * parsers must do so).</p>
1555 *
1556 * @param ch The characters from the XML document.
1557 * @param start The start position in the array.
1558 * @param length The number of characters to read from the array.
1559 * @throws org.xml.sax.SAXException Any SAX exception, possibly
1560 * wrapping another exception.
1561 * @see #ignorableWhitespace
1562 * @see org.xml.sax.Locator
1563 *
1564 * @throws org.xml.sax.SAXException
1565 */
1566 public final void cdata(char ch[], int start, int length)
1567 throws org.xml.sax.SAXException
1568 {
1569
1570 if ((null != m_elemContext.m_elementName)
1571 && (m_elemContext.m_elementName.equalsIgnoreCase("SCRIPT")
1572 || m_elemContext.m_elementName.equalsIgnoreCase("STYLE")))
1573 {
1574 try
1575 {
1576 if (m_elemContext.m_startTagOpen)
1577 {
1578 closeStartTag();
1579 m_elemContext.m_startTagOpen = false;
1580 }
1581
1582 m_ispreserve = true;
1583
1584 if (shouldIndent())
1585 indent();
1586
1587 // writer.write(ch, start, length);
1588 writeNormalizedChars(ch, start, length, true, m_lineSepUse);
1589 }
1600 else
1601 {
1602 super.cdata(ch, start, length);
1603 }
1604 }
1605
1606 /**
1607 * Receive notification of a processing instruction.
1608 *
1609 * @param target The processing instruction target.
1610 * @param data The processing instruction data, or null if
1611 * none was supplied.
1612 * @throws org.xml.sax.SAXException Any SAX exception, possibly
1613 * wrapping another exception.
1614 *
1615 * @throws org.xml.sax.SAXException
1616 */
1617 public void processingInstruction(String target, String data)
1618 throws org.xml.sax.SAXException
1619 {
1620
1621 // Process any pending starDocument and startElement first.
1622 flushPending();
1623
1624 // Use a fairly nasty hack to tell if the next node is supposed to be
1625 // unescaped text.
1626 if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
1627 {
1628 startNonEscaping();
1629 }
1630 else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING))
1631 {
1632 endNonEscaping();
1633 }
1634 else
1635 {
1636 try
1637 {
1638 if (m_elemContext.m_startTagOpen)
1639 {
1640 closeStartTag();
1928 public void comment(char ch[], int start, int length)
1929 throws SAXException
1930 {
1931 // The internal DTD subset is not serialized by the ToHTMLStream serializer
1932 if (m_inDTD)
1933 return;
1934 super.comment(ch, start, length);
1935 }
1936
1937 public boolean reset()
1938 {
1939 boolean ret = super.reset();
1940 if (!ret)
1941 return false;
1942 initToHTMLStream();
1943 return true;
1944 }
1945
1946 private void initToHTMLStream()
1947 {
1948 // m_elementDesc = null;
1949 m_inBlockElem = false;
1950 m_inDTD = false;
1951 // m_isRawStack.clear();
1952 m_omitMetaTag = false;
1953 m_specialEscapeURLs = true;
1954 }
1955
1956 static class Trie
1957 {
1958 /**
1959 * A digital search trie for 7-bit ASCII text
1960 * The API is a subset of java.util.Hashtable
1961 * The key must be a 7-bit ASCII string
1962 * The value may be any Java Object
1963 * One can get an object stored in a trie from its key,
1964 * but the search is either case sensitive or case
1965 * insensitive to the characters in the key, and this
1966 * choice of sensitivity or insensitivity is made when
1967 * the Trie is created, before any objects are put in it.
1968 *
1969 * This class is a copy of the one in com.sun.org.apache.xml.internal.utils.
1970 * It exists to cut the serializers dependancy on that package.
1971 *
|
1 /*
2 * Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements. See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 package com.sun.org.apache.xml.internal.serializer;
22
23 import java.io.IOException;
24 import java.util.Properties;
25
26 import javax.xml.transform.Result;
27
28 import org.xml.sax.Attributes;
29 import org.xml.sax.SAXException;
30
31 import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
32 import com.sun.org.apache.xml.internal.serializer.utils.Utils;
33
34 /**
35 * This serializer takes a series of SAX or
36 * SAX-like events and writes its output
37 * to the given stream.
38 *
39 * This class is not a public API, it is public
40 * because it is used from another package.
41 *
42 * @xsl.usage internal
43 */
44 public final class ToHTMLStream extends ToStream
45 {
46
47 /** This flag is set while receiving events from the DTD */
48 protected boolean m_inDTD = false;
49
50 /** True if the previous element is a block element. */
51 private boolean m_isprevblock = false;
52
53 /**
54 * Map that tells which XML characters should have special treatment, and it
55 * provides character to entity name lookup.
56 */
57 private static final CharInfo m_htmlcharInfo =
58 // new CharInfo(CharInfo.HTML_ENTITIES_RESOURCE);
59 CharInfo.getCharInfoInternal(CharInfo.HTML_ENTITIES_RESOURCE, Method.HTML);
60
61 /** A digital search trie for fast, case insensitive lookup of ElemDesc objects. */
62 static final Trie m_elementFlags = new Trie();
63
64 static {
65 initTagReference(m_elementFlags);
66 }
67 static void initTagReference(Trie m_elementFlags) {
68
69 // HTML 4.0 loose DTD
70 m_elementFlags.put("BASEFONT", new ElemDesc(0 | ElemDesc.EMPTY));
71 m_elementFlags.put(
700 catch(IOException e)
701 {
702 throw new SAXException(e);
703 }
704 }
705 }
706
707 m_needToOutputDocTypeDecl = false;
708 }
709
710 /**
711 * Receive notification of the end of a document.
712 *
713 * @throws org.xml.sax.SAXException Any SAX exception, possibly
714 * wrapping another exception.
715 *
716 * @throws org.xml.sax.SAXException
717 */
718 public final void endDocument() throws org.xml.sax.SAXException
719 {
720 flushCharactersBuffer();
721 flushPending();
722 if (m_doIndent && !m_isprevtext)
723 {
724 try
725 {
726 outputLineSep();
727 }
728 catch(IOException e)
729 {
730 throw new SAXException(e);
731 }
732 }
733
734 flushWriter();
735 if (m_tracer != null)
736 super.fireEndDoc();
737 }
738
739 /**
740 * If the previous is an inline element, won't insert a new line before the
741 * text.
742 *
743 */
744 protected boolean shouldIndentForText() {
745 return super.shouldIndentForText() && m_isprevblock;
746 }
747
748 /**
749 * Only check m_doIndent, disregard m_ispreserveSpace.
750 *
751 * @return True if the content should be formatted.
752 */
753 protected boolean shouldFormatOutput() {
754 return m_doIndent;
755 }
756
757 /**
758 * Receive notification of the beginning of an element.
759 *
760 *
761 * @param namespaceURI
762 * @param localName
763 * @param name
764 * The element type name.
765 * @param atts
766 * The attributes attached to the element, if any.
767 * @throws org.xml.sax.SAXException
768 * Any SAX exception, possibly wrapping another exception.
769 * @see #endElement
770 * @see org.xml.sax.AttributeList
771 */
772 public void startElement(
773 String namespaceURI,
774 String localName,
775 String name,
776 Attributes atts)
777 throws SAXException
778 {
779 // will add extra one if having namespace but no matter
780 m_childNodeNum++;
781 flushCharactersBuffer();
782 ElemContext elemContext = m_elemContext;
783
784 // clean up any pending things first
785 if (elemContext.m_startTagOpen)
786 {
787 closeStartTag();
788 elemContext.m_startTagOpen = false;
789 }
790 else if (m_cdataTagOpen)
791 {
792 closeCDATA();
793 m_cdataTagOpen = false;
794 }
795 else if (m_needToCallStartDocument)
796 {
797 startDocumentInternal();
798 m_needToCallStartDocument = false;
799 }
800
801
802 // if this element has a namespace then treat it like XML
803 if (null != namespaceURI && namespaceURI.length() > 0)
804 {
805 super.startElement(namespaceURI, localName, name, atts);
806
807 return;
808 }
809
810 try
811 {
812 // getElemDesc2(name) is faster than getElemDesc(name)
813 ElemDesc elemDesc = getElemDesc2(name);
814 int elemFlags = elemDesc.getFlags();
815
816 // deal with indentation issues first
817 if (m_doIndent)
818 {
819 boolean isBlockElement = (elemFlags & ElemDesc.BLOCK) != 0;
820 if ((elemContext.m_elementName != null)
821 // If this element is a block element,
822 // or if this is not a block element, then if the
823 // previous is neither a text nor an inline
824 && (isBlockElement || (!(m_isprevtext || !m_isprevblock))))
825 {
826 m_startNewLine = true;
827
828 indent();
829 }
830 m_isprevblock = isBlockElement;
831 }
832
833 // save any attributes for later processing
834 if (atts != null)
835 addAttributes(atts);
836
837 m_isprevtext = false;
838 final java.io.Writer writer = m_writer;
839 writer.write('<');
840 writer.write(name);
841
842 m_childNodeNumStack.push(m_childNodeNum);
843 m_childNodeNum = 0;
844
845 if (m_tracer != null)
846 firePseudoAttributes();
847
848 if ((elemFlags & ElemDesc.EMPTY) != 0)
849 {
850 // an optimization for elements which are expected
851 // to be empty.
852 m_elemContext = elemContext.push();
853 /* XSLTC sometimes calls namespaceAfterStartElement()
854 * so we need to remember the name
855 */
856 m_elemContext.m_elementName = name;
857 m_elemContext.m_elementDesc = elemDesc;
858 return;
859 }
860 else
861 {
862 elemContext = elemContext.push(namespaceURI,localName,name);
863 m_elemContext = elemContext;
864 elemContext.m_elementDesc = elemDesc;
865 elemContext.m_isRaw = (elemFlags & ElemDesc.RAW) != 0;
866
867 // set m_startNewLine for the next element
868 if (m_doIndent) {
869 // elemFlags is equivalent to m_elemContext.m_elementDesc.getFlags(),
870 // in this branch m_elemContext.m_elementName is not null
871 boolean isBlockElement = (elemFlags & ElemDesc.BLOCK) != 0;
872 if (isBlockElement)
873 m_startNewLine = true;
874 }
875 }
876
877
878 if ((elemFlags & ElemDesc.HEADELEM) != 0)
879 {
880 // This is the <HEAD> element, do some special processing
881 closeStartTag();
882 elemContext.m_startTagOpen = false;
883 if (!m_omitMetaTag)
884 {
885 if (m_doIndent)
886 indent();
887 writer.write(
888 "<META http-equiv=\"Content-Type\" content=\"text/html; charset=");
889 String encoding = getEncoding();
890 String encode = Encodings.getMimeEncoding(encoding);
891 writer.write(encode);
892 writer.write("\">");
893 }
894 }
898 throw new SAXException(e);
899 }
900 }
901
902 /**
903 * Receive notification of the end of an element.
904 *
905 *
906 * @param namespaceURI
907 * @param localName
908 * @param name The element type name
909 * @throws org.xml.sax.SAXException Any SAX exception, possibly
910 * wrapping another exception.
911 */
912 public final void endElement(
913 final String namespaceURI,
914 final String localName,
915 final String name)
916 throws org.xml.sax.SAXException
917 {
918 flushCharactersBuffer();
919 // deal with any pending issues
920 if (m_cdataTagOpen)
921 closeCDATA();
922
923 // if the element has a namespace, treat it like XML, not HTML
924 if (null != namespaceURI && namespaceURI.length() > 0)
925 {
926 super.endElement(namespaceURI, localName, name);
927
928 return;
929 }
930
931 try
932 {
933
934 ElemContext elemContext = m_elemContext;
935 final ElemDesc elemDesc = elemContext.m_elementDesc;
936 final int elemFlags = elemDesc.getFlags();
937 final boolean elemEmpty = (elemFlags & ElemDesc.EMPTY) != 0;
938
939 // deal with any indentation issues
940 if (m_doIndent)
941 {
942 final boolean isBlockElement = (elemFlags&ElemDesc.BLOCK) != 0;
943 boolean shouldIndent = false;
944
945 // If this element is a block element,
946 // or if this is not a block element, then if the previous is
947 // neither a text nor an inline
948 if (isBlockElement || (!(m_isprevtext || !m_isprevblock)))
949 {
950 m_startNewLine = true;
951 shouldIndent = true;
952 }
953 if (!elemContext.m_startTagOpen && shouldIndent && (m_childNodeNum > 1 || !m_isprevtext))
954 indent(elemContext.m_currentElemDepth - 1);
955
956 m_isprevblock = isBlockElement;
957 }
958
959 final java.io.Writer writer = m_writer;
960 if (!elemContext.m_startTagOpen)
961 {
962 writer.write("</");
963 writer.write(name);
964 writer.write('>');
965 }
966 else
967 {
968 // the start-tag open when this method was called,
969 // so we need to process it now.
970
971 if (m_tracer != null)
972 super.fireStartElem(name);
973
974 // the starting tag was still open when we received this endElement() call
975 // so we need to process any gathered attributes NOW, before they go away.
976 int nAttrs = m_attributes.getLength();
980 // clear attributes object for re-use with next element
981 m_attributes.clear();
982 }
983 if (!elemEmpty)
984 {
985 // As per Dave/Paul recommendation 12/06/2000
986 // if (shouldIndent)
987 // writer.write('>');
988 // indent(m_currentIndent);
989
990 writer.write("></");
991 writer.write(name);
992 writer.write('>');
993 }
994 else
995 {
996 writer.write('>');
997 }
998 }
999
1000 m_childNodeNum = m_childNodeNumStack.pop();
1001 // clean up because the element has ended
1002 if ((elemFlags & ElemDesc.WHITESPACESENSITIVE) != 0)
1003 m_ispreserve = true;
1004 m_isprevtext = false;
1005
1006 // fire off the end element event
1007 if (m_tracer != null)
1008 super.fireEndElem(name);
1009
1010 // OPTIMIZE-EMPTY
1011 if (elemEmpty)
1012 {
1013 // a quick exit if the HTML element had no children.
1014 // This block of code can be removed if the corresponding block of code
1015 // in startElement() also labeled with "OPTIMIZE-EMPTY" is also removed
1016 m_elemContext = elemContext.m_prev;
1017 return;
1018 }
1019
1020 // some more clean because the element has ended.
1518
1519 if (m_elemContext.m_isRaw)
1520 {
1521 try
1522 {
1523 if (m_elemContext.m_startTagOpen)
1524 {
1525 closeStartTag();
1526 m_elemContext.m_startTagOpen = false;
1527 }
1528 m_ispreserve = true;
1529
1530 // With m_ispreserve just set true it looks like shouldIndent()
1531 // will always return false, so drop any possible indentation.
1532 // if (shouldIndent())
1533 // indent();
1534
1535 // writer.write("<![CDATA[");
1536 // writer.write(chars, start, length);
1537 writeNormalizedChars(chars, start, length, false, m_lineSepUse);
1538 m_isprevtext = true;
1539 // writer.write("]]>");
1540
1541 // time to generate characters event
1542 if (m_tracer != null)
1543 super.fireCharEvent(chars, start, length);
1544
1545 return;
1546 }
1547 catch (IOException ioe)
1548 {
1549 throw new org.xml.sax.SAXException(
1550 Utils.messages.createMessage(
1551 MsgKey.ER_OIERROR,
1552 null),
1553 ioe);
1554 //"IO error", ioe);
1555 }
1556 }
1557 else
1558 {
1573 * <p>The application must not attempt to read from the array
1574 * outside of the specified range.</p>
1575 *
1576 * <p>Note that some parsers will report whitespace using the
1577 * ignorableWhitespace() method rather than this one (validating
1578 * parsers must do so).</p>
1579 *
1580 * @param ch The characters from the XML document.
1581 * @param start The start position in the array.
1582 * @param length The number of characters to read from the array.
1583 * @throws org.xml.sax.SAXException Any SAX exception, possibly
1584 * wrapping another exception.
1585 * @see #ignorableWhitespace
1586 * @see org.xml.sax.Locator
1587 *
1588 * @throws org.xml.sax.SAXException
1589 */
1590 public final void cdata(char ch[], int start, int length)
1591 throws org.xml.sax.SAXException
1592 {
1593 if ((null != m_elemContext.m_elementName)
1594 && (m_elemContext.m_elementName.equalsIgnoreCase("SCRIPT")
1595 || m_elemContext.m_elementName.equalsIgnoreCase("STYLE")))
1596 {
1597 try
1598 {
1599 if (m_elemContext.m_startTagOpen)
1600 {
1601 closeStartTag();
1602 m_elemContext.m_startTagOpen = false;
1603 }
1604
1605 m_ispreserve = true;
1606
1607 if (shouldIndent())
1608 indent();
1609
1610 // writer.write(ch, start, length);
1611 writeNormalizedChars(ch, start, length, true, m_lineSepUse);
1612 }
1623 else
1624 {
1625 super.cdata(ch, start, length);
1626 }
1627 }
1628
1629 /**
1630 * Receive notification of a processing instruction.
1631 *
1632 * @param target The processing instruction target.
1633 * @param data The processing instruction data, or null if
1634 * none was supplied.
1635 * @throws org.xml.sax.SAXException Any SAX exception, possibly
1636 * wrapping another exception.
1637 *
1638 * @throws org.xml.sax.SAXException
1639 */
1640 public void processingInstruction(String target, String data)
1641 throws org.xml.sax.SAXException
1642 {
1643 m_childNodeNum++;
1644 flushCharactersBuffer();
1645 // Process any pending starDocument and startElement first.
1646 flushPending();
1647
1648 // Use a fairly nasty hack to tell if the next node is supposed to be
1649 // unescaped text.
1650 if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
1651 {
1652 startNonEscaping();
1653 }
1654 else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING))
1655 {
1656 endNonEscaping();
1657 }
1658 else
1659 {
1660 try
1661 {
1662 if (m_elemContext.m_startTagOpen)
1663 {
1664 closeStartTag();
1952 public void comment(char ch[], int start, int length)
1953 throws SAXException
1954 {
1955 // The internal DTD subset is not serialized by the ToHTMLStream serializer
1956 if (m_inDTD)
1957 return;
1958 super.comment(ch, start, length);
1959 }
1960
1961 public boolean reset()
1962 {
1963 boolean ret = super.reset();
1964 if (!ret)
1965 return false;
1966 initToHTMLStream();
1967 return true;
1968 }
1969
1970 private void initToHTMLStream()
1971 {
1972 m_isprevblock = false;
1973 m_inDTD = false;
1974 m_omitMetaTag = false;
1975 m_specialEscapeURLs = true;
1976 }
1977
1978 static class Trie
1979 {
1980 /**
1981 * A digital search trie for 7-bit ASCII text
1982 * The API is a subset of java.util.Hashtable
1983 * The key must be a 7-bit ASCII string
1984 * The value may be any Java Object
1985 * One can get an object stored in a trie from its key,
1986 * but the search is either case sensitive or case
1987 * insensitive to the characters in the key, and this
1988 * choice of sensitivity or insensitivity is made when
1989 * the Trie is created, before any objects are put in it.
1990 *
1991 * This class is a copy of the one in com.sun.org.apache.xml.internal.utils.
1992 * It exists to cut the serializers dependancy on that package.
1993 *
|