1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * The Apache Software License, Version 1.1 7 * 8 * 9 * Copyright (c) 1999-2003 The Apache Software Foundation. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in 21 * the documentation and/or other materials provided with the 22 * distribution. 23 * 24 * 3. The end-user documentation included with the redistribution, 25 * if any, must include the following acknowledgment: 26 * "This product includes software developed by the 27 * Apache Software Foundation (http://www.apache.org/)." 28 * Alternately, this acknowledgment may appear in the software itself, 29 * if and wherever such third-party acknowledgments normally appear. 30 * 31 * 4. The names "Xerces" and "Apache Software Foundation" must 32 * not be used to endorse or promote products derived from this 33 * software without prior written permission. For written 34 * permission, please contact apache@apache.org. 35 * 36 * 5. Products derived from this software may not be called "Apache", 37 * nor may "Apache" appear in their name, without prior written 38 * permission of the Apache Software Foundation. 39 * 40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 42 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 47 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 48 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * ==================================================================== 53 * 54 * This software consists of voluntary contributions made by many 55 * individuals on behalf of the Apache Software Foundation and was 56 * originally based on software copyright (c) 2002, International 57 * Business Machines, Inc., http://www.apache.org. For more 58 * information on the Apache Software Foundation, please see 59 * <http://www.apache.org/>. 60 */ 61 62 package com.sun.org.apache.xerces.internal.impl.dtd; 63 64 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 65 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 66 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 67 import com.sun.org.apache.xerces.internal.xni.Augmentations; 68 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 69 import com.sun.org.apache.xerces.internal.xni.QName; 70 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 71 import com.sun.org.apache.xerces.internal.xni.XNIException; 72 73 /** 74 * The DTD validator. The validator implements a document 75 * filter: receiving document events from the scanner; validating 76 * the content and structure; augmenting the InfoSet, if applicable; 77 * and notifying the parser of the information resulting from the 78 * validation process. 79 * <p> Formerly, this component also handled DTD events and grammar construction. 80 * To facilitate the development of a meaningful DTD grammar caching/preparsing 81 * framework, this functionality has been moved into the XMLDTDLoader 82 * class. Therefore, this class no longer implements the DTDFilter 83 * or DTDContentModelFilter interfaces. 84 * <p> 85 * This component requires the following features and properties from the 86 * component manager that uses it: 87 * <ul> 88 * <li>http://xml.org/sax/features/namespaces</li> 89 * <li>http://xml.org/sax/features/validation</li> 90 * <li>http://apache.org/xml/features/validation/dynamic</li> 91 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 92 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 93 * <li>http://apache.org/xml/properties/internal/grammar-pool</li> 94 * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> 95 * </ul> 96 * 97 * @xerces.internal 98 * 99 * @author Elena Litani, IBM 100 * @author Michael Glavassevich, IBM 101 * 102 103 */ 104 public class XML11NSDTDValidator extends XML11DTDValidator { 105 106 /** Attribute QName. */ 107 private QName fAttributeQName = new QName(); 108 109 /** Bind namespaces */ 110 protected final void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs) 111 throws XNIException { 112 113 // add new namespace context 114 fNamespaceContext.pushContext(); 115 116 if (element.prefix == XMLSymbols.PREFIX_XMLNS) { 117 fErrorReporter.reportError( 118 XMLMessageFormatter.XMLNS_DOMAIN, 119 "ElementXMLNSPrefix", 120 new Object[] { element.rawname }, 121 XMLErrorReporter.SEVERITY_FATAL_ERROR); 122 } 123 124 // search for new namespace bindings 125 int length = attributes.getLength(); 126 for (int i = 0; i < length; i++) { 127 String localpart = attributes.getLocalName(i); 128 String prefix = attributes.getPrefix(i); 129 // when it's of form xmlns="..." or xmlns:prefix="...", 130 // it's a namespace declaration. but prefix:xmlns="..." isn't. 131 if (prefix == XMLSymbols.PREFIX_XMLNS || prefix == XMLSymbols.EMPTY_STRING 132 && localpart == XMLSymbols.PREFIX_XMLNS) { 133 134 // get the internalized value of this attribute 135 String uri = fSymbolTable.addSymbol(attributes.getValue(i)); 136 137 // 1. "xmlns" can't be bound to any namespace 138 if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { 139 fErrorReporter.reportError( 140 XMLMessageFormatter.XMLNS_DOMAIN, 141 "CantBindXMLNS", 142 new Object[] { attributes.getQName(i)}, 143 XMLErrorReporter.SEVERITY_FATAL_ERROR); 144 } 145 146 // 2. the namespace for "xmlns" can't be bound to any prefix 147 if (uri == NamespaceContext.XMLNS_URI) { 148 fErrorReporter.reportError( 149 XMLMessageFormatter.XMLNS_DOMAIN, 150 "CantBindXMLNS", 151 new Object[] { attributes.getQName(i)}, 152 XMLErrorReporter.SEVERITY_FATAL_ERROR); 153 } 154 155 // 3. "xml" can't be bound to any other namespace than it's own 156 if (localpart == XMLSymbols.PREFIX_XML) { 157 if (uri != NamespaceContext.XML_URI) { 158 fErrorReporter.reportError( 159 XMLMessageFormatter.XMLNS_DOMAIN, 160 "CantBindXML", 161 new Object[] { attributes.getQName(i)}, 162 XMLErrorReporter.SEVERITY_FATAL_ERROR); 163 } 164 } 165 // 4. the namespace for "xml" can't be bound to any other prefix 166 else { 167 if (uri == NamespaceContext.XML_URI) { 168 fErrorReporter.reportError( 169 XMLMessageFormatter.XMLNS_DOMAIN, 170 "CantBindXML", 171 new Object[] { attributes.getQName(i)}, 172 XMLErrorReporter.SEVERITY_FATAL_ERROR); 173 } 174 } 175 176 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; 177 178 // Declare prefix in context. Removing the association between a prefix and a 179 // namespace name is permitted in XML 1.1, so if the uri value is the empty string, 180 // the prefix is being unbound. -- mrglavas 181 fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); 182 } 183 } 184 185 // bind the element 186 String prefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; 187 element.uri = fNamespaceContext.getURI(prefix); 188 if (element.prefix == null && element.uri != null) { 189 element.prefix = XMLSymbols.EMPTY_STRING; 190 } 191 if (element.prefix != null && element.uri == null) { 192 fErrorReporter.reportError( 193 XMLMessageFormatter.XMLNS_DOMAIN, 194 "ElementPrefixUnbound", 195 new Object[] { element.prefix, element.rawname }, 196 XMLErrorReporter.SEVERITY_FATAL_ERROR); 197 } 198 199 // bind the attributes 200 for (int i = 0; i < length; i++) { 201 attributes.getName(i, fAttributeQName); 202 String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; 203 String arawname = fAttributeQName.rawname; 204 if (arawname == XMLSymbols.PREFIX_XMLNS) { 205 fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS); 206 attributes.setName(i, fAttributeQName); 207 } else if (aprefix != XMLSymbols.EMPTY_STRING) { 208 fAttributeQName.uri = fNamespaceContext.getURI(aprefix); 209 if (fAttributeQName.uri == null) { 210 fErrorReporter.reportError( 211 XMLMessageFormatter.XMLNS_DOMAIN, 212 "AttributePrefixUnbound", 213 new Object[] { element.rawname, arawname, aprefix }, 214 XMLErrorReporter.SEVERITY_FATAL_ERROR); 215 } 216 attributes.setName(i, fAttributeQName); 217 } 218 } 219 220 // verify that duplicate attributes don't exist 221 // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/> 222 int attrCount = attributes.getLength(); 223 for (int i = 0; i < attrCount - 1; i++) { 224 String auri = attributes.getURI(i); 225 if (auri == null || auri == NamespaceContext.XMLNS_URI) { 226 continue; 227 } 228 String alocalpart = attributes.getLocalName(i); 229 for (int j = i + 1; j < attrCount; j++) { 230 String blocalpart = attributes.getLocalName(j); 231 String buri = attributes.getURI(j); 232 if (alocalpart == blocalpart && auri == buri) { 233 fErrorReporter.reportError( 234 XMLMessageFormatter.XMLNS_DOMAIN, 235 "AttributeNSNotUnique", 236 new Object[] { element.rawname, alocalpart, auri }, 237 XMLErrorReporter.SEVERITY_FATAL_ERROR); 238 } 239 } 240 } 241 242 } // startNamespaceScope(QName,XMLAttributes) 243 244 /** Handles end element. */ 245 protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty) 246 throws XNIException { 247 248 // bind element 249 String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; 250 element.uri = fNamespaceContext.getURI(eprefix); 251 if (element.uri != null) { 252 element.prefix = eprefix; 253 } 254 255 // call handlers 256 if (fDocumentHandler != null) { 257 if (!isEmpty) { 258 fDocumentHandler.endElement(element, augs); 259 } 260 } 261 262 // pop context 263 fNamespaceContext.popContext(); 264 265 } // endNamespaceScope(QName,boolean) 266 }