1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xerces.internal.impl.dtd; 23 24 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 25 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 26 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 27 import com.sun.org.apache.xerces.internal.xni.Augmentations; 28 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 29 import com.sun.org.apache.xerces.internal.xni.QName; 30 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 31 import com.sun.org.apache.xerces.internal.xni.XNIException; 32 33 /** 34 * The DTD validator. The validator implements a document 35 * filter: receiving document events from the scanner; validating 36 * the content and structure; augmenting the InfoSet, if applicable; 37 * and notifying the parser of the information resulting from the 38 * validation process. 39 * <p> Formerly, this component also handled DTD events and grammar construction. 40 * To facilitate the development of a meaningful DTD grammar caching/preparsing 41 * framework, this functionality has been moved into the XMLDTDLoader 42 * class. Therefore, this class no longer implements the DTDFilter 43 * or DTDContentModelFilter interfaces. 44 * <p> 45 * This component requires the following features and properties from the 46 * component manager that uses it: 47 * <ul> 48 * <li>http://xml.org/sax/features/namespaces</li> 49 * <li>http://xml.org/sax/features/validation</li> 50 * <li>http://apache.org/xml/features/validation/dynamic</li> 51 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 52 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 53 * <li>http://apache.org/xml/properties/internal/grammar-pool</li> 54 * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> 55 * </ul> 56 * 57 * @xerces.internal 58 * 59 * @author Elena Litani, IBM 60 * @author Michael Glavassevich, IBM 61 * 62 63 */ 64 public class XML11NSDTDValidator extends XML11DTDValidator { 65 66 /** Attribute QName. */ 67 private QName fAttributeQName = new QName(); 68 69 /** Bind namespaces */ startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs)70 protected final void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs) 71 throws XNIException { 72 73 // add new namespace context 74 fNamespaceContext.pushContext(); 75 76 if (element.prefix == XMLSymbols.PREFIX_XMLNS) { 77 fErrorReporter.reportError( 78 XMLMessageFormatter.XMLNS_DOMAIN, 79 "ElementXMLNSPrefix", 80 new Object[] { element.rawname }, 81 XMLErrorReporter.SEVERITY_FATAL_ERROR); 82 } 83 84 // search for new namespace bindings 85 int length = attributes.getLength(); 86 for (int i = 0; i < length; i++) { 87 String localpart = attributes.getLocalName(i); 88 String prefix = attributes.getPrefix(i); 89 // when it's of form xmlns="..." or xmlns:prefix="...", 90 // it's a namespace declaration. but prefix:xmlns="..." isn't. 91 if (prefix == XMLSymbols.PREFIX_XMLNS || prefix == XMLSymbols.EMPTY_STRING 92 && localpart == XMLSymbols.PREFIX_XMLNS) { 93 94 // get the internalized value of this attribute 95 String uri = fSymbolTable.addSymbol(attributes.getValue(i)); 96 97 // 1. "xmlns" can't be bound to any namespace 98 if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { 99 fErrorReporter.reportError( 100 XMLMessageFormatter.XMLNS_DOMAIN, 101 "CantBindXMLNS", 102 new Object[] { attributes.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", 111 new Object[] { attributes.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.reportError( 119 XMLMessageFormatter.XMLNS_DOMAIN, 120 "CantBindXML", 121 new Object[] { attributes.getQName(i)}, 122 XMLErrorReporter.SEVERITY_FATAL_ERROR); 123 } 124 } 125 // 4. the namespace for "xml" can't be bound to any other prefix 126 else { 127 if (uri == NamespaceContext.XML_URI) { 128 fErrorReporter.reportError( 129 XMLMessageFormatter.XMLNS_DOMAIN, 130 "CantBindXML", 131 new Object[] { attributes.getQName(i)}, 132 XMLErrorReporter.SEVERITY_FATAL_ERROR); 133 } 134 } 135 136 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; 137 138 // Declare prefix in context. Removing the association between a prefix and a 139 // namespace name is permitted in XML 1.1, so if the uri value is the empty string, 140 // the prefix is being unbound. -- mrglavas 141 fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); 142 } 143 } 144 145 // bind the element 146 String prefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; 147 element.uri = fNamespaceContext.getURI(prefix); 148 if (element.prefix == null && element.uri != null) { 149 element.prefix = XMLSymbols.EMPTY_STRING; 150 } 151 if (element.prefix != null && element.uri == null) { 152 fErrorReporter.reportError( 153 XMLMessageFormatter.XMLNS_DOMAIN, 154 "ElementPrefixUnbound", 155 new Object[] { element.prefix, element.rawname }, 156 XMLErrorReporter.SEVERITY_FATAL_ERROR); 157 } 158 159 // bind the attributes 160 for (int i = 0; i < length; i++) { 161 attributes.getName(i, fAttributeQName); 162 String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; 163 String arawname = fAttributeQName.rawname; 164 if (arawname == XMLSymbols.PREFIX_XMLNS) { 165 fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS); 166 attributes.setName(i, fAttributeQName); 167 } else if (aprefix != XMLSymbols.EMPTY_STRING) { 168 fAttributeQName.uri = fNamespaceContext.getURI(aprefix); 169 if (fAttributeQName.uri == null) { 170 fErrorReporter.reportError( 171 XMLMessageFormatter.XMLNS_DOMAIN, 172 "AttributePrefixUnbound", 173 new Object[] { element.rawname, arawname, aprefix }, 174 XMLErrorReporter.SEVERITY_FATAL_ERROR); 175 } 176 attributes.setName(i, fAttributeQName); 177 } 178 } 179 180 // verify that duplicate attributes don't exist 181 // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/> 182 int attrCount = attributes.getLength(); 183 for (int i = 0; i < attrCount - 1; i++) { 184 String auri = attributes.getURI(i); 185 if (auri == null || auri == NamespaceContext.XMLNS_URI) { 186 continue; 187 } 188 String alocalpart = attributes.getLocalName(i); 189 for (int j = i + 1; j < attrCount; j++) { 190 String blocalpart = attributes.getLocalName(j); 191 String buri = attributes.getURI(j); 192 if (alocalpart == blocalpart && auri == buri) { 193 fErrorReporter.reportError( 194 XMLMessageFormatter.XMLNS_DOMAIN, 195 "AttributeNSNotUnique", 196 new Object[] { element.rawname, alocalpart, auri }, 197 XMLErrorReporter.SEVERITY_FATAL_ERROR); 198 } 199 } 200 } 201 202 } // startNamespaceScope(QName,XMLAttributes) 203 204 /** Handles end element. */ endNamespaceScope(QName element, Augmentations augs, boolean isEmpty)205 protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty) 206 throws XNIException { 207 208 // bind element 209 String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; 210 element.uri = fNamespaceContext.getURI(eprefix); 211 if (element.uri != null) { 212 element.prefix = eprefix; 213 } 214 215 // call handlers 216 if (fDocumentHandler != null) { 217 if (!isEmpty) { 218 fDocumentHandler.endElement(element, augs); 219 } 220 } 221 222 // pop context 223 fNamespaceContext.popContext(); 224 225 } // endNamespaceScope(QName,boolean) 226 } 227