Package com.sun.xml.parser

Source Code of com.sun.xml.parser.ValidatingParser

/*
* $Id: ValidatingParser.java,v 1.4 1999/04/11 16:07:50 db Exp $
*
* Copyright (c) 1998-1999 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information").  You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*/


package com.sun.xml.parser;

import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Vector;

import org.xml.sax.HandlerBase;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import com.sun.xml.util.XmlNames;


/**
* This parser tests XML documents against the validity constraints
* specified in the XML 1.0 specification as it parses them.  It
* reports violations of those constraints using the standard SAX API.
*
* <P><em>This parser should be configured to use an <code>ErrorHandler</code>
* that reject documents with validity errors, otherwise they will be accepted
* despite errors.</em>  The default error handling, as specified by SAX,
* ignores all validity errors.  The simplest way to have validity errors
* have a useful effect is to pass a boolean <em>true</em> value to
* the parser's constructor.
*
* <P> Note that most validity checks are performed during parsing by
* the base class, for efficiency.  They're disabled by default in
* that class, and enabled by the constructor in this class.
*
* @author David Brownell
* @version $Revision: 1.4 $
*/
public class ValidatingParser extends Parser
{
    private SimpleHashtable  ids = new SimpleHashtable ();

    /** Constructs a SAX parser object. */
    public ValidatingParser ()
    {
  setIsValidating (true);
    }

    /**
     * Constructs a SAX parser object, optionally assigning the error
     * handler to report exceptions on recoverable errors (which include
     * all validity errors) as well as fatal errors.
     *
     * @param rejectValidityErrors When true, the parser will use an
     *  error handler which throws exceptions on recoverable errors.
     *  Otherwise it uses the default SAX error handler, which ignores
     *  such errors.
     */
    public ValidatingParser (boolean rejectValidityErrors)
    {
  this ();
  if (rejectValidityErrors)
      setErrorHandler (new HandlerBase () {
    public void error (SAXParseException x)
        throws SAXException
        { throw x; }
    });
    }

    // REMINDER:  validation errors are not fatal, so code flow
    // must continue correctly if error() returns.


    // package private ... overrides base class method
    void afterRoot () throws SAXException
    {
  // Make sure all IDREFs match declared ID attributes.  We scan
  // after the document element is parsed, since XML allows forward
  // references, and only now can we know if they're all resolved.

  for (Enumeration e = ids.keys ();
    e.hasMoreElements ();
    ) {
      String id = (String) e.nextElement ();
      Boolean value = (Boolean) ids.get (id);
      if (Boolean.FALSE == value)
    error ("V-024", new Object [] { id });
  }
    }

    // package private ... overrides base class method
    void afterDocument ()
    {
  ids.clear ();
    }

    // package private ... overrides base class method
    void validateAttributeSyntax (AttributeDecl attr, String value)
    throws SAXException
    {
  // ID, IDREF(S) ... values are Names
  if (AttributeDecl.ID == attr.type) {
      if (!XmlNames.isName (value))
    error ("V-025", new Object [] { value });

      Boolean    b = (Boolean) ids.getNonInterned (value);
      if (b == null || b.equals (Boolean.FALSE))
    ids.put (value.intern (), Boolean.TRUE);
      else
    error ("V-026", new Object [] { value });

  } else if (AttributeDecl.IDREF == attr.type) {
      if (!XmlNames.isName (value))
    error ("V-027", new Object [] { value });

      Boolean    b = (Boolean) ids.getNonInterned (value);
      if (b == null)
    ids.put (value.intern (), Boolean.FALSE);

  } else if (AttributeDecl.IDREFS == attr.type) {
      StringTokenizer  tokenizer = new StringTokenizer (value);
      Boolean    b;
      boolean    sawValue = false;

      while (tokenizer.hasMoreTokens ()) {
    value = tokenizer.nextToken ();
    if (!XmlNames.isName (value))
        error ("V-027", new Object [] { value });
    b = (Boolean) ids.getNonInterned (value);
    if (b == null)
        ids.put (value.intern (), Boolean.FALSE);
    sawValue = true;
      }
      if (!sawValue)
    error ("V-039", null);


  // NMTOKEN(S) ... values are Nmtoken(s)
  } else if (AttributeDecl.NMTOKEN == attr.type) {
      if (!XmlNames.isNmtoken (value))
    error ("V-028", new Object [] { value });

  } else if (AttributeDecl.NMTOKENS == attr.type) {
      StringTokenizer  tokenizer = new StringTokenizer (value);
      boolean    sawValue = false;

      while (tokenizer.hasMoreTokens ()) {
    value = tokenizer.nextToken ();
    if (!XmlNames.isNmtoken (value))
        error ("V-028", new Object [] { value });
    sawValue = true;
      }
      if (!sawValue)
    error ("V-032", null);

  // ENUMERATION ... values match one of the tokens
  } else if (AttributeDecl.ENUMERATION == attr.type) {
      for (int i = 0; i < attr.values.length; i++)
    if (value.equals (attr.values [i]))
        return;
      error ("V-029", new Object [] { value });

  // NOTATION values match a notation name
  } else if (AttributeDecl.NOTATION == attr.type) {
      //
      // XXX XML 1.0 spec should probably list references to
      // externally defined notations in standalone docs as
      // validity errors.  Ditto externally defined unparsed
      // entities; neither should show up in attributes, else
      // one needs to read the external declarations in order
      // to make sense of the document (exactly what tagging
      // a doc as "standalone" intends you won't need to do).
      //
      for (int i = 0; i < attr.values.length; i++)
    if (value.equals (attr.values [i]))
        return;
      error ("V-030", new Object [] { value });

  // ENTITY(IES) values match an unparsed entity(ies)
  } else if (AttributeDecl.ENTITY == attr.type) {
      // see note above re standalone
      if (!isUnparsedEntity (value))
    error ("V-031", new Object [] { value });

  } else if (AttributeDecl.ENTITIES == attr.type) {
      StringTokenizer  tokenizer = new StringTokenizer (value);
      boolean    sawValue = false;

      while (tokenizer.hasMoreTokens ()) {
    value = tokenizer.nextToken ();
    // see note above re standalone
    if (!isUnparsedEntity (value))
        error ("V-031", new Object [] { value });
    sawValue = true;
      }
      if (!sawValue)
    error ("V-040", null);

  } else if (AttributeDecl.CDATA != attr.type)
      throw new InternalError (attr.type);
    }


