View Javadoc
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 }