aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.bind.unmarshaller; aoqi@0: aoqi@0: import java.util.Enumeration; aoqi@0: aoqi@0: import javax.xml.bind.ValidationEventLocator; aoqi@0: import javax.xml.bind.helpers.AbstractUnmarshallerImpl; aoqi@0: import javax.xml.bind.helpers.ValidationEventLocatorImpl; aoqi@0: aoqi@0: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.LocatorEx; aoqi@0: aoqi@0: import org.w3c.dom.Attr; aoqi@0: import org.w3c.dom.Document; aoqi@0: import org.w3c.dom.Element; aoqi@0: import org.w3c.dom.NamedNodeMap; aoqi@0: import org.w3c.dom.Node; aoqi@0: import org.w3c.dom.NodeList; aoqi@0: import org.w3c.dom.ProcessingInstruction; aoqi@0: import org.xml.sax.ContentHandler; aoqi@0: import org.xml.sax.Locator; aoqi@0: import org.xml.sax.SAXException; aoqi@0: import org.xml.sax.helpers.AttributesImpl; aoqi@0: import org.xml.sax.helpers.NamespaceSupport; aoqi@0: aoqi@0: /** aoqi@0: * Visits a W3C DOM tree and generates SAX2 events from it. aoqi@0: * aoqi@0: *

aoqi@0: * This class is just intended to be used by {@link AbstractUnmarshallerImpl}. aoqi@0: * The javax.xml.bind.helpers package is generally a wrong place to put aoqi@0: * classes like this. aoqi@0: * aoqi@0: * @author

aoqi@0: * @since JAXB1.0 aoqi@0: */ aoqi@0: public class DOMScanner implements LocatorEx,InfosetScanner/* --- but can't do this to protect 1.0 clients, or can I? */ aoqi@0: { aoqi@0: aoqi@0: /** reference to the current node being scanned - used for determining aoqi@0: * location info for validation events */ aoqi@0: private Node currentNode = null; aoqi@0: aoqi@0: /** To save memory, only one instance of AttributesImpl will be used. */ aoqi@0: private final AttributesImpl atts = new AttributesImpl(); aoqi@0: aoqi@0: /** This handler will receive SAX2 events. */ aoqi@0: private ContentHandler receiver=null; aoqi@0: aoqi@0: private Locator locator=this; aoqi@0: aoqi@0: public DOMScanner() { aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * Configures the locator object that the SAX {@link ContentHandler} will see. aoqi@0: */ aoqi@0: public void setLocator( Locator loc ) { aoqi@0: this.locator = loc; aoqi@0: } aoqi@0: aoqi@0: public void scan(Object node) throws SAXException { aoqi@0: if( node instanceof Document ) { aoqi@0: scan( (Document)node ); aoqi@0: } else { aoqi@0: scan( (Element)node ); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void scan( Document doc ) throws SAXException { aoqi@0: scan( doc.getDocumentElement() ); aoqi@0: } aoqi@0: aoqi@0: public void scan( Element e) throws SAXException { aoqi@0: setCurrentLocation( e ); aoqi@0: aoqi@0: receiver.setDocumentLocator(locator); aoqi@0: receiver.startDocument(); aoqi@0: aoqi@0: NamespaceSupport nss = new NamespaceSupport(); aoqi@0: buildNamespaceSupport( nss, e.getParentNode() ); aoqi@0: aoqi@0: for( Enumeration en = nss.getPrefixes(); en.hasMoreElements(); ) { aoqi@0: String prefix = (String)en.nextElement(); aoqi@0: receiver.startPrefixMapping( prefix, nss.getURI(prefix) ); aoqi@0: } aoqi@0: aoqi@0: visit(e); aoqi@0: aoqi@0: for( Enumeration en = nss.getPrefixes(); en.hasMoreElements(); ) { aoqi@0: String prefix = (String)en.nextElement(); aoqi@0: receiver.endPrefixMapping( prefix ); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: setCurrentLocation( e ); aoqi@0: receiver.endDocument(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Parses a subtree starting from the element e and aoqi@0: * reports SAX2 events to the specified handler. aoqi@0: * aoqi@0: * @deprecated in JAXB 2.0 aoqi@0: * Use {@link #scan(Element)} aoqi@0: */ aoqi@0: public void parse( Element e, ContentHandler handler ) throws SAXException { aoqi@0: // it might be better to set receiver at the constructor. aoqi@0: receiver = handler; aoqi@0: aoqi@0: setCurrentLocation( e ); aoqi@0: receiver.startDocument(); aoqi@0: aoqi@0: receiver.setDocumentLocator(locator); aoqi@0: visit(e); aoqi@0: aoqi@0: setCurrentLocation( e ); aoqi@0: receiver.endDocument(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Similar to the parse method but it visits the ancestor nodes aoqi@0: * and properly emulate the all in-scope namespace declarations. aoqi@0: * aoqi@0: * @deprecated in JAXB 2.0 aoqi@0: * Use {@link #scan(Element)} aoqi@0: */ aoqi@0: public void parseWithContext( Element e, ContentHandler handler ) throws SAXException { aoqi@0: setContentHandler(handler); aoqi@0: scan(e); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Recursively visit ancestors and build up {@link NamespaceSupport} oject. aoqi@0: */ aoqi@0: private void buildNamespaceSupport(NamespaceSupport nss, Node node) { aoqi@0: if(node==null || node.getNodeType()!=Node.ELEMENT_NODE) aoqi@0: return; aoqi@0: aoqi@0: buildNamespaceSupport( nss, node.getParentNode() ); aoqi@0: aoqi@0: nss.pushContext(); aoqi@0: NamedNodeMap atts = node.getAttributes(); aoqi@0: for( int i=0; i=0; i-- ) { aoqi@0: Attr a = (Attr)attributes.item(i); aoqi@0: String name = a.getName(); aoqi@0: // start namespace binding aoqi@0: if(name.startsWith("xmlns")) { aoqi@0: if(name.length()==5) { aoqi@0: receiver.startPrefixMapping( "", a.getValue() ); aoqi@0: } else { aoqi@0: String localName = a.getLocalName(); aoqi@0: if(localName==null) { aoqi@0: // DOM built without namespace support has this problem aoqi@0: localName = name.substring(6); aoqi@0: } aoqi@0: receiver.startPrefixMapping( localName, a.getValue() ); aoqi@0: } aoqi@0: continue; aoqi@0: } aoqi@0: aoqi@0: String uri = a.getNamespaceURI(); aoqi@0: if(uri==null) uri=""; aoqi@0: aoqi@0: String local = a.getLocalName(); aoqi@0: if(local==null) local = a.getName(); aoqi@0: // add other attributes to the attribute list aoqi@0: // that we will pass to the ContentHandler aoqi@0: atts.addAttribute( aoqi@0: uri, aoqi@0: local, aoqi@0: a.getName(), aoqi@0: "CDATA", aoqi@0: a.getValue()); aoqi@0: } aoqi@0: aoqi@0: String uri = e.getNamespaceURI(); aoqi@0: if(uri==null) uri=""; aoqi@0: String local = e.getLocalName(); aoqi@0: String qname = e.getTagName(); aoqi@0: if(local==null) local = qname; aoqi@0: receiver.startElement( uri, local, qname, atts ); aoqi@0: aoqi@0: // visit its children aoqi@0: NodeList children = e.getChildNodes(); aoqi@0: int clen = children.getLength(); aoqi@0: for( int i=0; i=0; i-- ) { aoqi@0: Attr a = (Attr)attributes.item(i); aoqi@0: String name = a.getName(); aoqi@0: if(name.startsWith("xmlns")) { aoqi@0: if(name.length()==5) aoqi@0: receiver.endPrefixMapping(""); aoqi@0: else aoqi@0: receiver.endPrefixMapping(a.getLocalName()); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void visit( Node n ) throws SAXException { aoqi@0: setCurrentLocation( n ); aoqi@0: aoqi@0: // if a case statement gets too big, it should be made into a separate method. aoqi@0: switch(n.getNodeType()) { aoqi@0: case Node.CDATA_SECTION_NODE: aoqi@0: case Node.TEXT_NODE: aoqi@0: String value = n.getNodeValue(); aoqi@0: receiver.characters( value.toCharArray(), 0, value.length() ); aoqi@0: break; aoqi@0: case Node.ELEMENT_NODE: aoqi@0: visit( (Element)n ); aoqi@0: break; aoqi@0: case Node.ENTITY_REFERENCE_NODE: aoqi@0: receiver.skippedEntity(n.getNodeName()); aoqi@0: break; aoqi@0: case Node.PROCESSING_INSTRUCTION_NODE: aoqi@0: ProcessingInstruction pi = (ProcessingInstruction)n; aoqi@0: receiver.processingInstruction(pi.getTarget(),pi.getData()); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private void setCurrentLocation( Node currNode ) { aoqi@0: currentNode = currNode; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * The same as {@link #getCurrentElement()} but aoqi@0: * better typed. aoqi@0: */ aoqi@0: public Node getCurrentLocation() { aoqi@0: return currentNode; aoqi@0: } aoqi@0: aoqi@0: public Object getCurrentElement() { aoqi@0: return currentNode; aoqi@0: } aoqi@0: aoqi@0: public LocatorEx getLocator() { aoqi@0: return this; aoqi@0: } aoqi@0: aoqi@0: public void setContentHandler(ContentHandler handler) { aoqi@0: this.receiver = handler; aoqi@0: } aoqi@0: aoqi@0: public ContentHandler getContentHandler() { aoqi@0: return this.receiver; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: // LocatorEx implementation aoqi@0: public String getPublicId() { return null; } aoqi@0: public String getSystemId() { return null; } aoqi@0: public int getLineNumber() { return -1; } aoqi@0: public int getColumnNumber() { return -1; } aoqi@0: aoqi@0: public ValidationEventLocator getLocation() { aoqi@0: return new ValidationEventLocatorImpl(getCurrentLocation()); aoqi@0: } aoqi@0: }