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:
018: package org.apache.xerces.impl.dtd;
019:
020: import org.apache.xerces.impl.XMLErrorReporter;
021: import org.apache.xerces.impl.msg.XMLMessageFormatter;
022: import org.apache.xerces.util.XMLSymbols;
023: import org.apache.xerces.xni.Augmentations;
024: import org.apache.xerces.xni.NamespaceContext;
025: import org.apache.xerces.xni.QName;
026: import org.apache.xerces.xni.XMLAttributes;
027: import org.apache.xerces.xni.XNIException;
028:
029: /**
030: * The DTD validator. The validator implements a document
031: * filter: receiving document events from the scanner; validating
032: * the content and structure; augmenting the InfoSet, if applicable;
033: * and notifying the parser of the information resulting from the
034: * validation process.
035: * <p> Formerly, this component also handled DTD events and grammar construction.
036: * To facilitate the development of a meaningful DTD grammar caching/preparsing
037: * framework, this functionality has been moved into the XMLDTDLoader
038: * class. Therefore, this class no longer implements the DTDFilter
039: * or DTDContentModelFilter interfaces.
040: * <p>
041: * This component requires the following features and properties from the
042: * component manager that uses it:
043: * <ul>
044: * <li>http://xml.org/sax/features/namespaces</li>
045: * <li>http://xml.org/sax/features/validation</li>
046: * <li>http://apache.org/xml/features/validation/dynamic</li>
047: * <li>http://apache.org/xml/properties/internal/symbol-table</li>
048: * <li>http://apache.org/xml/properties/internal/error-reporter</li>
049: * <li>http://apache.org/xml/properties/internal/grammar-pool</li>
050: * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
051: * </ul>
052: *
053: * @xerces.internal
054: *
055: * @author Elena Litani, IBM
056: * @author Michael Glavassevich, IBM
057: *
058: * @version $Id: XML11NSDTDValidator.java 572055 2007-09-02 17:55:43Z mrglavas $
059: */
060: public class XML11NSDTDValidator extends XML11DTDValidator {
061:
062: /** Attribute QName. */
063: private final QName fAttributeQName = new QName();
064:
065: /** Bind namespaces */
066: protected final void startNamespaceScope(QName element,
067: XMLAttributes attributes, Augmentations augs)
068: throws XNIException {
069:
070: // add new namespace context
071: fNamespaceContext.pushContext();
072:
073: if (element.prefix == XMLSymbols.PREFIX_XMLNS) {
074: fErrorReporter.reportError(
075: XMLMessageFormatter.XMLNS_DOMAIN,
076: "ElementXMLNSPrefix",
077: new Object[] { element.rawname },
078: XMLErrorReporter.SEVERITY_FATAL_ERROR);
079: }
080:
081: // search for new namespace bindings
082: int length = attributes.getLength();
083: for (int i = 0; i < length; i++) {
084: String localpart = attributes.getLocalName(i);
085: String prefix = attributes.getPrefix(i);
086: // when it's of form xmlns="..." or xmlns:prefix="...",
087: // it's a namespace declaration. but prefix:xmlns="..." isn't.
088: if (prefix == XMLSymbols.PREFIX_XMLNS
089: || prefix == XMLSymbols.EMPTY_STRING
090: && localpart == XMLSymbols.PREFIX_XMLNS) {
091:
092: // get the internalized value of this attribute
093: String uri = fSymbolTable.addSymbol(attributes
094: .getValue(i));
095:
096: // 1. "xmlns" can't be bound to any namespace
097: if (prefix == XMLSymbols.PREFIX_XMLNS
098: && localpart == XMLSymbols.PREFIX_XMLNS) {
099: fErrorReporter.reportError(
100: XMLMessageFormatter.XMLNS_DOMAIN,
101: "CantBindXMLNS", new Object[] { attributes
102: .getQName(i) },
103: XMLErrorReporter.SEVERITY_FATAL_ERROR);
104: }
105:
106: // 2. the namespace for "xmlns" can't be bound to any prefix
107: if (uri == NamespaceContext.XMLNS_URI) {
108: fErrorReporter.reportError(
109: XMLMessageFormatter.XMLNS_DOMAIN,
110: "CantBindXMLNS", new Object[] { attributes
111: .getQName(i) },
112: XMLErrorReporter.SEVERITY_FATAL_ERROR);
113: }
114:
115: // 3. "xml" can't be bound to any other namespace than it's own
116: if (localpart == XMLSymbols.PREFIX_XML) {
117: if (uri != NamespaceContext.XML_URI) {
118: fErrorReporter
119: .reportError(
120: XMLMessageFormatter.XMLNS_DOMAIN,
121: "CantBindXML",
122: new Object[] { attributes
123: .getQName(i) },
124: XMLErrorReporter.SEVERITY_FATAL_ERROR);
125: }
126: }
127: // 4. the namespace for "xml" can't be bound to any other prefix
128: else {
129: if (uri == NamespaceContext.XML_URI) {
130: fErrorReporter
131: .reportError(
132: XMLMessageFormatter.XMLNS_DOMAIN,
133: "CantBindXML",
134: new Object[] { attributes
135: .getQName(i) },
136: XMLErrorReporter.SEVERITY_FATAL_ERROR);
137: }
138: }
139:
140: prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart
141: : XMLSymbols.EMPTY_STRING;
142:
143: // Declare prefix in context. Removing the association between a prefix and a
144: // namespace name is permitted in XML 1.1, so if the uri value is the empty string,
145: // the prefix is being unbound. -- mrglavas
146: fNamespaceContext.declarePrefix(prefix,
147: uri.length() != 0 ? uri : null);
148: }
149: }
150:
151: // bind the element
152: String prefix = element.prefix != null ? element.prefix
153: : XMLSymbols.EMPTY_STRING;
154: element.uri = fNamespaceContext.getURI(prefix);
155: if (element.prefix == null && element.uri != null) {
156: element.prefix = XMLSymbols.EMPTY_STRING;
157: }
158: if (element.prefix != null && element.uri == null) {
159: fErrorReporter.reportError(
160: XMLMessageFormatter.XMLNS_DOMAIN,
161: "ElementPrefixUnbound", new Object[] {
162: element.prefix, element.rawname },
163: XMLErrorReporter.SEVERITY_FATAL_ERROR);
164: }
165:
166: // bind the attributes
167: for (int i = 0; i < length; i++) {
168: attributes.getName(i, fAttributeQName);
169: String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix
170: : XMLSymbols.EMPTY_STRING;
171: String arawname = fAttributeQName.rawname;
172: if (arawname == XMLSymbols.PREFIX_XMLNS) {
173: fAttributeQName.uri = fNamespaceContext
174: .getURI(XMLSymbols.PREFIX_XMLNS);
175: attributes.setName(i, fAttributeQName);
176: } else if (aprefix != XMLSymbols.EMPTY_STRING) {
177: fAttributeQName.uri = fNamespaceContext.getURI(aprefix);
178: if (fAttributeQName.uri == null) {
179: fErrorReporter.reportError(
180: XMLMessageFormatter.XMLNS_DOMAIN,
181: "AttributePrefixUnbound",
182: new Object[] { element.rawname, arawname,
183: aprefix },
184: XMLErrorReporter.SEVERITY_FATAL_ERROR);
185: }
186: attributes.setName(i, fAttributeQName);
187: }
188: }
189:
190: // verify that duplicate attributes don't exist
191: // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
192: int attrCount = attributes.getLength();
193: for (int i = 0; i < attrCount - 1; i++) {
194: String auri = attributes.getURI(i);
195: if (auri == null || auri == NamespaceContext.XMLNS_URI) {
196: continue;
197: }
198: String alocalpart = attributes.getLocalName(i);
199: for (int j = i + 1; j < attrCount; j++) {
200: String blocalpart = attributes.getLocalName(j);
201: String buri = attributes.getURI(j);
202: if (alocalpart == blocalpart && auri == buri) {
203: fErrorReporter.reportError(
204: XMLMessageFormatter.XMLNS_DOMAIN,
205: "AttributeNSNotUnique",
206: new Object[] { element.rawname, alocalpart,
207: auri },
208: XMLErrorReporter.SEVERITY_FATAL_ERROR);
209: }
210: }
211: }
212:
213: } // startNamespaceScope(QName,XMLAttributes)
214:
215: /** Handles end element. */
216: protected void endNamespaceScope(QName element, Augmentations augs,
217: boolean isEmpty) throws XNIException {
218:
219: // bind element
220: String eprefix = element.prefix != null ? element.prefix
221: : XMLSymbols.EMPTY_STRING;
222: element.uri = fNamespaceContext.getURI(eprefix);
223: if (element.uri != null) {
224: element.prefix = eprefix;
225: }
226:
227: // call handlers
228: if (fDocumentHandler != null) {
229: if (!isEmpty) {
230: fDocumentHandler.endElement(element, augs);
231: }
232: }
233:
234: // pop context
235: fNamespaceContext.popContext();
236:
237: } // endNamespaceScope(QName,boolean)
238: }
|