mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			394 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			394 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* XMLSchemaValidatorHandler.java --
 | |
|    Copyright (C) 2006  Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| package gnu.xml.validation.xmlschema;
 | |
| 
 | |
| import java.util.ArrayList;
 | |
| import java.util.LinkedList;
 | |
| import javax.xml.XMLConstants;
 | |
| import javax.xml.namespace.QName;
 | |
| import javax.xml.validation.TypeInfoProvider;
 | |
| import javax.xml.validation.ValidatorHandler;
 | |
| import org.relaxng.datatype.DatatypeException;
 | |
| import org.relaxng.datatype.DatatypeLibrary;
 | |
| import org.relaxng.datatype.helpers.DatatypeLibraryLoader;
 | |
| import org.w3c.dom.TypeInfo;
 | |
| import org.w3c.dom.ls.LSResourceResolver;
 | |
| import org.xml.sax.Attributes;
 | |
| import org.xml.sax.ContentHandler;
 | |
| import org.xml.sax.ErrorHandler;
 | |
| import org.xml.sax.Locator;
 | |
| import org.xml.sax.SAXException;
 | |
| import org.xml.sax.ext.Attributes2Impl;
 | |
| import org.xml.sax.helpers.NamespaceSupport;
 | |
| import gnu.xml.validation.datatype.SimpleType;
 | |
| import gnu.xml.validation.datatype.Type;
 | |
| 
 | |
| /**
 | |
|  * Streaming validator.
 | |
|  *
 | |
|  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
 | |
|  */
 | |
| final class XMLSchemaValidatorHandler
 | |
|   extends ValidatorHandler
 | |
