Save This Page
Home » openjdk-7 » com.sun.org.apache.xml.internal » serializer » [javadoc | source]
    1   /*
    2    * reserved comment block
    3    * DO NOT REMOVE OR ALTER!
    4    */
    5   /*
    6    * Copyright 2001-2004 The Apache Software Foundation.
    7    *
    8    * Licensed under the Apache License, Version 2.0 (the "License");
    9    * you may not use this file except in compliance with the License.
   10    * 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    * $Id: ToXMLSAXHandler.java,v 1.3 2005/09/28 13:49:08 pvedula Exp $
   22    */
   23   package com.sun.org.apache.xml.internal.serializer;
   24   
   25   import java.io.IOException;
   26   import java.io.OutputStream;
   27   import java.io.Writer;
   28   import java.util.Properties;
   29   
   30   import javax.xml.transform.Result;
   31   
   32   import org.w3c.dom.Node;
   33   import org.xml.sax.Attributes;
   34   import org.xml.sax.ContentHandler;
   35   import org.xml.sax.Locator;
   36   import org.xml.sax.SAXException;
   37   import org.xml.sax.ext.LexicalHandler;
   38   
   39   /**
   40    * This class receives notification of SAX-like events, and with gathered
   41    * information over these calls it will invoke the equivalent SAX methods
   42    * on a handler, the ultimate xsl:output method is known to be "xml".
   43    *
   44    * This class is not a public API, it is only public because it is used by Xalan.
   45    * @xsl.usage internal
   46    */
   47   public final class ToXMLSAXHandler extends ToSAXHandler
   48   {
   49   
   50       /**
   51        * Keeps track of whether output escaping is currently enabled
   52        */
   53       protected boolean m_escapeSetting = false;
   54   
   55       public ToXMLSAXHandler()
   56       {
   57           // default constructor (need to set content handler ASAP !)
   58           m_prefixMap = new NamespaceMappings();
   59           initCDATA();
   60       }
   61   
   62       /**
   63        * @see Serializer#getOutputFormat()
   64        */
   65       public Properties getOutputFormat()
   66       {
   67           return null;
   68       }
   69   
   70       /**
   71        * @see Serializer#getOutputStream()
   72        */
   73       public OutputStream getOutputStream()
   74       {
   75           return null;
   76       }
   77   
   78       /**
   79        * @see Serializer#getWriter()
   80        */
   81       public Writer getWriter()
   82       {
   83           return null;
   84       }
   85   
   86       /**
   87        * Do nothing for SAX.
   88        */
   89       public void indent(int n) throws SAXException
   90       {
   91       }
   92   
   93   
   94       /**
   95        * @see DOMSerializer#serialize(Node)
   96        */
   97       public void serialize(Node node) throws IOException
   98       {
   99       }
  100   
  101       /**
  102        * @see SerializationHandler#setEscaping(boolean)
  103        */
  104       public boolean setEscaping(boolean escape) throws SAXException
  105       {
  106           boolean oldEscapeSetting = m_escapeSetting;
  107           m_escapeSetting = escape;
  108   
  109           if (escape) {
  110               processingInstruction(Result.PI_ENABLE_OUTPUT_ESCAPING, "");
  111           } else {
  112               processingInstruction(Result.PI_DISABLE_OUTPUT_ESCAPING, "");
  113           }
  114   
  115           return oldEscapeSetting;
  116       }
  117   
  118       /**
  119        * @see Serializer#setOutputFormat(Properties)
  120        */
  121       public void setOutputFormat(Properties format)
  122       {
  123       }
  124   
  125       /**
  126        * @see Serializer#setOutputStream(OutputStream)
  127        */
  128       public void setOutputStream(OutputStream output)
  129       {
  130       }
  131   
  132       /**
  133        * @see Serializer#setWriter(Writer)
  134        */
  135       public void setWriter(Writer writer)
  136       {
  137       }
  138   
  139       /**
  140        * @see org.xml.sax.ext.DeclHandler#attributeDecl(String, String, String, String, String)
  141        */
  142       public void attributeDecl(
  143           String arg0,
  144           String arg1,
  145           String arg2,
  146           String arg3,
  147           String arg4)
  148           throws SAXException
  149       {
  150       }
  151   
  152       /**
  153        * @see org.xml.sax.ext.DeclHandler#elementDecl(String, String)
  154        */
  155       public void elementDecl(String arg0, String arg1) throws SAXException
  156       {
  157       }
  158   
  159       /**
  160        * @see org.xml.sax.ext.DeclHandler#externalEntityDecl(String, String, String)
  161        */
  162       public void externalEntityDecl(String arg0, String arg1, String arg2)
  163           throws SAXException
  164       {
  165       }
  166   
  167       /**
  168        * @see org.xml.sax.ext.DeclHandler#internalEntityDecl(String, String)
  169        */
  170       public void internalEntityDecl(String arg0, String arg1)
  171           throws SAXException
  172       {
  173       }
  174   
  175       /**
  176        * Receives notification of the end of the document.
  177        * @see org.xml.sax.ContentHandler#endDocument()
  178        */
  179       public void endDocument() throws SAXException
  180       {
  181   
  182           flushPending();
  183   
  184           // Close output document
  185           m_saxHandler.endDocument();
  186   
  187           if (m_tracer != null)
  188               super.fireEndDoc();
  189       }
  190   
  191       /**
  192        * This method is called when all the data needed for a call to the
  193        * SAX handler's startElement() method has been gathered.
  194        */
  195       protected void closeStartTag() throws SAXException
  196       {
  197   
  198           m_elemContext.m_startTagOpen = false;
  199   
  200           final String localName = getLocalName(m_elemContext.m_elementName);
  201           final String uri = getNamespaceURI(m_elemContext.m_elementName, true);
  202   
  203           // Now is time to send the startElement event
  204           if (m_needToCallStartDocument)
  205           {
  206               startDocumentInternal();
  207           }
  208           m_saxHandler.startElement(uri, localName, m_elemContext.m_elementName, m_attributes);
  209           // we've sent the official SAX attributes on their way,
  210           // now we don't need them anymore.
  211           m_attributes.clear();
  212   
  213           if(m_state != null)
  214             m_state.setCurrentNode(null);
  215       }
  216   
  217       /**
  218        * Closes ane open cdata tag, and
  219        * unlike the this.endCDATA() method (from the LexicalHandler) interface,
  220        * this "internal" method will send the endCDATA() call to the wrapped
  221        * handler.
  222        *
  223        */
  224       public void closeCDATA() throws SAXException
  225       {
  226   
  227           // Output closing bracket - "]]>"
  228           if (m_lexHandler != null && m_cdataTagOpen) {
  229               m_lexHandler.endCDATA();
  230           }
  231   
  232   
  233           // There are no longer any calls made to
  234           // m_lexHandler.startCDATA() without a balancing call to
  235           // m_lexHandler.endCDATA()
  236           // so we set m_cdataTagOpen to false to remember this.
  237           m_cdataTagOpen = false;
  238       }
  239   
  240       /**
  241        * @see org.xml.sax.ContentHandler#endElement(String, String, String)
  242        */
  243       public void endElement(String namespaceURI, String localName, String qName)
  244           throws SAXException
  245       {
  246           // Close any open elements etc.
  247           flushPending();
  248   
  249           if (namespaceURI == null)
  250           {
  251               if (m_elemContext.m_elementURI != null)
  252                   namespaceURI = m_elemContext.m_elementURI;
  253               else
  254                   namespaceURI = getNamespaceURI(qName, true);
  255           }
  256   
  257           if (localName == null)
  258           {
  259               if (m_elemContext.m_elementLocalName != null)
  260                   localName = m_elemContext.m_elementLocalName;
  261               else
  262                   localName = getLocalName(qName);
  263           }
  264   
  265           m_saxHandler.endElement(namespaceURI, localName, qName);
  266   
  267           if (m_tracer != null)
  268               super.fireEndElem(qName);
  269   
  270           /* Pop all namespaces at the current element depth.
  271            * We are not waiting for official endPrefixMapping() calls.
  272            */
  273           m_prefixMap.popNamespaces(m_elemContext.m_currentElemDepth,
  274               m_saxHandler);
  275           m_elemContext = m_elemContext.m_prev;
  276       }
  277   
  278       /**
  279        * @see org.xml.sax.ContentHandler#endPrefixMapping(String)
  280        */
  281       public void endPrefixMapping(String prefix) throws SAXException
  282       {
  283           /* poping all prefix mappings should have been done
  284            * in endElement() already
  285            */
  286            return;
  287       }
  288   
  289       /**
  290        * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
  291        */
  292       public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
  293           throws SAXException
  294       {
  295           m_saxHandler.ignorableWhitespace(arg0,arg1,arg2);
  296       }
  297   
  298       /**
  299        * @see org.xml.sax.ContentHandler#setDocumentLocator(Locator)
  300        */
  301       public void setDocumentLocator(Locator arg0)
  302       {
  303           super.setDocumentLocator(arg0);
  304           m_saxHandler.setDocumentLocator(arg0);
  305       }
  306   
  307       /**
  308        * @see org.xml.sax.ContentHandler#skippedEntity(String)
  309        */
  310       public void skippedEntity(String arg0) throws SAXException
  311       {
  312           m_saxHandler.skippedEntity(arg0);
  313       }
  314   
  315       /**
  316        * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
  317        * @param prefix The prefix that maps to the URI
  318        * @param uri The URI for the namespace
  319        */
  320       public void startPrefixMapping(String prefix, String uri)
  321           throws SAXException
  322       {
  323          startPrefixMapping(prefix, uri, true);
  324       }
  325   
  326       /**
  327        * Remember the prefix/uri mapping at the current nested element depth.
  328        *
  329        * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
  330        * @param prefix The prefix that maps to the URI
  331        * @param uri The URI for the namespace
  332        * @param shouldFlush a flag indicating if the mapping applies to the
  333        * current element or an up coming child (not used).
  334        */
  335   
  336       public boolean startPrefixMapping(
  337           String prefix,
  338           String uri,
  339           boolean shouldFlush)
  340           throws org.xml.sax.SAXException
  341       {
  342   
  343           /* Remember the mapping, and at what depth it was declared
  344            * This is one greater than the current depth because these
  345            * mappings will apply to the next depth. This is in
  346            * consideration that startElement() will soon be called
  347            */
  348   
  349           boolean pushed;
  350           int pushDepth;
  351           if (shouldFlush)
  352           {
  353               flushPending();
  354               // the prefix mapping applies to the child element (one deeper)
  355               pushDepth = m_elemContext.m_currentElemDepth + 1;
  356           }
  357           else
  358           {
  359               // the prefix mapping applies to the current element
  360               pushDepth = m_elemContext.m_currentElemDepth;
  361           }
  362           pushed = m_prefixMap.pushNamespace(prefix, uri, pushDepth);
  363   
  364           if (pushed)
  365           {
  366               m_saxHandler.startPrefixMapping(prefix,uri);
  367   
  368               if (getShouldOutputNSAttr())
  369               {
  370   
  371                         /* Brian M.: don't know if we really needto do this. The
  372                          * callers of this object should have injected both
  373                          * startPrefixMapping and the attributes.  We are
  374                          * just covering our butt here.
  375                          */
  376                         String name;
  377                       if (EMPTYSTRING.equals(prefix))
  378                       {
  379                           name = "xmlns";
  380                           addAttributeAlways(XMLNS_URI, name, name,"CDATA",uri, false);
  381                       }
  382                       else
  383                   {
  384                           if (!EMPTYSTRING.equals(uri)) // hack for XSLTC attribset16 test
  385                           {                             // that maps ns1 prefix to "" URI
  386                               name = "xmlns:" + prefix;
  387   
  388                               /* for something like xmlns:abc="w3.pretend.org"
  389                                        *  the uri is the value, that is why we pass it in the
  390                                        * value, or 5th slot of addAttributeAlways()
  391                                      */
  392                               addAttributeAlways(XMLNS_URI, prefix, name,"CDATA",uri, false );
  393                           }
  394                       }
  395               }
  396           }
  397           return pushed;
  398       }
  399   
  400   
  401       /**
  402        * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
  403        */
  404       public void comment(char[] arg0, int arg1, int arg2) throws SAXException
  405       {
  406           flushPending();
  407           if (m_lexHandler != null)
  408               m_lexHandler.comment(arg0, arg1, arg2);
  409   
  410           if (m_tracer != null)
  411               super.fireCommentEvent(arg0, arg1, arg2);
  412       }
  413   
  414       /**
  415        * @see org.xml.sax.ext.LexicalHandler#endCDATA()
  416        */
  417       public void endCDATA() throws SAXException
  418       {
  419           /* Normally we would do somthing with this but we ignore it.
  420            * The neccessary call to m_lexHandler.endCDATA() will be made
  421            * in flushPending().
  422            *
  423            * This is so that if we get calls like these:
  424            *   this.startCDATA();
  425            *   this.characters(chars1, off1, len1);
  426            *   this.endCDATA();
  427            *   this.startCDATA();
  428            *   this.characters(chars2, off2, len2);
  429            *   this.endCDATA();
  430            *
  431            * that we will only make these calls to the wrapped handlers:
  432            *
  433            *   m_lexHandler.startCDATA();
  434            *   m_saxHandler.characters(chars1, off1, len1);
  435            *   m_saxHandler.characters(chars1, off2, len2);
  436            *   m_lexHandler.endCDATA();
  437            *
  438            * We will merge adjacent CDATA blocks.
  439            */
  440       }
  441   
  442       /**
  443        * @see org.xml.sax.ext.LexicalHandler#endDTD()
  444        */
  445       public void endDTD() throws SAXException
  446       {
  447           if (m_lexHandler != null)
  448               m_lexHandler.endDTD();
  449       }
  450   
  451       /**
  452        * @see org.xml.sax.ext.LexicalHandler#startEntity(String)
  453        */
  454       public void startEntity(String arg0) throws SAXException
  455       {
  456           if (m_lexHandler != null)
  457               m_lexHandler.startEntity(arg0);
  458       }
  459   
  460       /**
  461        * @see ExtendedContentHandler#characters(String)
  462        */
  463       public void characters(String chars) throws SAXException
  464       {
  465           final int length = chars.length();
  466           if (length > m_charsBuff.length)
  467           {
  468               m_charsBuff = new char[length*2 + 1];
  469           }
  470           chars.getChars(0, length, m_charsBuff, 0);
  471           this.characters(m_charsBuff, 0, length);
  472       }
  473   
  474       /////////////////// from XSLTC //////////////
  475       public ToXMLSAXHandler(ContentHandler handler, String encoding)
  476       {
  477           super(handler, encoding);
  478   
  479           initCDATA();
  480           // initNamespaces();
  481           m_prefixMap = new NamespaceMappings();
  482       }
  483   
  484       public ToXMLSAXHandler(
  485           ContentHandler handler,
  486           LexicalHandler lex,
  487           String encoding)
  488       {
  489           super(handler, lex, encoding);
  490   
  491           initCDATA();
  492           //      initNamespaces();
  493           m_prefixMap = new NamespaceMappings();
  494       }
  495   
  496       /**
  497        * Start an element in the output document. This might be an XML element
  498        * (<elem>data</elem> type) or a CDATA section.
  499        */
  500       public void startElement(
  501       String elementNamespaceURI,
  502       String elementLocalName,
  503       String elementName) throws SAXException
  504       {
  505           startElement(
  506               elementNamespaceURI,elementLocalName,elementName, null);
  507   
  508   
  509       }
  510       public void startElement(String elementName) throws SAXException
  511       {
  512           startElement(null, null, elementName, null);
  513       }
  514   
  515   
  516       public void characters(char[] ch, int off, int len) throws SAXException
  517       {
  518           // We do the first two things in flushPending() but we don't
  519           // close any open CDATA calls.
  520           if (m_needToCallStartDocument)
  521           {
  522               startDocumentInternal();
  523               m_needToCallStartDocument = false;
  524           }
  525   
  526           if (m_elemContext.m_startTagOpen)
  527           {
  528               closeStartTag();
  529               m_elemContext.m_startTagOpen = false;
  530           }
  531   
  532           if (m_elemContext.m_isCdataSection && !m_cdataTagOpen
  533           && m_lexHandler != null)
  534           {
  535               m_lexHandler.startCDATA();
  536               // We have made a call to m_lexHandler.startCDATA() with
  537               // no balancing call to m_lexHandler.endCDATA()
  538               // so we set m_cdataTagOpen true to remember this.
  539               m_cdataTagOpen = true;
  540           }
  541   
  542           /* If there are any occurances of "]]>" in the character data
  543            * let m_saxHandler worry about it, we've already warned them with
  544            * the previous call of m_lexHandler.startCDATA();
  545            */
  546           m_saxHandler.characters(ch, off, len);
  547   
  548           // time to generate characters event
  549           if (m_tracer != null)
  550               fireCharEvent(ch, off, len);
  551       }
  552   
  553   
  554       /**
  555        * @see ExtendedContentHandler#endElement(String)
  556        */
  557       public void endElement(String elemName) throws SAXException
  558       {
  559           endElement(null, null, elemName);
  560       }
  561   
  562   
  563       /**
  564        * Send a namespace declaration in the output document. The namespace
  565        * declaration will not be include if the namespace is already in scope
  566        * with the same prefix.
  567        */
  568       public void namespaceAfterStartElement(
  569           final String prefix,
  570           final String uri)
  571           throws SAXException
  572       {
  573           startPrefixMapping(prefix,uri,false);
  574       }
  575   
  576       /**
  577        *
  578        * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
  579        * Send a processing instruction to the output document
  580        */
  581       public void processingInstruction(String target, String data)
  582           throws SAXException
  583       {
  584           flushPending();
  585   
  586           // Pass the processing instruction to the SAX handler
  587           m_saxHandler.processingInstruction(target, data);
  588   
  589           // we don't want to leave serializer to fire off this event,
  590           // so do it here.
  591           if (m_tracer != null)
  592               super.fireEscapingEvent(target, data);
  593       }
  594   
  595       /**
  596        * Undeclare the namespace that is currently pointed to by a given
  597        * prefix. Inform SAX handler if prefix was previously mapped.
  598        */
  599       protected boolean popNamespace(String prefix)
  600       {
  601           try
  602           {
  603               if (m_prefixMap.popNamespace(prefix))
  604               {
  605                   m_saxHandler.endPrefixMapping(prefix);
  606                   return true;
  607               }
  608           }
  609           catch (SAXException e)
  610           {
  611               // falls through
  612           }
  613           return false;
  614       }
  615   
  616       public void startCDATA() throws SAXException
  617       {
  618           /* m_cdataTagOpen can only be true here if we have ignored the
  619            * previous call to this.endCDATA() and the previous call
  620            * this.startCDATA() before that is still "open". In this way
  621            * we merge adjacent CDATA. If anything else happened after the
  622            * ignored call to this.endCDATA() and this call then a call to
  623            * flushPending() would have been made which would have
  624            * closed the CDATA and set m_cdataTagOpen to false.
  625            */
  626           if (!m_cdataTagOpen )
  627           {
  628               flushPending();
  629               if (m_lexHandler != null) {
  630                   m_lexHandler.startCDATA();
  631   
  632                   // We have made a call to m_lexHandler.startCDATA() with
  633                   // no balancing call to m_lexHandler.endCDATA()
  634                   // so we set m_cdataTagOpen true to remember this.
  635                   m_cdataTagOpen = true;
  636               }
  637           }
  638       }
  639   
  640       /**
  641        * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
  642        */
  643       public void startElement(
  644       String namespaceURI,
  645       String localName,
  646       String name,
  647       Attributes atts)
  648           throws SAXException
  649       {
  650           flushPending();
  651           super.startElement(namespaceURI, localName, name, atts);
  652   
  653           // Handle document type declaration (for first element only)
  654            if (m_needToOutputDocTypeDecl)
  655            {
  656                String doctypeSystem = getDoctypeSystem();
  657                if (doctypeSystem != null && m_lexHandler != null)
  658                {
  659                    String doctypePublic = getDoctypePublic();
  660                    if (doctypeSystem != null)
  661                        m_lexHandler.startDTD(
  662                            name,
  663                            doctypePublic,
  664                            doctypeSystem);
  665                }
  666                m_needToOutputDocTypeDecl = false;
  667            }
  668           m_elemContext = m_elemContext.push(namespaceURI, localName, name);
  669   
  670           // ensurePrefixIsDeclared depends on the current depth, so
  671           // the previous increment is necessary where it is.
  672           if (namespaceURI != null)
  673               ensurePrefixIsDeclared(namespaceURI, name);
  674   
  675           // add the attributes to the collected ones
  676           if (atts != null)
  677               addAttributes(atts);
  678   
  679   
  680           // do we really need this CDATA section state?
  681           m_elemContext.m_isCdataSection = isCdataSection();
  682   
  683       }
  684   
  685       private void ensurePrefixIsDeclared(String ns, String rawName)
  686           throws org.xml.sax.SAXException
  687       {
  688   
  689           if (ns != null && ns.length() > 0)
  690           {
  691               int index;
  692               final boolean no_prefix = ((index = rawName.indexOf(":")) < 0);
  693               String prefix = (no_prefix) ? "" : rawName.substring(0, index);
  694   
  695   
  696               if (null != prefix)
  697               {
  698                   String foundURI = m_prefixMap.lookupNamespace(prefix);
  699   
  700                   if ((null == foundURI) || !foundURI.equals(ns))
  701                   {
  702                       this.startPrefixMapping(prefix, ns, false);
  703   
  704                       if (getShouldOutputNSAttr()) {
  705                           // Bugzilla1133: Generate attribute as well as namespace event.
  706                           // SAX does expect both.
  707                           this.addAttributeAlways(
  708                               "http://www.w3.org/2000/xmlns/",
  709                               no_prefix ? "xmlns" : prefix,  // local name
  710                               no_prefix ? "xmlns" : ("xmlns:"+ prefix), // qname
  711                               "CDATA",
  712                               ns,
  713                               false);
  714                       }
  715                   }
  716   
  717               }
  718           }
  719       }
  720       /**
  721        * Adds the given attribute to the set of attributes, and also makes sure
  722        * that the needed prefix/uri mapping is declared, but only if there is a
  723        * currently open element.
  724        *
  725        * @param uri the URI of the attribute
  726        * @param localName the local name of the attribute
  727        * @param rawName    the qualified name of the attribute
  728        * @param type the type of the attribute (probably CDATA)
  729        * @param value the value of the attribute
  730        * @param XSLAttribute true if this attribute is coming from an xsl:attribute element
  731        * @see ExtendedContentHandler#addAttribute(String, String, String, String, String)
  732        */
  733       public void addAttribute(
  734           String uri,
  735           String localName,
  736           String rawName,
  737           String type,
  738           String value,
  739           boolean XSLAttribute)
  740           throws SAXException
  741       {
  742           if (m_elemContext.m_startTagOpen)
  743           {
  744               ensurePrefixIsDeclared(uri, rawName);
  745               addAttributeAlways(uri, localName, rawName, type, value, false);
  746           }
  747   
  748       }
  749   
  750       /**
  751        * Try's to reset the super class and reset this class for
  752        * re-use, so that you don't need to create a new serializer
  753        * (mostly for performance reasons).
  754        *
  755        * @return true if the class was successfuly reset.
  756        * @see Serializer#reset()
  757        */
  758       public boolean reset()
  759       {
  760           boolean wasReset = false;
  761           if (super.reset())
  762           {
  763               resetToXMLSAXHandler();
  764               wasReset = true;
  765           }
  766           return wasReset;
  767       }
  768   
  769       /**
  770        * Reset all of the fields owned by ToXMLSAXHandler class
  771        *
  772        */
  773       private void resetToXMLSAXHandler()
  774       {
  775           this.m_escapeSetting = false;
  776       }
  777   
  778   }

Save This Page
Home » openjdk-7 » com.sun.org.apache.xml.internal » serializer » [javadoc | source]