Thu, 12 Oct 2017 19:44:07 +0800
merge
1 /*
2 * Copyright (c) 1997, 2010, 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 */
26 package com.sun.xml.internal.bind.unmarshaller;
28 import java.util.Enumeration;
30 import javax.xml.bind.ValidationEventLocator;
31 import javax.xml.bind.helpers.AbstractUnmarshallerImpl;
32 import javax.xml.bind.helpers.ValidationEventLocatorImpl;
34 import com.sun.xml.internal.bind.v2.runtime.unmarshaller.LocatorEx;
36 import org.w3c.dom.Attr;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Element;
39 import org.w3c.dom.NamedNodeMap;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42 import org.w3c.dom.ProcessingInstruction;
43 import org.xml.sax.ContentHandler;
44 import org.xml.sax.Locator;
45 import org.xml.sax.SAXException;
46 import org.xml.sax.helpers.AttributesImpl;
47 import org.xml.sax.helpers.NamespaceSupport;
49 /**
50 * Visits a W3C DOM tree and generates SAX2 events from it.
51 *
52 * <p>
53 * This class is just intended to be used by {@link AbstractUnmarshallerImpl}.
54 * The javax.xml.bind.helpers package is generally a wrong place to put
55 * classes like this.
56 *
57 * @author <ul><li>Kohsuke Kawaguchi, Sun Microsystems, Inc.</li></ul>
58 * @since JAXB1.0
59 */
60 public class DOMScanner implements LocatorEx,InfosetScanner/*<Node> --- but can't do this to protect 1.0 clients, or can I? */
61 {
63 /** reference to the current node being scanned - used for determining
64 * location info for validation events */
65 private Node currentNode = null;
67 /** To save memory, only one instance of AttributesImpl will be used. */
68 private final AttributesImpl atts = new AttributesImpl();
70 /** This handler will receive SAX2 events. */
71 private ContentHandler receiver=null;
73 private Locator locator=this;
75 public DOMScanner() {
76 }
79 /**
80 * Configures the locator object that the SAX {@link ContentHandler} will see.
81 */
82 public void setLocator( Locator loc ) {
83 this.locator = loc;
84 }
86 public void scan(Object node) throws SAXException {
87 if( node instanceof Document ) {
88 scan( (Document)node );
89 } else {
90 scan( (Element)node );
91 }
92 }
94 public void scan( Document doc ) throws SAXException {
95 scan( doc.getDocumentElement() );
96 }
98 public void scan( Element e) throws SAXException {
99 setCurrentLocation( e );
101 receiver.setDocumentLocator(locator);
102 receiver.startDocument();
104 NamespaceSupport nss = new NamespaceSupport();
105 buildNamespaceSupport( nss, e.getParentNode() );
107 for( Enumeration en = nss.getPrefixes(); en.hasMoreElements(); ) {
108 String prefix = (String)en.nextElement();
109 receiver.startPrefixMapping( prefix, nss.getURI(prefix) );
110 }
112 visit(e);
114 for( Enumeration en = nss.getPrefixes(); en.hasMoreElements(); ) {
115 String prefix = (String)en.nextElement();
116 receiver.endPrefixMapping( prefix );
117 }
120 setCurrentLocation( e );
121 receiver.endDocument();
122 }
124 /**
125 * Parses a subtree starting from the element e and
126 * reports SAX2 events to the specified handler.
127 *
128 * @deprecated in JAXB 2.0
129 * Use {@link #scan(Element)}
130 */
131 public void parse( Element e, ContentHandler handler ) throws SAXException {
132 // it might be better to set receiver at the constructor.
133 receiver = handler;
135 setCurrentLocation( e );
136 receiver.startDocument();
138 receiver.setDocumentLocator(locator);
139 visit(e);
141 setCurrentLocation( e );
142 receiver.endDocument();
143 }
145 /**
146 * Similar to the parse method but it visits the ancestor nodes
147 * and properly emulate the all in-scope namespace declarations.
148 *
149 * @deprecated in JAXB 2.0
150 * Use {@link #scan(Element)}
151 */
152 public void parseWithContext( Element e, ContentHandler handler ) throws SAXException {
153 setContentHandler(handler);
154 scan(e);
155 }
157 /**
158 * Recursively visit ancestors and build up {@link NamespaceSupport} oject.
159 */
160 private void buildNamespaceSupport(NamespaceSupport nss, Node node) {
161 if(node==null || node.getNodeType()!=Node.ELEMENT_NODE)
162 return;
164 buildNamespaceSupport( nss, node.getParentNode() );
166 nss.pushContext();
167 NamedNodeMap atts = node.getAttributes();
168 for( int i=0; i<atts.getLength(); i++ ) {
169 Attr a = (Attr)atts.item(i);
170 if( "xmlns".equals(a.getPrefix()) ) {
171 nss.declarePrefix( a.getLocalName(), a.getValue() );
172 continue;
173 }
174 if( "xmlns".equals(a.getName()) ) {
175 nss.declarePrefix( "", a.getValue() );
176 continue;
177 }
178 }
179 }
181 /**
182 * Visits an element and its subtree.
183 */
184 public void visit( Element e ) throws SAXException {
185 setCurrentLocation( e );
186 final NamedNodeMap attributes = e.getAttributes();
188 atts.clear();
189 int len = attributes==null ? 0: attributes.getLength();
191 for( int i=len-1; i>=0; i-- ) {
192 Attr a = (Attr)attributes.item(i);
193 String name = a.getName();
194 // start namespace binding
195 if(name.startsWith("xmlns")) {
196 if(name.length()==5) {
197 receiver.startPrefixMapping( "", a.getValue() );
198 } else {
199 String localName = a.getLocalName();
200 if(localName==null) {
201 // DOM built without namespace support has this problem
202 localName = name.substring(6);
203 }
204 receiver.startPrefixMapping( localName, a.getValue() );
205 }
206 continue;
207 }
209 String uri = a.getNamespaceURI();
210 if(uri==null) uri="";
212 String local = a.getLocalName();
213 if(local==null) local = a.getName();
214 // add other attributes to the attribute list
215 // that we will pass to the ContentHandler
216 atts.addAttribute(
217 uri,
218 local,
219 a.getName(),
220 "CDATA",
221 a.getValue());
222 }
224 String uri = e.getNamespaceURI();
225 if(uri==null) uri="";
226 String local = e.getLocalName();
227 String qname = e.getTagName();
228 if(local==null) local = qname;
229 receiver.startElement( uri, local, qname, atts );
231 // visit its children
232 NodeList children = e.getChildNodes();
233 int clen = children.getLength();
234 for( int i=0; i<clen; i++ )
235 visit(children.item(i));
239 setCurrentLocation( e );
240 receiver.endElement( uri, local, qname );
242 // call the endPrefixMapping method
243 for( int i=len-1; i>=0; i-- ) {
244 Attr a = (Attr)attributes.item(i);
245 String name = a.getName();
246 if(name.startsWith("xmlns")) {
247 if(name.length()==5)
248 receiver.endPrefixMapping("");
249 else
250 receiver.endPrefixMapping(a.getLocalName());
251 }
252 }
253 }
255 private void visit( Node n ) throws SAXException {
256 setCurrentLocation( n );
258 // if a case statement gets too big, it should be made into a separate method.
259 switch(n.getNodeType()) {
260 case Node.CDATA_SECTION_NODE:
261 case Node.TEXT_NODE:
262 String value = n.getNodeValue();
263 receiver.characters( value.toCharArray(), 0, value.length() );
264 break;
265 case Node.ELEMENT_NODE:
266 visit( (Element)n );
267 break;
268 case Node.ENTITY_REFERENCE_NODE:
269 receiver.skippedEntity(n.getNodeName());
270 break;
271 case Node.PROCESSING_INSTRUCTION_NODE:
272 ProcessingInstruction pi = (ProcessingInstruction)n;
273 receiver.processingInstruction(pi.getTarget(),pi.getData());
274 break;
275 }
276 }
278 private void setCurrentLocation( Node currNode ) {
279 currentNode = currNode;
280 }
282 /**
283 * The same as {@link #getCurrentElement()} but
284 * better typed.
285 */
286 public Node getCurrentLocation() {
287 return currentNode;
288 }
290 public Object getCurrentElement() {
291 return currentNode;
292 }
294 public LocatorEx getLocator() {
295 return this;
296 }
298 public void setContentHandler(ContentHandler handler) {
299 this.receiver = handler;
300 }
302 public ContentHandler getContentHandler() {
303 return this.receiver;
304 }
307 // LocatorEx implementation
308 public String getPublicId() { return null; }
309 public String getSystemId() { return null; }
310 public int getLineNumber() { return -1; }
311 public int getColumnNumber() { return -1; }
313 public ValidationEventLocator getLocation() {
314 return new ValidationEventLocatorImpl(getCurrentLocation());
315 }
316 }