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: *
057: * @version $Id: XMLNSDTDValidator.java 572055 2007-09-02 17:55:43Z mrglavas $
058: */
059: public class XMLNSDTDValidator extends XMLDTDValidator {
060:
061: /** Attribute QName. */
062: private final QName fAttributeQName = new QName();
063:
064: /** Bind namespaces */
065: protected final void startNamespaceScope(QName element,
066: XMLAttributes attributes, Augmentations augs)
067: throws XNIException {
068:
069: // add new namespace context
070: fNamespaceContext.pushContext();
071:
072: if (element.prefix == XMLSymbols.PREFIX_XMLNS) {
073: fErrorReporter.reportError(
074: XMLMessageFormatter.XMLNS_DOMAIN,
075: "ElementXMLNSPrefix",
076: new Object[] { element.rawname },
077: XMLErrorReporter.SEVERITY_FATAL_ERROR);
078: }
079:
080: // search for new namespace bindings
081: int length = attributes.getLength();
082: for (int i = 0; i < length; i++) {
083: String localpart = attributes.getLocalName(i);
084: String prefix = attributes.getPrefix(i);
085: // when it's of form xmlns="..." or xmlns:prefix="...",
086: // it's a namespace declaration. but prefix:xmlns="..." isn't.
087: if (prefix == XMLSymbols.PREFIX_XMLNS
088: || prefix == XMLSymbols.EMPTY_STRING
089: && localpart == XMLSymbols.PREFIX_XMLNS) {
090:
091: // get the internalized value of this attribute
092: String uri = fSymbolTable.addSymbol(attributes
093: .getValue(i));
094:
095: // 1. "xmlns" can't be bound to any namespace
096: if (prefix == XMLSymbols.PREFIX_XMLNS
097: && localpart == XMLSymbols.PREFIX_XMLNS) {
098: fErrorReporter.reportError(
099: XMLMessageFormatter.XMLNS_DOMAIN,
100: "CantBindXMLNS", new Object[] { attributes
101: .getQName(i) },
102: XMLErrorReporter.SEVERITY_FATAL_ERROR);
103: }
104:
105: // 2. the namespace for "xmlns" can't be bound to any prefix
106: if (uri == NamespaceContext.XMLNS_URI) {
107: fErrorReporter.reportError(
108: XMLMessageFormatter.XMLNS_DOMAIN,
109: "CantBindXMLNS", new Object[] { attributes
110: .getQName(i) },
111: XMLErrorReporter.SEVERITY_FATAL_ERROR);
112: }
113:
114: // 3. "xml" can't be bound to any other namespace than it's own
115: if (localpart == XMLSymbols.PREFIX_XML) {
116: if (uri != NamespaceContext.XML_URI) {
117: fErrorReporter
118: .reportError(
119: XMLMessageFormatter.XMLNS_DOMAIN,
120: "CantBindXML",
121: new Object[] { attributes
122: .getQName(i) },
123: XMLErrorReporter.SEVERITY_FATAL_ERROR);
124: }
125: }
126: // 4. the namespace for "xml" can't be bound to any other prefix
127: else {
128: if (uri == NamespaceContext.XML_URI) {
129: fErrorReporter
130: .reportError(
131: XMLMessageFormatter.XMLNS_DOMAIN,
132: "CantBindXML",
133: new Object[] { attributes
134: .getQName(i) },
135: XMLErrorReporter.SEVERITY_FATAL_ERROR);
136: }
137: }
138:
139: prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart
140: : XMLSymbols.EMPTY_STRING;
141:
142: // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
143: // We should only report an error if there is a prefix,
144: // that is, the local part is not "xmlns". -SG
145: if (uri == XMLSymbols.EMPTY_STRING
146: && localpart != XMLSymbols.PREFIX_XMLNS) {
147: fErrorReporter.reportError(
148: XMLMessageFormatter.XMLNS_DOMAIN,
149: "EmptyPrefixedAttName",
150: new Object[] { attributes.getQName(i) },
151: XMLErrorReporter.SEVERITY_FATAL_ERROR);
152: continue;
153: }
154:
155: // declare prefix in context
156: fNamespaceContext.declarePrefix(prefix,
157: uri.length() != 0 ? uri : null);
158: }
159: }
160:
161: // bind the element
162: String prefix = element.prefix != null ? element.prefix
163: : XMLSymbols.EMPTY_STRING;
164: element.uri = fNamespaceContext.getURI(prefix);
165: if (element.prefix == null && element.uri != null) {
166: element.prefix = XMLSymbols.EMPTY_STRING;
167: }
168: if (element.prefix != null && element.uri == null) {
169: fErrorReporter.reportError(
170: XMLMessageFormatter.XMLNS_DOMAIN,
171: "ElementPrefixUnbound", new Object[] {
172: element.prefix, element.rawname },
173: XMLErrorReporter.SEVERITY_FATAL_ERROR);
174: }
175:
176: // bind the attributes
177: for (int i = 0; i < length; i++) {
178: attributes.getName(i, fAttributeQName);
179: String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix
180: : XMLSymbols.EMPTY_STRING;
181: String arawname = fAttributeQName.rawname;
182: if (arawname == XMLSymbols.PREFIX_XMLNS) {
183: fAttributeQName.uri = fNamespaceContext
184: .getURI(XMLSymbols.PREFIX_XMLNS);
185: attributes.setName(i, fAttributeQName);
186: } else if (aprefix != XMLSymbols.EMPTY_STRING) {
187: fAttributeQName.uri = fNamespaceContext.getURI(aprefix);
188: if (fAttributeQName.uri == null) {
189: fErrorReporter.reportError(
190: XMLMessageFormatter.XMLNS_DOMAIN,
191: "AttributePrefixUnbound",
192: new Object[] { element.rawname, arawname,
193: aprefix },
194: XMLErrorReporter.SEVERITY_FATAL_ERROR);
195: }
196: attributes.setName(i, fAttributeQName);
197: }
198: }
199:
200: // verify that duplicate attributes don't exist
201: // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
202: int attrCount = attributes.getLength();
203: for (int i = 0; i < attrCount - 1; i++) {
204: String auri = attributes.getURI(i);
205: if (auri == null || auri == NamespaceContext.XMLNS_URI) {
206: continue;
207: }
208: String alocalpart = attributes.getLocalName(i);
209: for (int j = i + 1; j < attrCount; j++) {
210: String blocalpart = attributes.getLocalName(j);
211: String buri = attributes.getURI(j);
212: if (alocalpart == blocalpart && auri == buri) {
213: fErrorReporter.reportError(
214: XMLMessageFormatter.XMLNS_DOMAIN,
215: "AttributeNSNotUnique",
216: new Object[] { element.rawname, alocalpart,
217: auri },
218: XMLErrorReporter.SEVERITY_FATAL_ERROR);
219: }
220: }
221: }
222:
223: } // startNamespaceScope(QName,XMLAttributes)
224:
225: /** Handles end element. */
226: protected void endNamespaceScope(QName element, Augmentations augs,
227: boolean isEmpty) throws XNIException {
228:
229: // bind element
230: String eprefix = element.prefix != null ? element.prefix
231: : XMLSymbols.EMPTY_STRING;
232: element.uri = fNamespaceContext.getURI(eprefix);
233: if (element.uri != null) {
234: element.prefix = eprefix;
235: }
236:
237: // call handlers
238: if (fDocumentHandler != null) {
239: if (!isEmpty) {
240: fDocumentHandler.endElement(element, augs);
241: }
242: }
243:
244: // pop context
245: fNamespaceContext.popContext();
246:
247: } // endNamespaceScope(QName,boolean)
248:
249: }
|