/* * @(#)$Id: DblAttrConstraintChecker.java,v 1.9 2001/10/18 23:52:13 Bear Exp $ * * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved. * * This software is the proprietary information of Sun Microsystems, Inc. * Use is subject to license terms. * */ package com.sun.msv.reader.relax.core.checker; import com.sun.msv.grammar.*; import com.sun.msv.grammar.relax.*; import com.sun.msv.reader.relax.core.RELAXCoreReader; import com.sun.msv.util.StringPair; import java.util.Map; import org.xml.sax.Locator; /** * makes sure that no two AttributeExps have the same attribute name as their target. * * @author <a href="mailto:kohsuke.kawaguchi@eng.sun.com">Kohsuke KAWAGUCHI</a> */ public class DblAttrConstraintChecker implements RELAXExpressionVisitorVoid { /** map of StringPairs to ReferenceExp(TagClause/AttPoolClause). * * keys are names of visited AttributeExps, and its value is * Clause object in which AttributeExp is declared. */ private final Map atts = new java.util.HashMap(); /** current clause. */ private ReferenceExp current; public void check( TagClause clause, RELAXCoreReader reader ) { atts.clear(); current = clause; try { clause.visit(this); } catch( Eureka e ) { reader.reportError( new Locator[]{reader.getDeclaredLocationOf(current), reader.getDeclaredLocationOf((ReferenceExp)atts.get(e.name)) }, reader.ERR_MULTIPLE_ATTRIBUTE_CONSTRAINT, new Object[]{ e.name.localName } ); } } private static final class Eureka extends RuntimeException { final StringPair name; Eureka( StringPair an ) { name=an; } }; public void onAttribute( AttributeExp exp ) { if( exp.nameClass instanceof SimpleNameClass ) { // this check is only appliable for those who constrains // one particular attribute. SimpleNameClass nc = (SimpleNameClass)exp.nameClass; StringPair p = new StringPair( nc.namespaceURI, nc.localName ); if( atts.containsKey(p) ) throw new Eureka(p); // eureka! : find two AttributeExps that share the same name. atts.put(p,current); } } public void onAttPool( AttPoolClause exp ) { ReferenceExp old = current; current = exp; exp.exp.visit(this); current = old; } public void onSequence( SequenceExp exp ) { exp.exp1.visit(this);exp.exp2.visit(this); } public void onChoice( ChoiceExp exp ) { exp.exp1.visit(this);exp.exp2.visit(this); } public void onEpsilon() {;} public void onRef( ReferenceExp exp ) {;} public void onOther( OtherExp exp ) { exp.exp.visit(this); } public void onElement( ElementExp exp ) {;} public void onOneOrMore( OneOrMoreExp exp ) { exp.exp.visit(this); } public void onMixed( MixedExp exp ) { exp.exp.visit(this); } public void onNullSet() {;} public void onAnyString() {;} public void onData( DataExp exp ) {;} public void onValue( ValueExp exp ) {;} public void onTag( TagClause exp ) { exp.exp.visit(this); } public void onElementRules( ElementRules exp ) { exp.exp.visit(this); } public void onHedgeRules( HedgeRules exp ) { exp.exp.visit(this); } // those methods should also never be called in case of RELAX. public void onConcur( ConcurExp exp ) {;} public void onInterleave( InterleaveExp exp ) {;} public void onList( ListExp exp ) {;} }