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