View Javadoc
1   /*
2    * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.bind.v2.runtime;
27  
28  import java.io.IOException;
29  
30  import javax.xml.stream.XMLStreamException;
31  
32  import com.sun.istack.internal.FinalArrayList;
33  import com.sun.istack.internal.SAXException2;
34  
35  import org.xml.sax.Attributes;
36  import org.xml.sax.SAXException;
37  import org.xml.sax.helpers.DefaultHandler;
38  
39  /**
40   * Receives SAX2 events and send the equivalent events to
41   * {@link XMLSerializer}
42   *
43   * @author
44   *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
45   */
46  final class ContentHandlerAdaptor extends DefaultHandler {
47  
48      /** Stores newly declared prefix-URI mapping. */
49      private final FinalArrayList<String> prefixMap = new FinalArrayList<String>();
50  
51      /** Events will be sent to this object. */
52      private final XMLSerializer serializer;
53  
54      private final StringBuffer text = new StringBuffer();
55  
56  
57      ContentHandlerAdaptor( XMLSerializer _serializer ) {
58          this.serializer = _serializer;
59      }
60  
61      public void startDocument() {
62          prefixMap.clear();
63      }
64  
65      public void startPrefixMapping(String prefix, String uri) {
66          prefixMap.add(prefix);
67          prefixMap.add(uri);
68      }
69  
70      private boolean containsPrefixMapping(String prefix, String uri) {
71          for( int i=0; i<prefixMap.size(); i+=2 ) {
72              if(prefixMap.get(i).equals(prefix)
73              && prefixMap.get(i+1).equals(uri))
74                  return true;
75          }
76          return false;
77      }
78  
79      public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
80          throws SAXException {
81          try {
82              flushText();
83  
84              int len = atts.getLength();
85  
86              String p = getPrefix(qName);
87  
88              // is this prefix going to be declared on this element?
89              if(containsPrefixMapping(p,namespaceURI))
90                  serializer.startElementForce(namespaceURI,localName,p,null);
91              else
92                  serializer.startElement(namespaceURI,localName, p,null);
93  
94              // declare namespace events
95              for( int i=0; i<prefixMap.size(); i+=2 ) {
96                  // forcibly set this binding, instead of using declareNsUri.
97                  // this guarantees that namespaces used in DOM will show up
98                  // as-is in the marshalled output (instead of reassigned to something else,
99                  // which may happen if you'd use declareNsUri.)
100                 serializer.getNamespaceContext().force(
101                     prefixMap.get(i+1), prefixMap.get(i) );
102             }
103             // make sure namespaces needed by attributes are bound
104             for( int i=0; i<len; i++ ) {
105                 String qname = atts.getQName(i);
106                 if(qname.startsWith("xmlns") || atts.getURI(i).length() == 0)
107                     continue;
108                 String prefix = getPrefix(qname);
109 
110                 serializer.getNamespaceContext().declareNamespace(
111                     atts.getURI(i), prefix, true );
112             }
113 
114             serializer.endNamespaceDecls(null);
115             // fire attribute events
116             for( int i=0; i<len; i++ ) {
117                 // be defensive.
118                 if(atts.getQName(i).startsWith("xmlns"))
119                     continue;
120                 serializer.attribute( atts.getURI(i), atts.getLocalName(i), atts.getValue(i));
121             }
122             prefixMap.clear();
123             serializer.endAttributes();
124         } catch (IOException e) {
125             throw new SAXException2(e);
126         } catch (XMLStreamException e) {
127             throw new SAXException2(e);
128         }
129     }
130 
131     private String getPrefix(String qname) {
132         int idx = qname.indexOf(':');
133         String prefix = (idx==-1)?qname:qname.substring(0,idx);
134         return prefix;
135     }
136 
137     public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
138         try {
139             flushText();
140             serializer.endElement();
141         } catch (IOException e) {
142             throw new SAXException2(e);
143         } catch (XMLStreamException e) {
144             throw new SAXException2(e);
145         }
146     }
147 
148     private void flushText() throws SAXException, IOException, XMLStreamException {
149         if( text.length()!=0 ) {
150             serializer.text(text.toString(),null);
151             text.setLength(0);
152         }
153     }
154 
155     public void characters(char[] ch, int start, int length) {
156         text.append(ch,start,length);
157     }
158 }