/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.xerces.impl.dtd;

import org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.impl.msg.XMLMessageFormatter;
import org.apache.xerces.util.XMLSymbols;
import org.apache.xerces.xni.Augmentations;
import org.apache.xerces.xni.NamespaceContext;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XNIException;

The DTD validator. The validator implements a document filter: receiving document events from the scanner; validating the content and structure; augmenting the InfoSet, if applicable; and notifying the parser of the information resulting from the validation process.

Formerly, this component also handled DTD events and grammar construction. To facilitate the development of a meaningful DTD grammar caching/preparsing framework, this functionality has been moved into the XMLDTDLoader class. Therefore, this class no longer implements the DTDFilter or DTDContentModelFilter interfaces.

This component requires the following features and properties from the component manager that uses it:

  • http://xml.org/sax/features/namespaces
  • http://xml.org/sax/features/validation
  • http://apache.org/xml/features/validation/dynamic
  • http://apache.org/xml/properties/internal/symbol-table
  • http://apache.org/xml/properties/internal/error-reporter
  • http://apache.org/xml/properties/internal/grammar-pool
  • http://apache.org/xml/properties/internal/datatype-validator-factory
Author:Elena Litani, IBM, Michael Glavassevich, IBM
@xerces.internal
Version:$Id: XML11NSDTDValidator.java 572055 2007-09-02 17:55:43Z mrglavas $
/** * The DTD validator. The validator implements a document * filter: receiving document events from the scanner; validating * the content and structure; augmenting the InfoSet, if applicable; * and notifying the parser of the information resulting from the * validation process. * <p> Formerly, this component also handled DTD events and grammar construction. * To facilitate the development of a meaningful DTD grammar caching/preparsing * framework, this functionality has been moved into the XMLDTDLoader * class. Therefore, this class no longer implements the DTDFilter * or DTDContentModelFilter interfaces. * <p> * This component requires the following features and properties from the * component manager that uses it: * <ul> * <li>http://xml.org/sax/features/namespaces</li> * <li>http://xml.org/sax/features/validation</li> * <li>http://apache.org/xml/features/validation/dynamic</li> * <li>http://apache.org/xml/properties/internal/symbol-table</li> * <li>http://apache.org/xml/properties/internal/error-reporter</li> * <li>http://apache.org/xml/properties/internal/grammar-pool</li> * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> * </ul> * * @xerces.internal * * @author Elena Litani, IBM * @author Michael Glavassevich, IBM * * @version $Id: XML11NSDTDValidator.java 572055 2007-09-02 17:55:43Z mrglavas $ */
public class XML11NSDTDValidator extends XML11DTDValidator {
Attribute QName.
/** Attribute QName. */
private final QName fAttributeQName = new QName();
Bind namespaces
/** Bind namespaces */
protected final void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { // add new namespace context fNamespaceContext.pushContext(); if (element.prefix == XMLSymbols.PREFIX_XMLNS) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "ElementXMLNSPrefix", new Object[] { element.rawname }, XMLErrorReporter.SEVERITY_FATAL_ERROR); } // search for new namespace bindings int length = attributes.getLength(); for (int i = 0; i < length; i++) { String localpart = attributes.getLocalName(i); String prefix = attributes.getPrefix(i); // when it's of form xmlns="..." or xmlns:prefix="...", // it's a namespace declaration. but prefix:xmlns="..." isn't. if (prefix == XMLSymbols.PREFIX_XMLNS || prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) { // get the internalized value of this attribute String uri = fSymbolTable.addSymbol(attributes.getValue(i)); // 1. "xmlns" can't be bound to any namespace if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "CantBindXMLNS", new Object[] { attributes.getQName(i)}, XMLErrorReporter.SEVERITY_FATAL_ERROR); } // 2. the namespace for "xmlns" can't be bound to any prefix if (uri == NamespaceContext.XMLNS_URI) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "CantBindXMLNS", new Object[] { attributes.getQName(i)}, XMLErrorReporter.SEVERITY_FATAL_ERROR); } // 3. "xml" can't be bound to any other namespace than it's own if (localpart == XMLSymbols.PREFIX_XML) { if (uri != NamespaceContext.XML_URI) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "CantBindXML", new Object[] { attributes.getQName(i)}, XMLErrorReporter.SEVERITY_FATAL_ERROR); } } // 4. the namespace for "xml" can't be bound to any other prefix else { if (uri == NamespaceContext.XML_URI) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "CantBindXML", new Object[] { attributes.getQName(i)}, XMLErrorReporter.SEVERITY_FATAL_ERROR); } } prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING; // Declare prefix in context. Removing the association between a prefix and a // namespace name is permitted in XML 1.1, so if the uri value is the empty string, // the prefix is being unbound. -- mrglavas fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null); } } // bind the element String prefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; element.uri = fNamespaceContext.getURI(prefix); if (element.prefix == null && element.uri != null) { element.prefix = XMLSymbols.EMPTY_STRING; } if (element.prefix != null && element.uri == null) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "ElementPrefixUnbound", new Object[] { element.prefix, element.rawname }, XMLErrorReporter.SEVERITY_FATAL_ERROR); } // bind the attributes for (int i = 0; i < length; i++) { attributes.getName(i, fAttributeQName); String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING; String arawname = fAttributeQName.rawname; if (arawname == XMLSymbols.PREFIX_XMLNS) { fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS); attributes.setName(i, fAttributeQName); } else if (aprefix != XMLSymbols.EMPTY_STRING) { fAttributeQName.uri = fNamespaceContext.getURI(aprefix); if (fAttributeQName.uri == null) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "AttributePrefixUnbound", new Object[] { element.rawname, arawname, aprefix }, XMLErrorReporter.SEVERITY_FATAL_ERROR); } attributes.setName(i, fAttributeQName); } } // verify that duplicate attributes don't exist // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/> int attrCount = attributes.getLength(); for (int i = 0; i < attrCount - 1; i++) { String auri = attributes.getURI(i); if (auri == null || auri == NamespaceContext.XMLNS_URI) { continue; } String alocalpart = attributes.getLocalName(i); for (int j = i + 1; j < attrCount; j++) { String blocalpart = attributes.getLocalName(j); String buri = attributes.getURI(j); if (alocalpart == blocalpart && auri == buri) { fErrorReporter.reportError( XMLMessageFormatter.XMLNS_DOMAIN, "AttributeNSNotUnique", new Object[] { element.rawname, alocalpart, auri }, XMLErrorReporter.SEVERITY_FATAL_ERROR); } } } } // startNamespaceScope(QName,XMLAttributes)
Handles end element.
/** Handles end element. */
protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty) throws XNIException { // bind element String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING; element.uri = fNamespaceContext.getURI(eprefix); if (element.uri != null) { element.prefix = eprefix; } // call handlers if (fDocumentHandler != null) { if (!isEmpty) { fDocumentHandler.endElement(element, augs); } } // pop context fNamespaceContext.popContext(); } // endNamespaceScope(QName,boolean) }