| {
 | |
| 
 | |
|   final XMLSchema schema;
 | |
|   final TypeInfoProvider typeInfoProvider;
 | |
|   final NamespaceSupport namespaceSupport;
 | |
|   final DatatypeLibrary typeLibrary;
 | |
|   Locator loc;
 | |
|   ContentHandler contentHandler;
 | |
|   ErrorHandler errorHandler;
 | |
|   LSResourceResolver resourceResolver;
 | |
|   final LinkedList context; // element context
 | |
|   final ArrayList attributes; // attribute context;
 | |
| 
 | |
|   XMLSchemaValidatorHandler(XMLSchema schema)
 | |
|   {
 | |
|     this.schema = schema;
 | |
|     typeInfoProvider = new XMLSchemaTypeInfoProvider(this);
 | |
|     namespaceSupport = new NamespaceSupport();
 | |
|     context = new LinkedList();
 | |
|     attributes = new ArrayList();
 | |
|     final String ns = XMLConstants.W3C_XML_SCHEMA_NS_URI;
 | |
|     typeLibrary = new DatatypeLibraryLoader().createDatatypeLibrary(ns);
 | |
|   }
 | |
| 
 | |
|   public ContentHandler getContentHandler()
 | |
|   {
 | |
|     return contentHandler;
 | |
|   }
 | |
| 
 | |
|   public void setContentHandler(ContentHandler contentHandler)
 | |
|   {
 | |
|     this.contentHandler = contentHandler;
 | |
|   }
 | |
| 
 | |
|   public ErrorHandler getErrorHandler()
 | |
|   {
 | |
|     return errorHandler;
 | |
|   }
 | |
| 
 | |
|   public void setErrorHandler(ErrorHandler errorHandler)
 | |
|   {
 | |
|     this.errorHandler = errorHandler;
 | |
|   }
 | |
| 
 | |
|   public LSResourceResolver getResourceResolver()
 | |
|   {
 | |
|     return resourceResolver;
 | |
|   }
 | |
| 
 | |
|   public void setResourceResolver(LSResourceResolver resourceResolver)
 | |
|   {
 | |
|     this.resourceResolver = resourceResolver;
 | |
|   }
 | |
| 
 | |
|   public TypeInfoProvider getTypeInfoProvider()
 | |
|   {
 | |
|     return typeInfoProvider;
 | |
|   }
 | |
| 
 | |
|   TypeInfo getElementTypeInfo()
 | |
|   {
 | |
|     return (XMLSchemaElementTypeInfo) context.getFirst();
 | |
|   }
 | |
| 
 | |
|   TypeInfo getAttributeTypeInfo(int index)
 | |
|   {
 | |
|     return (XMLSchemaAttributeTypeInfo) attributes.get(index);
 | |
|   }
 | |
| 
 | |
|   boolean isIdAttribute(int index)
 | |
|   {
 | |
|     XMLSchemaAttributeTypeInfo typeInfo =
 | |
|       (XMLSchemaAttributeTypeInfo) attributes.get(index);
 | |
|     return typeInfo.id;
 | |
|   }
 | |
| 
 | |
|   boolean isSpecified(int index)
 | |
|   {
 | |
|     XMLSchemaAttributeTypeInfo typeInfo =
 | |
|       (XMLSchemaAttributeTypeInfo) attributes.get(index);
 | |
|     return typeInfo.specified;
 | |
|   }
 | |
| 
 | |
|   public void setDocumentLocator(Locator locator)
 | |
|   {
 | |
|     loc = locator;
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.setDocumentLocator(locator);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void startDocument()
 | |
|     throws SAXException
 | |
|   {
 | |
|     namespaceSupport.reset();
 | |
|     context.clear();
 | |
|     attributes.clear();
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.startDocument();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void endDocument()
 | |
|     throws SAXException
 | |
|   {
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.endDocument();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void startPrefixMapping(String prefix, String uri)
 | |
|     throws SAXException
 | |
|   {
 | |
|     namespaceSupport.declarePrefix(prefix, uri);
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.startPrefixMapping(prefix, uri);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void endPrefixMapping(String prefix)
 | |
|     throws SAXException
 | |
|   {
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.endPrefixMapping(prefix);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void startElement(String uri, String localName, String qName,
 | |
|                            Attributes atts)
 | |
|     throws SAXException
 | |
|   {
 | |
|     namespaceSupport.pushContext();
 | |
|     QName name = new QName(uri, localName);
 | |
|     ElementDeclaration decl =
 | |
|       (ElementDeclaration) schema.elementDeclarations.get(name);
 | |
|     // Validation Rule: Element Locally Valid (Element)
 | |
|     String xsiType =
 | |
|       atts.getValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type");
 | |
|     xsiType = xsiType.trim(); // normalise
 | |
|     String xsiNil =
 | |
|       atts.getValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil");
 | |
|     Type type = decl.datatype;
 | |
|     if (xsiType.length() > 0)
 | |
|       {
 | |
|         try
 | |
|           {
 | |
|             Type specifiedType = resolveType(xsiType);
 | |
|             //  TODO 4.3
 | |
|             type = specifiedType;
 | |
|           }
 | |
|         catch (DatatypeException e) // 4.1, 4.2
 | |
|           {
 | |
|             ValidationException e2 =
 | |
|               new ValidationException("Can't resolve type " + xsiType,
 | |
|                                       loc);
 | |
|             e2.initCause(e);
 | |
|             throw e2;
 | |
|           }
 | |
|       }
 | |
|     XMLSchemaElementTypeInfo typeInfo =
 | |
|       new XMLSchemaElementTypeInfo(schema, decl, type);
 | |
|     if (decl == null) // 1
 | |
|       {
 | |
|         throw new ValidationException("No declaration for " + name, loc);
 | |
|       }
 | |
|     if (decl.isAbstract) // 2
 | |
|       {
 | |
|         throw new ValidationException("Declaration for " + name +
 | |
|                                       " is abstract", loc);
 | |
|       }
 | |
|     if (xsiNil.length() > 0)
 | |
|       {
 | |
|         if (!decl.nillable) // 3.1
 | |
|           {
 | |
|             throw new ValidationException("Declaration for " + name +
 | |
|                                           " is nillable but xsi:nil present",
 | |
|                                           loc);
 | |
|           }
 | |
|         else if ("true".equals(xsiNil)) // 3.2
 | |
|           {
 | |
|             typeInfo.nil = true;
 | |
|             if (decl.type == XMLSchema.CONSTRAINT_FIXED) // 3.2.2
 | |
|               {
 | |
|                 throw new ValidationException("Declaration for " + name +
 | |
|                                               " is fixed but xsi:nil is true",
 | |
|                                               loc);
 | |
|               }
 | |
|           }
 | |
|       }
 | |
|     // TODO 5, 6, 7
 | |
| 
 | |
|     // parent
 | |
|     if (!context.isEmpty())
 | |
|       {
 | |
|         XMLSchemaElementTypeInfo parent =
 | |
|           (XMLSchemaElementTypeInfo) context.getFirst();
 | |
|         if (parent.nil) // Element Locally Valid (Element) 3.2.1
 | |
|           {
 | |
|             throw new ValidationException("Parent of " + qName +
 | |
|                                           " is declared xsi:nil", loc);
 | |
|           }
 | |
|         // TODO
 | |
|       }
 | |
|     context.addFirst(typeInfo);
 | |
|     // attributes
 | |
|     int len = atts.getLength();
 | |
|     Attributes2Impl atts2 = new Attributes2Impl();
 | |
|     int count = 0;
 | |
|     for (int i = 0; i < len; i++)
 | |
|       {
 | |
|         String attUri = atts.getURI(i);
 | |
|         String attLocalName = atts.getLocalName(i);
 | |
|         String attQName = atts.getQName(i);
 | |
|         String attValue = atts.getValue(i);
 | |
| 
 | |
|         if (XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(attUri))
 | |
|           {
 | |
|             continue; // ?
 | |
|           }
 | |
| 
 | |
|         QName attName = new QName(attUri, attLocalName);
 | |
|         AttributeDeclaration attDecl =
 | |
|           (AttributeDeclaration) schema.attributeDeclarations.get(attName);
 | |
|         boolean declared = (attDecl != null);
 | |
| 
 | |
|         String attType = (attDecl != null) ?
 | |
|           attDecl.datatype.toString() : "CDATA";
 | |
|         XMLSchemaAttributeTypeInfo attTypeInfo =
 | |
|           new XMLSchemaAttributeTypeInfo(schema, attDecl, true);
 | |
|         attributes.add(attTypeInfo);
 | |
| 
 | |
|         atts2.addAttribute(attUri, attLocalName, attQName, attType, attValue);
 | |
|         atts2.setDeclared(count, declared);
 | |
|         atts2.setSpecified(count, true);
 | |
|         count++;
 | |
|       }
 | |
|     // add defaulted attributes to atts2
 | |
|     // TODO
 | |
|     // atts2.setSpecified(count, false);
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.startElement(uri, localName, qName, atts2);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void endElement(String uri, String localName, String qName)
 | |
|     throws SAXException
 | |
|   {
 | |
|     // TODO check all required have been seen
 | |
|     context.removeFirst();
 | |
|     attributes.clear();
 | |
|     namespaceSupport.popContext();
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.endElement(uri, localName, qName);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void characters(char[] ch, int start, int length)
 | |
|     throws SAXException
 | |
|   {
 | |
|     XMLSchemaElementTypeInfo parent =
 | |
|       (XMLSchemaElementTypeInfo) context.getFirst();
 | |
|     if (parent.nil) // Element Locally Valid (Element) 3.2.1
 | |
|       {
 | |
|         throw new ValidationException(parent.decl.name.toString() +
 | |
|                                       " is declared xsi:nil",
 | |
|                                       loc);
 | |
|       }
 | |
|     // TODO
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.characters(ch, start, length);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void ignorableWhitespace(char[] ch, int start, int length)
 | |
|     throws SAXException
 | |
|   {
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.ignorableWhitespace(ch, start, length);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void processingInstruction(String target, String data)
 | |
|     throws SAXException
 | |
|   {
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.processingInstruction(target, data);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void skippedEntity(String name)
 | |
|     throws SAXException
 | |
|   {
 | |
|     if (contentHandler != null)
 | |
|       {
 | |
|         contentHandler.skippedEntity(name);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   Type resolveType(String value)
 | |
|     throws DatatypeException
 | |
|   {
 | |
|     QName name = QName.valueOf(value);
 | |
|     String prefix = name.getPrefix();
 | |
|     String localName = name.getLocalPart();
 | |
|     if (prefix != null && prefix.length() > 0)
 | |
|       {
 | |
|         String uri = namespaceSupport.getURI(prefix);
 | |
|         if (!XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri))
 | |
|           return null;
 | |
|       }
 | |
|     if ("anyType".equals(localName))
 | |
|       return Type.ANY_TYPE;
 | |
|     return (SimpleType) typeLibrary.createDatatype(localName);
 | |
|   }
 | |
| 
 | |
| }
 |