0001: /*
0002: * $Id: XMLNamespaceBinder.java,v 1.2 2006/04/01 06:01:48 jeffsuttor Exp $
0003: */
0004:
0005: /*
0006: * The contents of this file are subject to the terms
0007: * of the Common Development and Distribution License
0008: * (the License). You may not use this file except in
0009: * compliance with the License.
0010: *
0011: * You can obtain a copy of the license at
0012: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
0013: * See the License for the specific language governing
0014: * permissions and limitations under the License.
0015: *
0016: * When distributing Covered Code, include this CDDL
0017: * Header Notice in each file and include the License file
0018: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
0019: * If applicable, add the following below the CDDL Header,
0020: * with the fields enclosed by brackets [] replaced by
0021: * you own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * [Name of File] [ver.__] [Date]
0025: *
0026: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
0027: */
0028:
0029: /*
0030: * The Apache Software License, Version 1.1
0031: *
0032: *
0033: * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
0034: * reserved.
0035: *
0036: * Redistribution and use in source and binary forms, with or without
0037: * modification, are permitted provided that the following conditions
0038: * are met:
0039: *
0040: * 1. Redistributions of source code must retain the above copyright
0041: * notice, this list of conditions and the following disclaimer.
0042: *
0043: * 2. Redistributions in binary form must reproduce the above copyright
0044: * notice, this list of conditions and the following disclaimer in
0045: * the documentation and/or other materials provided with the
0046: * distribution.
0047: *
0048: * 3. The end-user documentation included with the redistribution,
0049: * if any, must include the following acknowledgment:
0050: * "This product includes software developed by the
0051: * Apache Software Foundation (http://www.apache.org/)."
0052: * Alternately, this acknowledgment may appear in the software itself,
0053: * if and wherever such third-party acknowledgments normally appear.
0054: *
0055: * 4. The names "Xerces" and "Apache Software Foundation" must
0056: * not be used to endorse or promote products derived from this
0057: * software without prior written permission. For written
0058: * permission, please contact apache@apache.org.
0059: *
0060: * 5. Products derived from this software may not be called "Apache",
0061: * nor may "Apache" appear in their name, without prior written
0062: * permission of the Apache Software Foundation.
0063: *
0064: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0065: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0066: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0067: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0068: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0069: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0070: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0071: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0072: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0073: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0074: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0075: * SUCH DAMAGE.
0076: * ====================================================================
0077: *
0078: * This software consists of voluntary contributions made by many
0079: * individuals on behalf of the Apache Software Foundation and was
0080: * originally based on software copyright (c) 1999, International
0081: * Business Machines, Inc., http://www.apache.org. For more
0082: * information on the Apache Software Foundation, please see
0083: * <http://www.apache.org/>.
0084: */
0085:
0086: package com.sun.xml.stream;
0087:
0088: import com.sun.xml.stream.xerces.impl.msg.XMLMessageFormatter;
0089:
0090: import com.sun.xml.stream.xerces.util.NamespaceSupport;
0091: import com.sun.xml.stream.xerces.util.SymbolTable;
0092: import com.sun.xml.stream.xerces.util.XMLSymbols;
0093:
0094: import com.sun.xml.stream.xerces.xni.Augmentations;
0095: import com.sun.xml.stream.xerces.xni.NamespaceContext;
0096: import com.sun.xml.stream.xerces.xni.QName;
0097: import com.sun.xml.stream.xerces.xni.XMLAttributes;
0098: import com.sun.xml.stream.xerces.xni.XMLDocumentHandler;
0099: import com.sun.xml.stream.xerces.xni.XMLLocator;
0100: import com.sun.xml.stream.xerces.xni.XMLResourceIdentifier;
0101: import com.sun.xml.stream.xerces.xni.XMLString;
0102: import com.sun.xml.stream.xerces.xni.XNIException;
0103: import com.sun.xml.stream.xerces.xni.parser.XMLComponent;
0104: import com.sun.xml.stream.xerces.xni.parser.XMLComponentManager;
0105: import com.sun.xml.stream.xerces.xni.parser.XMLConfigurationException;
0106: import com.sun.xml.stream.xerces.xni.parser.XMLDocumentSource;
0107: import com.sun.xml.stream.xerces.xni.parser.XMLDocumentFilter;
0108:
0109: /**
0110: * This class performs namespace binding on the startElement and endElement
0111: * method calls and passes all other methods through to the registered
0112: * document handler. This class can be configured to only pass the
0113: * start and end prefix mappings (start/endPrefixMapping).
0114: * <p>
0115: * This component requires the following features and properties from the
0116: * component manager that uses it:
0117: * <ul>
0118: * <li>http://xml.org/sax/features/namespaces</li>
0119: * <li>http://apache.org/xml/properties/internal/symbol-table</li>
0120: * <li>http://apache.org/xml/properties/internal/error-reporter</li>
0121: * </ul>
0122: *
0123: * @author Andy Clark, IBM
0124: *
0125: * @version $Id: XMLNamespaceBinder.java,v 1.2 2006/04/01 06:01:48 jeffsuttor Exp $
0126: */
0127: public class XMLNamespaceBinder implements XMLComponent,
0128: XMLDocumentFilter {
0129:
0130: //
0131: // Constants
0132: //
0133:
0134: // feature identifiers
0135:
0136: /** Feature identifier: namespaces. */
0137: protected static final String NAMESPACES = Constants.SAX_FEATURE_PREFIX
0138: + Constants.NAMESPACES_FEATURE;
0139:
0140: // property identifiers
0141:
0142: /** Property identifier: symbol table. */
0143: protected static final String SYMBOL_TABLE = Constants.XERCES_PROPERTY_PREFIX
0144: + Constants.SYMBOL_TABLE_PROPERTY;
0145:
0146: /** Property identifier: error reporter. */
0147: protected static final String ERROR_REPORTER = Constants.XERCES_PROPERTY_PREFIX
0148: + Constants.ERROR_REPORTER_PROPERTY;
0149:
0150: // recognized features and properties
0151:
0152: /** Recognized features. */
0153: private static final String[] RECOGNIZED_FEATURES = { NAMESPACES, };
0154:
0155: /** Feature defaults. */
0156: private static final Boolean[] FEATURE_DEFAULTS = { null, };
0157:
0158: /** Recognized properties. */
0159: private static final String[] RECOGNIZED_PROPERTIES = {
0160: SYMBOL_TABLE, ERROR_REPORTER, };
0161:
0162: /** Property defaults. */
0163: private static final Object[] PROPERTY_DEFAULTS = { null, null, };
0164:
0165: //
0166: // Data
0167: //
0168:
0169: // features
0170:
0171: /** Namespaces. */
0172: protected boolean fNamespaces;
0173:
0174: // properties
0175:
0176: /** Symbol table. */
0177: protected SymbolTable fSymbolTable;
0178:
0179: /** Error reporter. */
0180: protected XMLErrorReporter fErrorReporter;
0181:
0182: // handlers
0183:
0184: /** Document handler. */
0185: protected XMLDocumentHandler fDocumentHandler;
0186:
0187: protected XMLDocumentSource fDocumentSource;
0188:
0189: // namespaces
0190:
0191: /** Namespace support. */
0192: protected NamespaceSupport fNamespaceSupport = new NamespaceSupport();
0193:
0194: // settings
0195:
0196: /** Only pass start and end prefix mapping events. */
0197: protected boolean fOnlyPassPrefixMappingEvents;
0198:
0199: // shared context
0200:
0201: /** Namespace context. */
0202: private NamespaceContext fNamespaceContext;
0203:
0204: // temp vars
0205:
0206: /** Attribute QName. */
0207: private QName fAttributeQName = new QName();
0208:
0209: //
0210: // Constructors
0211: //
0212:
0213: /** Default constructor. */
0214: public XMLNamespaceBinder() {
0215: this (null);
0216: } // <init>()
0217:
0218: /**
0219: * Constructs a namespace binder that shares the specified namespace
0220: * context during each parse.
0221: *
0222: * @param namespaceContext The shared context.
0223: */
0224: public XMLNamespaceBinder(NamespaceContext namespaceContext) {
0225: fNamespaceContext = namespaceContext;
0226: } // <init>(NamespaceContext)
0227:
0228: //
0229: // Public methods
0230: //
0231:
0232: /** Returns the current namespace context. */
0233: public NamespaceContext getNamespaceContext() {
0234: return fNamespaceSupport;
0235: } // getNamespaceContext():NamespaceContext
0236:
0237: // settings
0238:
0239: /**
0240: * Sets whether the namespace binder only passes the prefix mapping
0241: * events to the registered document handler or passes all document
0242: * events.
0243: *
0244: * @param onlyPassPrefixMappingEvents True to pass only the prefix
0245: * mapping events; false to pass
0246: * all events.
0247: */
0248: public void setOnlyPassPrefixMappingEvents(
0249: boolean onlyPassPrefixMappingEvents) {
0250: fOnlyPassPrefixMappingEvents = onlyPassPrefixMappingEvents;
0251: } // setOnlyPassPrefixMappingEvents(boolean)
0252:
0253: /**
0254: * Returns true if the namespace binder only passes the prefix mapping
0255: * events to the registered document handler; false if the namespace
0256: * binder passes all document events.
0257: */
0258: public boolean getOnlyPassPrefixMappingEvents() {
0259: return fOnlyPassPrefixMappingEvents;
0260: } // getOnlyPassPrefixMappingEvents():boolean
0261:
0262: //
0263: // XMLComponent methods
0264: //
0265:
0266: /**
0267: * Resets the component. The component can query the component manager
0268: * about any features and properties that affect the operation of the
0269: * component.
0270: *
0271: * @param componentManager The component manager.
0272: *
0273: * @throws SAXException Thrown by component on initialization error.
0274: * For example, if a feature or property is
0275: * required for the operation of the component, the
0276: * component manager may throw a
0277: * SAXNotRecognizedException or a
0278: * SAXNotSupportedException.
0279: */
0280: public void reset(XMLComponentManager componentManager)
0281: throws XNIException {
0282:
0283: // features
0284: try {
0285: fNamespaces = componentManager.getFeature(NAMESPACES);
0286: } catch (XMLConfigurationException e) {
0287: fNamespaces = true;
0288: }
0289:
0290: // Xerces properties
0291: fSymbolTable = (SymbolTable) componentManager
0292: .getProperty(SYMBOL_TABLE);
0293: fErrorReporter = (XMLErrorReporter) componentManager
0294: .getProperty(ERROR_REPORTER);
0295:
0296: fNamespaceSupport.reset();
0297:
0298: // use shared context
0299: NamespaceContext context = fNamespaceContext;
0300: while (context != null) {
0301: int count = context.getDeclaredPrefixCount();
0302: for (int i = 0; i < count; i++) {
0303: String prefix = context.getDeclaredPrefixAt(i);
0304: if (fNamespaceSupport.getURI(prefix) == null) {
0305: String uri = context.getURI(prefix);
0306: fNamespaceSupport.declarePrefix(prefix, uri);
0307: }
0308: }
0309: }
0310:
0311: } // reset(XMLComponentManager)
0312:
0313: /**
0314: * Returns a list of feature identifiers that are recognized by
0315: * this component. This method may return null if no features
0316: * are recognized by this component.
0317: */
0318: public String[] getRecognizedFeatures() {
0319: return (String[]) (RECOGNIZED_FEATURES.clone());
0320: } // getRecognizedFeatures():String[]
0321:
0322: /**
0323: * Sets the state of a feature. This method is called by the component
0324: * manager any time after reset when a feature changes state.
0325: * <p>
0326: * <strong>Note:</strong> Components should silently ignore features
0327: * that do not affect the operation of the component.
0328: *
0329: * @param featureId The feature identifier.
0330: * @param state The state of the feature.
0331: *
0332: * @throws SAXNotRecognizedException The component should not throw
0333: * this exception.
0334: * @throws SAXNotSupportedException The component should not throw
0335: * this exception.
0336: */
0337: public void setFeature(String featureId, boolean state)
0338: throws XMLConfigurationException {
0339: } // setFeature(String,boolean)
0340:
0341: /**
0342: * Returns a list of property identifiers that are recognized by
0343: * this component. This method may return null if no properties
0344: * are recognized by this component.
0345: */
0346: public String[] getRecognizedProperties() {
0347: return (String[]) (RECOGNIZED_PROPERTIES.clone());
0348: } // getRecognizedProperties():String[]
0349:
0350: /**
0351: * Sets the value of a property during parsing.
0352: *
0353: * @param propertyId
0354: * @param value
0355: */
0356: public void setProperty(String propertyId, Object value)
0357: throws XMLConfigurationException {
0358:
0359: // Xerces properties
0360: if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
0361: String property = propertyId
0362: .substring(Constants.XERCES_PROPERTY_PREFIX
0363: .length());
0364: if (property.equals(Constants.SYMBOL_TABLE_PROPERTY)) {
0365: fSymbolTable = (SymbolTable) value;
0366: } else if (property
0367: .equals(Constants.ERROR_REPORTER_PROPERTY)) {
0368: fErrorReporter = (XMLErrorReporter) value;
0369: }
0370: return;
0371: }
0372:
0373: } // setProperty(String,Object)
0374:
0375: /**
0376: * Returns the default state for a feature, or null if this
0377: * component does not want to report a default value for this
0378: * feature.
0379: *
0380: * @param featureId The feature identifier.
0381: *
0382: * @since Xerces 2.2.0
0383: */
0384: public Boolean getFeatureDefault(String featureId) {
0385: for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
0386: if (RECOGNIZED_FEATURES[i].equals(featureId)) {
0387: return FEATURE_DEFAULTS[i];
0388: }
0389: }
0390: return null;
0391: } // getFeatureDefault(String):Boolean
0392:
0393: /**
0394: * Returns the default state for a property, or null if this
0395: * component does not want to report a default value for this
0396: * property.
0397: *
0398: * @param propertyId The property identifier.
0399: *
0400: * @since Xerces 2.2.0
0401: */
0402: public Object getPropertyDefault(String propertyId) {
0403: for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
0404: if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
0405: return PROPERTY_DEFAULTS[i];
0406: }
0407: }
0408: return null;
0409: } // getPropertyDefault(String):Object
0410:
0411: //
0412: // XMLDocumentSource methods
0413: //
0414:
0415: /** Sets the document handler to receive information about the document. */
0416: public void setDocumentHandler(XMLDocumentHandler documentHandler) {
0417: fDocumentHandler = documentHandler;
0418: } // setDocumentHandler(XMLDocumentHandler)
0419:
0420: /** Returns the document handler */
0421: public XMLDocumentHandler getDocumentHandler() {
0422: return fDocumentHandler;
0423: } // setDocumentHandler(XMLDocumentHandler)
0424:
0425: //
0426: // XMLDocumentHandler methods
0427: //
0428:
0429: /** Sets the document source */
0430: public void setDocumentSource(XMLDocumentSource source) {
0431: fDocumentSource = source;
0432: } // setDocumentSource
0433:
0434: /** Returns the document source */
0435: public XMLDocumentSource getDocumentSource() {
0436: return fDocumentSource;
0437: } // getDocumentSource
0438:
0439: /**
0440: * This method notifies the start of a general entity.
0441: * <p>
0442: * <strong>Note:</strong> This method is not called for entity references
0443: * appearing as part of attribute values.
0444: *
0445: * @param name The name of the general entity.
0446: * @param identifier The resource identifier.
0447: * @param encoding The auto-detected IANA encoding name of the entity
0448: * stream. This value will be null in those situations
0449: * where the entity encoding is not auto-detected (e.g.
0450: * internal entities or a document entity that is
0451: * parsed from a java.io.Reader).
0452: * @param augs Additional information that may include infoset augmentations
0453: *
0454: * @exception XNIException Thrown by handler to signal an error.
0455: */
0456: public void startGeneralEntity(String name,
0457: XMLResourceIdentifier identifier, String encoding,
0458: Augmentations augs) throws XNIException {
0459: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0460: fDocumentHandler.startGeneralEntity(name, identifier,
0461: encoding, augs);
0462: }
0463: } // startEntity(String,String,String,String,String)
0464:
0465: /**
0466: * Notifies of the presence of a TextDecl line in an entity. If present,
0467: * this method will be called immediately following the startEntity call.
0468: * <p>
0469: * <strong>Note:</strong> This method will never be called for the
0470: * document entity; it is only called for external general entities
0471: * referenced in document content.
0472: * <p>
0473: * <strong>Note:</strong> This method is not called for entity references
0474: * appearing as part of attribute values.
0475: *
0476: * @param version The XML version, or null if not specified.
0477: * @param encoding The IANA encoding name of the entity.
0478: * @param augs Additional information that may include infoset augmentations
0479: *
0480: * @throws XNIException Thrown by handler to signal an error.
0481: */
0482: public void textDecl(String version, String encoding,
0483: Augmentations augs) throws XNIException {
0484: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0485: fDocumentHandler.textDecl(version, encoding, augs);
0486: }
0487: } // textDecl(String,String)
0488:
0489: /**
0490: * The start of the document.
0491: *
0492: * @param locator The system identifier of the entity if the entity
0493: * is external, null otherwise.
0494: * @param encoding The auto-detected IANA encoding name of the entity
0495: * stream. This value will be null in those situations
0496: * where the entity encoding is not auto-detected (e.g.
0497: * internal entities or a document entity that is
0498: * parsed from a java.io.Reader).
0499: * @param namespaceContext
0500: * The namespace context in effect at the
0501: * start of this document.
0502: * This object represents the current context.
0503: * Implementors of this class are responsible
0504: * for copying the namespace bindings from the
0505: * the current context (and its parent contexts)
0506: * if that information is important.
0507: * @param augs Additional information that may include infoset augmentations
0508: *
0509: * @throws XNIException Thrown by handler to signal an error.
0510: */
0511: public void startDocument(XMLLocator locator, String encoding,
0512: NamespaceContext namespaceContext, Augmentations augs)
0513: throws XNIException {
0514: // REVISIT: in the namespace binder we should be able to modify the namespace
0515: // context object, thus for now we are dropping the namespaceContext
0516: // Not sure this is a correct behaviour....
0517: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0518: fDocumentHandler.startDocument(locator, encoding,
0519: fNamespaceSupport, augs);
0520: }
0521: } // startDocument(XMLLocator,String)
0522:
0523: /**
0524: * Notifies of the presence of an XMLDecl line in the document. If
0525: * present, this method will be called immediately following the
0526: * startDocument call.
0527: *
0528: * @param version The XML version.
0529: * @param encoding The IANA encoding name of the document, or null if
0530: * not specified.
0531: * @param standalone The standalone value, or null if not specified.
0532: * @param augs Additional information that may include infoset augmentations
0533: *
0534: * @throws XNIException Thrown by handler to signal an error.
0535: */
0536: public void xmlDecl(String version, String encoding,
0537: String standalone, Augmentations augs) throws XNIException {
0538: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0539: fDocumentHandler.xmlDecl(version, encoding, standalone,
0540: augs);
0541: }
0542: } // xmlDecl(String,String,String)
0543:
0544: /**
0545: * Notifies of the presence of the DOCTYPE line in the document.
0546: *
0547: * @param rootElement The name of the root element.
0548: * @param publicId The public identifier if an external DTD or null
0549: * if the external DTD is specified using SYSTEM.
0550: * @param systemId The system identifier if an external DTD, null
0551: * otherwise.
0552: * @param augs Additional information that may include infoset augmentations
0553: *
0554: * @throws XNIException Thrown by handler to signal an error.
0555: */
0556: public void doctypeDecl(String rootElement, String publicId,
0557: String systemId, Augmentations augs) throws XNIException {
0558: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0559: fDocumentHandler.doctypeDecl(rootElement, publicId,
0560: systemId, augs);
0561: }
0562: } // doctypeDecl(String,String,String)
0563:
0564: /**
0565: * A comment.
0566: *
0567: * @param text The text in the comment.
0568: * @param augs Additional information that may include infoset augmentations
0569: *
0570: * @throws XNIException Thrown by application to signal an error.
0571: */
0572: public void comment(XMLString text, Augmentations augs)
0573: throws XNIException {
0574: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0575: fDocumentHandler.comment(text, augs);
0576: }
0577: } // comment(XMLString)
0578:
0579: /**
0580: * A processing instruction. Processing instructions consist of a
0581: * target name and, optionally, text data. The data is only meaningful
0582: * to the application.
0583: * <p>
0584: * Typically, a processing instruction's data will contain a series
0585: * of pseudo-attributes. These pseudo-attributes follow the form of
0586: * element attributes but are <strong>not</strong> parsed or presented
0587: * to the application as anything other than text. The application is
0588: * responsible for parsing the data.
0589: *
0590: * @param target The target.
0591: * @param data The data or null if none specified.
0592: * @param augs Additional information that may include infoset augmentations
0593: *
0594: * @throws XNIException Thrown by handler to signal an error.
0595: */
0596: public void processingInstruction(String target, XMLString data,
0597: Augmentations augs) throws XNIException {
0598: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0599: fDocumentHandler.processingInstruction(target, data, augs);
0600: }
0601: } // processingInstruction(String,XMLString)
0602:
0603: /**
0604: * The start of a namespace prefix mapping. This method will only be
0605: * called when namespace processing is enabled.
0606: *
0607: * @param prefix The namespace prefix.
0608: * @param uri The URI bound to the prefix.
0609: * @param augs Additional information that may include infoset augmentations
0610: *
0611: * @throws XNIException Thrown by handler to signal an error.
0612: */
0613: public void startPrefixMapping(String prefix, String uri,
0614: Augmentations augs) throws XNIException {
0615:
0616: // REVISIT: Should prefix mapping from previous stage in
0617: // the pipeline affect the namespaces?
0618:
0619: // call handlers
0620: if (fDocumentHandler != null) {
0621: fDocumentHandler.startPrefixMapping(prefix, uri, augs);
0622: }
0623:
0624: } // startPrefixMapping(String,String)
0625:
0626: /**
0627: * Binds the namespaces. This method will handle calling the
0628: * document handler to start the prefix mappings.
0629: * <p>
0630: * <strong>Note:</strong> This method makes use of the
0631: * fAttributeQName variable. Any contents of the variable will
0632: * be destroyed. Caller should copy the values out of this
0633: * temporary variable before calling this method.
0634: *
0635: * @param element The name of the element.
0636: * @param attributes The element attributes.
0637: * @param augs Additional information that may include infoset augmentations
0638: *
0639: * @throws XNIException Thrown by handler to signal an error.
0640: */
0641: public void startElement(QName element, XMLAttributes attributes,
0642: Augmentations augs) throws XNIException {
0643:
0644: if (fNamespaces) {
0645: handleStartElement(element, attributes, augs, false);
0646: } else if (fDocumentHandler != null) {
0647: fDocumentHandler.startElement(element, attributes, augs);
0648: }
0649:
0650: } // startElement(QName,XMLAttributes)
0651:
0652: /**
0653: * An empty element.
0654: *
0655: * @param element The name of the element.
0656: * @param attributes The element attributes.
0657: * @param augs Additional information that may include infoset augmentations
0658: *
0659: * @throws XNIException Thrown by handler to signal an error.
0660: */
0661: public void emptyElement(QName element, XMLAttributes attributes,
0662: Augmentations augs) throws XNIException {
0663:
0664: if (fNamespaces) {
0665: handleStartElement(element, attributes, augs, true);
0666: handleEndElement(element, augs, true);
0667: } else if (fDocumentHandler != null) {
0668: fDocumentHandler.emptyElement(element, attributes, augs);
0669: }
0670:
0671: } // emptyElement(QName,XMLAttributes)
0672:
0673: /**
0674: * Character content.
0675: *
0676: * @param text The content.
0677: * @param augs Additional information that may include infoset augmentations
0678: *
0679: * @throws XNIException Thrown by handler to signal an error.
0680: */
0681: public void characters(XMLString text, Augmentations augs)
0682: throws XNIException {
0683: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0684: fDocumentHandler.characters(text, augs);
0685: }
0686: } // characters(XMLString)
0687:
0688: /**
0689: * Ignorable whitespace. For this method to be called, the document
0690: * source must have some way of determining that the text containing
0691: * only whitespace characters should be considered ignorable. For
0692: * example, the validator can determine if a length of whitespace
0693: * characters in the document are ignorable based on the element
0694: * content model.
0695: *
0696: * @param text The ignorable whitespace.
0697: * @param augs Additional information that may include infoset augmentations
0698: *
0699: * @throws XNIException Thrown by handler to signal an error.
0700: */
0701: public void ignorableWhitespace(XMLString text, Augmentations augs)
0702: throws XNIException {
0703: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0704: fDocumentHandler.ignorableWhitespace(text, augs);
0705: }
0706: } // ignorableWhitespace(XMLString)
0707:
0708: /**
0709: * The end of an element.
0710: *
0711: * @param element The name of the element.
0712: * @param augs Additional information that may include infoset augmentations
0713: *
0714: * @throws XNIException Thrown by handler to signal an error.
0715: */
0716: public void endElement(QName element, Augmentations augs)
0717: throws XNIException {
0718:
0719: if (fNamespaces) {
0720: handleEndElement(element, augs, false);
0721: } else if (fDocumentHandler != null) {
0722: fDocumentHandler.endElement(element, augs);
0723: }
0724:
0725: } // endElement(QName)
0726:
0727: /**
0728: * The end of a namespace prefix mapping. This method will only be
0729: * called when namespace processing is enabled.
0730: *
0731: * @param prefix The namespace prefix.
0732: * @param augs Additional information that may include infoset augmentations
0733: *
0734: * @throws XNIException Thrown by handler to signal an error.
0735: */
0736: public void endPrefixMapping(String prefix, Augmentations augs)
0737: throws XNIException {
0738:
0739: // REVISIT: Should prefix mapping from previous stage in
0740: // the pipeline affect the namespaces?
0741:
0742: // call handlers
0743: if (fDocumentHandler != null) {
0744: fDocumentHandler.endPrefixMapping(prefix, augs);
0745: }
0746:
0747: } // endPrefixMapping(String)
0748:
0749: /**
0750: * The start of a CDATA section.
0751: * @param augs Additional information that may include infoset augmentations
0752: *
0753: * @throws XNIException Thrown by handler to signal an error.
0754: */
0755: public void startCDATA(Augmentations augs) throws XNIException {
0756: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0757: fDocumentHandler.startCDATA(augs);
0758: }
0759: } // startCDATA()
0760:
0761: /**
0762: * The end of a CDATA section.
0763: * @param augs Additional information that may include infoset augmentations
0764: *
0765: * @throws XNIException Thrown by handler to signal an error.
0766: */
0767: public void endCDATA(Augmentations augs) throws XNIException {
0768: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0769: fDocumentHandler.endCDATA(augs);
0770: }
0771: } // endCDATA()
0772:
0773: /**
0774: * The end of the document.
0775: * @param augs Additional information that may include infoset augmentations
0776: *
0777: * @throws XNIException Thrown by handler to signal an error.
0778: */
0779: public void endDocument(Augmentations augs) throws XNIException {
0780: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0781: fDocumentHandler.endDocument(augs);
0782: }
0783: } // endDocument()
0784:
0785: /**
0786: * This method notifies the end of a general entity.
0787: * <p>
0788: * <strong>Note:</strong> This method is not called for entity references
0789: * appearing as part of attribute values.
0790: *
0791: * @param name The name of the entity.
0792: * @param augs Additional information that may include infoset augmentations
0793: *
0794: * @exception XNIException
0795: * Thrown by handler to signal an error.
0796: */
0797: public void endGeneralEntity(String name, Augmentations augs)
0798: throws XNIException {
0799: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0800: fDocumentHandler.endGeneralEntity(name, augs);
0801: }
0802: } // endEntity(String)
0803:
0804: //
0805: // Protected methods
0806: //
0807:
0808: /** Handles start element. */
0809: protected void handleStartElement(QName element,
0810: XMLAttributes attributes, Augmentations augs,
0811: boolean isEmpty) throws XNIException {
0812:
0813: // add new namespace context
0814: fNamespaceSupport.pushContext();
0815:
0816: if (element.prefix == XMLSymbols.PREFIX_XMLNS) {
0817: fErrorReporter.reportError(
0818: XMLMessageFormatter.XMLNS_DOMAIN,
0819: "ElementXMLNSPrefix",
0820: new Object[] { element.rawname },
0821: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0822: }
0823:
0824: // search for new namespace bindings
0825: int length = attributes.getLength();
0826: for (int i = 0; i < length; i++) {
0827: String localpart = attributes.getLocalName(i);
0828: String prefix = attributes.getPrefix(i);
0829: // when it's of form xmlns="..." or xmlns:prefix="...",
0830: // it's a namespace declaration. but prefix:xmlns="..." isn't.
0831: if (prefix == XMLSymbols.PREFIX_XMLNS
0832: || prefix == XMLSymbols.EMPTY_STRING
0833: && localpart == XMLSymbols.PREFIX_XMLNS) {
0834:
0835: // get the internalized value of this attribute
0836: String uri = fSymbolTable.addSymbol(attributes
0837: .getValue(i));
0838:
0839: // 1. "xmlns" can't be bound to any namespace
0840: if (prefix == XMLSymbols.PREFIX_XMLNS
0841: && localpart == XMLSymbols.PREFIX_XMLNS) {
0842: fErrorReporter.reportError(
0843: XMLMessageFormatter.XMLNS_DOMAIN,
0844: "CantBindXMLNS", new Object[] { attributes
0845: .getQName(i) },
0846: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0847: }
0848:
0849: // 2. the namespace for "xmlns" can't be bound to any prefix
0850: if (uri == NamespaceContext.XMLNS_URI) {
0851: fErrorReporter.reportError(
0852: XMLMessageFormatter.XMLNS_DOMAIN,
0853: "CantBindXMLNS", new Object[] { attributes
0854: .getQName(i) },
0855: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0856: }
0857:
0858: // 3. "xml" can't be bound to any other namespace than it's own
0859: if (localpart == XMLSymbols.PREFIX_XML) {
0860: if (uri != NamespaceContext.XML_URI) {
0861: fErrorReporter
0862: .reportError(
0863: XMLMessageFormatter.XMLNS_DOMAIN,
0864: "CantBindXML",
0865: new Object[] { attributes
0866: .getQName(i) },
0867: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0868: }
0869: }
0870: // 4. the namespace for "xml" can't be bound to any other prefix
0871: else {
0872: if (uri == NamespaceContext.XML_URI) {
0873: fErrorReporter
0874: .reportError(
0875: XMLMessageFormatter.XMLNS_DOMAIN,
0876: "CantBindXML",
0877: new Object[] { attributes
0878: .getQName(i) },
0879: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0880: }
0881: }
0882:
0883: prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart
0884: : XMLSymbols.EMPTY_STRING;
0885:
0886: // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
0887: // We should only report an error if there is a prefix,
0888: // that is, the local part is not "xmlns". -SG
0889: if (uri == XMLSymbols.EMPTY_STRING
0890: && localpart != XMLSymbols.PREFIX_XMLNS) {
0891: fErrorReporter.reportError(
0892: XMLMessageFormatter.XMLNS_DOMAIN,
0893: "EmptyPrefixedAttName",
0894: new Object[] { attributes.getQName(i) },
0895: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0896: continue;
0897: }
0898:
0899: // declare prefix in context
0900: fNamespaceSupport.declarePrefix(prefix,
0901: uri.length() != 0 ? uri : null);
0902:
0903: // call handler
0904: if (fDocumentHandler != null) {
0905: fDocumentHandler.startPrefixMapping(prefix, uri,
0906: augs);
0907: }
0908: }
0909: }
0910:
0911: // bind the element
0912: String prefix = element.prefix != null ? element.prefix
0913: : XMLSymbols.EMPTY_STRING;
0914: element.uri = fNamespaceSupport.getURI(prefix);
0915: if (element.prefix == null && element.uri != null) {
0916: element.prefix = XMLSymbols.EMPTY_STRING;
0917: }
0918: if (element.prefix != null && element.uri == null) {
0919: fErrorReporter.reportError(
0920: XMLMessageFormatter.XMLNS_DOMAIN,
0921: "ElementPrefixUnbound", new Object[] {
0922: element.prefix, element.rawname },
0923: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0924: }
0925:
0926: // bind the attributes
0927: for (int i = 0; i < length; i++) {
0928: attributes.getName(i, fAttributeQName);
0929: String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix
0930: : XMLSymbols.EMPTY_STRING;
0931: String arawname = fAttributeQName.rawname;
0932: if (arawname == XMLSymbols.PREFIX_XMLNS) {
0933: fAttributeQName.uri = fNamespaceSupport
0934: .getURI(XMLSymbols.PREFIX_XMLNS);
0935: attributes.setName(i, fAttributeQName);
0936: } else if (aprefix != XMLSymbols.EMPTY_STRING) {
0937: fAttributeQName.uri = fNamespaceSupport.getURI(aprefix);
0938: if (fAttributeQName.uri == null) {
0939: fErrorReporter.reportError(
0940: XMLMessageFormatter.XMLNS_DOMAIN,
0941: "AttributePrefixUnbound", new Object[] {
0942: aprefix, arawname },
0943: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0944: }
0945: attributes.setName(i, fAttributeQName);
0946: }
0947: }
0948:
0949: // verify that duplicate attributes don't exist
0950: // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
0951: int attrCount = attributes.getLength();
0952: for (int i = 0; i < attrCount - 1; i++) {
0953: String alocalpart = attributes.getLocalName(i);
0954: String auri = attributes.getURI(i);
0955: for (int j = i + 1; j < attrCount; j++) {
0956: String blocalpart = attributes.getLocalName(j);
0957: String buri = attributes.getURI(j);
0958: if (alocalpart == blocalpart && auri == buri) {
0959: fErrorReporter.reportError(
0960: XMLMessageFormatter.XMLNS_DOMAIN,
0961: "AttributeNSNotUnique",
0962: new Object[] { element.rawname, alocalpart,
0963: auri },
0964: XMLErrorReporter.SEVERITY_FATAL_ERROR);
0965: }
0966: }
0967: }
0968:
0969: // call handler
0970: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0971: if (isEmpty) {
0972: fDocumentHandler
0973: .emptyElement(element, attributes, augs);
0974: } else {
0975: fDocumentHandler
0976: .startElement(element, attributes, augs);
0977: }
0978: }
0979:
0980: } // handleStartElement(QName,XMLAttributes,boolean)
0981:
0982: /** Handles end element. */
0983: protected void handleEndElement(QName element, Augmentations augs,
0984: boolean isEmpty) throws XNIException {
0985:
0986: // bind element
0987: String eprefix = element.prefix != null ? element.prefix
0988: : XMLSymbols.EMPTY_STRING;
0989: element.uri = fNamespaceSupport.getURI(eprefix);
0990: if (element.uri != null) {
0991: element.prefix = eprefix;
0992: }
0993:
0994: // call handlers
0995: if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
0996: if (!isEmpty) {
0997: fDocumentHandler.endElement(element, augs);
0998: }
0999: }
1000:
1001: // end prefix mappings
1002: if (fDocumentHandler != null) {
1003: int count = fNamespaceSupport.getDeclaredPrefixCount();
1004: for (int i = count - 1; i >= 0; i--) {
1005: String prefix = fNamespaceSupport
1006: .getDeclaredPrefixAt(i);
1007: fDocumentHandler.endPrefixMapping(prefix, augs);
1008: }
1009: }
1010:
1011: // pop context
1012: fNamespaceSupport.popContext();
1013:
1014: } // handleEndElement(QName,boolean)
1015:
1016: } // class XMLNamespaceBinder
|