| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cocoon.xml; |
| |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| import java.util.Vector; |
| |
| import org.xml.sax.AttributeList; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.DocumentHandler; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.helpers.AttributesImpl; |
| |
| /** |
| * This class is an utility class "adapting" a SAX version 1.0 |
| * <code>DocumentHandler</code>, to SAX version 2 <code>ContentHandler</code>. |
| * <br> |
| * This class fully supports XML namespaces, converting <code>xmlns</code> and |
| * <code>xmlns:...</code> element attributes into appropriate |
| * <code>startPrefixMapping(...)</code> and <code>endPrefixMapping(...)</code> |
| * calls. |
| * |
| * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a> |
| * (Apache Software Foundation) |
| * @version CVS $Id$ |
| */ |
| public class DocumentHandlerAdapter extends AbstractXMLProducer |
| implements DocumentHandler { |
| |
| /** The element-oriented namespace-uri stacked mapping table. */ |
| private Hashtable stackedNS=new Hashtable(); |
| /** The current namespaces table. */ |
| private NamespacesTable namespaces=new NamespacesTable(); |
| /** The current stack depth.*/ |
| private int stack=0; |
| |
| /** |
| * Create a new <code>DocumentHandlerAdapter</code> instance. |
| */ |
| public DocumentHandlerAdapter() { |
| super(); |
| } |
| |
| /** |
| * Create a new <code>DocumentHandlerAdapter</code> instance. |
| */ |
| public DocumentHandlerAdapter(XMLConsumer consumer) { |
| this(); |
| super.setConsumer(consumer); |
| } |
| |
| /** |
| * Create a new <code>DocumentHandlerAdapter</code> instance. |
| */ |
| public DocumentHandlerAdapter(ContentHandler content) { |
| this(); |
| super.setContentHandler(content); |
| } |
| |
| /** |
| * Receive an object for locating the origin of SAX document events. |
| */ |
| public void setDocumentLocator (Locator locator) { |
| if (super.contentHandler==null) return; |
| else super.contentHandler.setDocumentLocator(locator); |
| } |
| |
| /** |
| * Receive notification of the beginning of a document. |
| */ |
| public void startDocument () |
| throws SAXException { |
| if (super.contentHandler==null) |
| throw new SAXException("ContentHandler not set"); |
| super.contentHandler.startDocument(); |
| } |
| |
| /** |
| * Receive notification of the end of a document. |
| */ |
| public void endDocument () |
| throws SAXException { |
| if (super.contentHandler==null) |
| throw new SAXException("ContentHandler not set"); |
| super.contentHandler.endDocument(); |
| } |
| |
| /** |
| * Receive notification of the beginning of an element. |
| */ |
| public void startElement (String name, AttributeList a) |
| throws SAXException { |
| if (super.contentHandler==null) |
| throw new SAXException("ContentHandler not set"); |
| // Check for namespace declarations (two loops because we're not sure |
| // about attribute ordering. |
| AttributesImpl a2=new AttributesImpl(); |
| Vector nslist=new Vector(); |
| for (int x=0; x<a.getLength(); x++) { |
| String att=a.getName(x); |
| String uri=a.getValue(x); |
| if (att.equals("xmlns") || att.startsWith("xmlns:")) { |
| String pre=""; |
| if (att.length()>5) pre=att.substring(6); |
| this.namespaces.addDeclaration(pre,uri); |
| nslist.addElement(pre); |
| super.contentHandler.startPrefixMapping(pre,uri); |
| } |
| } |
| if (nslist.size()>0) this.stackedNS.put(new Integer(this.stack),nslist); |
| // Resolve the element namespaced name |
| NamespacesTable.Name w=this.namespaces.resolve(null,name,null,null); |
| // Second loop through attributes to fill AttributesImpl |
| for (int x=0; x<a.getLength(); x++) { |
| String att=a.getName(x); |
| if (att.equals("xmlns") || att.startsWith("xmlns:")) continue; |
| // We have something different from a namespace declaration |
| NamespacesTable.Name k=this.namespaces.resolve(null,att,null,null); |
| String val=a.getValue(x); |
| String typ=a.getType(x); |
| String uri=k.getPrefix().length()==0?"":k.getUri(); |
| a2.addAttribute(uri,k.getLocalName(),k.getQName(),typ,val); |
| } |
| // Notify the contentHandler |
| super.contentHandler.startElement(w.getUri(),w.getLocalName(), |
| w.getQName(),a2); |
| // Forward on the stack |
| this.stack++; |
| } |
| |
| /** |
| * Receive notification of the end of an element. |
| */ |
| public void endElement (String name) |
| throws SAXException { |
| if (super.contentHandler==null) |
| throw new SAXException("ContentHandler not set"); |
| // Get back on the stack |
| this.stack--; |
| // Notify the contentHandler |
| NamespacesTable.Name w=this.namespaces.resolve(null,name,null,null); |
| super.contentHandler.endElement(w.getUri(),w.getLocalName(), |
| w.getQName()); |
| // Undeclare namespaces |
| Vector nslist=(Vector)this.stackedNS.remove(new Integer(this.stack)); |
| if (nslist==null) return; |
| if (nslist.size()==0) return; |
| Enumeration e=nslist.elements(); |
| while (e.hasMoreElements()) { |
| String prefix=(String)e.nextElement(); |
| NamespacesTable.Declaration d=namespaces.removeDeclaration(prefix); |
| super.contentHandler.endPrefixMapping(d.getPrefix()); |
| } |
| } |
| |
| |
| /** |
| * Receive notification of character data. |
| */ |
| public void characters (char ch[], int start, int len) |
| throws SAXException { |
| if (super.contentHandler==null) |
| throw new SAXException("ContentHandler not set"); |
| super.contentHandler.characters(ch,start,len); |
| } |
| |
| |
| /** |
| * Receive notification of ignorable whitespace in element content. |
| */ |
| public void ignorableWhitespace (char ch[], int start, int len) |
| throws SAXException { |
| if (super.contentHandler==null) |
| throw new SAXException("ContentHandler not set"); |
| super.contentHandler.ignorableWhitespace(ch,start,len); |
| } |
| |
| |
| /** |
| * Receive notification of a processing instruction. |
| */ |
| public void processingInstruction (String target, String data) |
| throws SAXException { |
| if (super.contentHandler==null) |
| throw new SAXException("ContentHandler not set"); |
| super.contentHandler.processingInstruction(target,data); |
| } |
| } |