    // package private ... overrides base class method
    ContentModel newContentModel (String tag)
    {
  return new ContentModel (tag);
    }

    // package private ... overrides base class method
    ContentModel newContentModel (char type, ContentModel next)
    {
  return new ContentModel (type, next);
    }

    // package private ... overrides base class method
    ElementValidator newValidator (ElementDecl element)
    {
  if (element.validator != null)
      return element.validator;
  if (element.model != null)
      return new ChildrenValidator (element);

  //
  // most types of content model have very simple validation
  // algorithms; only "children" needs mutable state.
  //
  if (element.contentType == null || strANY == element.contentType)
      element.validator = ElementValidator.ANY;
  else if (strEMPTY == element.contentType)
      element.validator = EMPTY;
  else // (element.contentType.charAt (1) == '#')
      element.validator = new MixedValidator (element);
  return element.validator;
    }

    private final EmptyValidator EMPTY = new EmptyValidator ();

    // "EMPTY" model allows nothing
    class EmptyValidator extends ElementValidator
    {
  public void consume (String token) throws SAXException
      { error ("V-033", null); }

  public void text () throws SAXException
      { error ("V-033", null); }
    }

    // Mixed content models allow text with selected elements
    class MixedValidator extends ElementValidator
    {
  private ElementDecl    element;

  MixedValidator (ElementDecl element)
      { this.element = element; }

  public void consume (String type) throws SAXException
  {
      String model = element.contentType;

      for (int index = 8;     // skip "(#PCDATA|"
        (index = model.indexOf (type, index + 1)) >= 9;
        ) {
    char  c;

    // allow this type name to suffix -- "|xxTYPE"
    if (model.charAt (index -1) != '|')
        continue;
    c = model.charAt (index + type.length ());
    if (c == '|' || c == ')')
        return;
    // allow this type name to prefix -- "|TYPExx"
      }
      error ("V-034", new Object [] { element.name, type, model });
  }
    }

    class ChildrenValidator extends ElementValidator
    {
  private ContentModelState  state;
  private String      name;

  ChildrenValidator (ElementDecl element)
  {
      state = new ContentModelState (element.model);
      name = element.name;
  }

  public void consume (String token) throws SAXException
  {
      if (state == null)
    error ("V-035", new Object [] { name, token });
      else try {
    state = state.advance (token);
      } catch (EndOfInputException e) {
    error ("V-036", new Object [] { name, token });
      }
  }

  public void text () throws SAXException
  {
      error ("V-037", new Object [] { name });
  }

  public void done () throws SAXException
  {
      if (state != null && !state.terminate ())
    error ("V-038", new Object [] { name });
  }
    }

    private boolean isUnparsedEntity (String name)
    {
  Object e = entities.getNonInterned (name);
  if (e == null || !(e instanceof ExternalEntity))
      return false;
  return ((ExternalEntity)e).notation != null;
    }
}
TOP

Related Classes of com.sun.xml.parser.ValidatingParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.