XML11NSDTDValidator.java revision 628:2bfaf29cc90b
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
62package com.sun.org.apache.xerces.internal.impl.dtd;
63
64import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
65import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
66import com.sun.org.apache.xerces.internal.util.XMLSymbols;
67import com.sun.org.apache.xerces.internal.xni.Augmentations;
68import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
69import com.sun.org.apache.xerces.internal.xni.QName;
70import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
71import 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 */
104public 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}
267