001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.xml;
018:
019: import java.util.Enumeration;
020: import java.util.Hashtable;
021: import java.util.Vector;
022:
023: import org.xml.sax.AttributeList;
024: import org.xml.sax.ContentHandler;
025: import org.xml.sax.DocumentHandler;
026: import org.xml.sax.Locator;
027: import org.xml.sax.SAXException;
028: import org.xml.sax.helpers.AttributesImpl;
029:
030: /**
031: * This class is an utility class "adapting" a SAX version 1.0
032: * <code>DocumentHandler</code>, to SAX version 2 <code>ContentHandler</code>.
033: * <br>
034: * This class fully supports XML namespaces, converting <code>xmlns</code> and
035: * <code>xmlns:...</code> element attributes into appropriate
036: * <code>startPrefixMapping(...)</code> and <code>endPrefixMapping(...)</code>
037: * calls.
038: *
039: * @author <a href="mailto:pier@apache.org">Pierpaolo Fumagalli</a>
040: * (Apache Software Foundation)
041: * @version CVS $Id: DocumentHandlerAdapter.java 433543 2006-08-22 06:22:54Z crossley $
042: */
043: public class DocumentHandlerAdapter extends AbstractXMLProducer
044: implements DocumentHandler {
045:
046: /** The element-oriented namespace-uri stacked mapping table. */
047: private Hashtable stackedNS = new Hashtable();
048: /** The current namespaces table. */
049: private NamespacesTable namespaces = new NamespacesTable();
050: /** The current stack depth.*/
051: private int stack = 0;
052:
053: /**
054: * Create a new <code>DocumentHandlerAdapter</code> instance.
055: */
056: public DocumentHandlerAdapter() {
057: super ();
058: }
059:
060: /**
061: * Create a new <code>DocumentHandlerAdapter</code> instance.
062: */
063: public DocumentHandlerAdapter(XMLConsumer consumer) {
064: this ();
065: super .setConsumer(consumer);
066: }
067:
068: /**
069: * Create a new <code>DocumentHandlerAdapter</code> instance.
070: */
071: public DocumentHandlerAdapter(ContentHandler content) {
072: this ();
073: super .setContentHandler(content);
074: }
075:
076: /**
077: * Receive an object for locating the origin of SAX document events.
078: */
079: public void setDocumentLocator(Locator locator) {
080: if (super .contentHandler == null)
081: return;
082: else
083: super .contentHandler.setDocumentLocator(locator);
084: }
085:
086: /**
087: * Receive notification of the beginning of a document.
088: */
089: public void startDocument() throws SAXException {
090: if (super .contentHandler == null)
091: throw new SAXException("ContentHandler not set");
092: super .contentHandler.startDocument();
093: }
094:
095: /**
096: * Receive notification of the end of a document.
097: */
098: public void endDocument() throws SAXException {
099: if (super .contentHandler == null)
100: throw new SAXException("ContentHandler not set");
101: super .contentHandler.endDocument();
102: }
103:
104: /**
105: * Receive notification of the beginning of an element.
106: */
107: public void startElement(String name, AttributeList a)
108: throws SAXException {
109: if (super .contentHandler == null)
110: throw new SAXException("ContentHandler not set");
111: // Check for namespace declarations (two loops because we're not sure
112: // about attribute ordering.
113: AttributesImpl a2 = new AttributesImpl();
114: Vector nslist = new Vector();
115: for (int x = 0; x < a.getLength(); x++) {
116: String att = a.getName(x);
117: String uri = a.getValue(x);
118: if (att.equals("xmlns") || att.startsWith("xmlns:")) {
119: String pre = "";
120: if (att.length() > 5)
121: pre = att.substring(6);
122: this .namespaces.addDeclaration(pre, uri);
123: nslist.addElement(pre);
124: super .contentHandler.startPrefixMapping(pre, uri);
125: }
126: }
127: if (nslist.size() > 0)
128: this .stackedNS.put(new Integer(this .stack), nslist);
129: // Resolve the element namespaced name
130: NamespacesTable.Name w = this .namespaces.resolve(null, name,
131: null, null);
132: // Second loop through attributes to fill AttributesImpl
133: for (int x = 0; x < a.getLength(); x++) {
134: String att = a.getName(x);
135: if (att.equals("xmlns") || att.startsWith("xmlns:"))
136: continue;
137: // We have something different from a namespace declaration
138: NamespacesTable.Name k = this .namespaces.resolve(null, att,
139: null, null);
140: String val = a.getValue(x);
141: String typ = a.getType(x);
142: String uri = k.getPrefix().length() == 0 ? "" : k.getUri();
143: a2.addAttribute(uri, k.getLocalName(), k.getQName(), typ,
144: val);
145: }
146: // Notify the contentHandler
147: super .contentHandler.startElement(w.getUri(), w.getLocalName(),
148: w.getQName(), a2);
149: // Forward on the stack
150: this .stack++;
151: }
152:
153: /**
154: * Receive notification of the end of an element.
155: */
156: public void endElement(String name) throws SAXException {
157: if (super .contentHandler == null)
158: throw new SAXException("ContentHandler not set");
159: // Get back on the stack
160: this .stack--;
161: // Notify the contentHandler
162: NamespacesTable.Name w = this .namespaces.resolve(null, name,
163: null, null);
164: super .contentHandler.endElement(w.getUri(), w.getLocalName(), w
165: .getQName());
166: // Undeclare namespaces
167: Vector nslist = (Vector) this .stackedNS.remove(new Integer(
168: this .stack));
169: if (nslist == null)
170: return;
171: if (nslist.size() == 0)
172: return;
173: Enumeration e = nslist.elements();
174: while (e.hasMoreElements()) {
175: String prefix = (String) e.nextElement();
176: NamespacesTable.Declaration d = namespaces
177: .removeDeclaration(prefix);
178: super .contentHandler.endPrefixMapping(d.getPrefix());
179: }
180: }
181:
182: /**
183: * Receive notification of character data.
184: */
185: public void characters(char ch[], int start, int len)
186: throws SAXException {
187: if (super .contentHandler == null)
188: throw new SAXException("ContentHandler not set");
189: super .contentHandler.characters(ch, start, len);
190: }
191:
192: /**
193: * Receive notification of ignorable whitespace in element content.
194: */
195: public void ignorableWhitespace(char ch[], int start, int len)
196: throws SAXException {
197: if (super .contentHandler == null)
198: throw new SAXException("ContentHandler not set");
199: super .contentHandler.ignorableWhitespace(ch, start, len);
200: }
201:
202: /**
203: * Receive notification of a processing instruction.
204: */
205: public void processingInstruction(String target, String data)
206: throws SAXException {
207: if (super .contentHandler == null)
208: throw new SAXException("ContentHandler not set");
209: super.contentHandler.processingInstruction(target, data);
210: }
211: }
|