// so that we can find any invalid use of ID/IDREF types.
exp.exp.visit(this);
return;
}
DataOrValueExp texp = (DataOrValueExp)exp.exp;
if(texp.getType().getIdType()==Datatype.ID_TYPE_NULL) {
// if this type is not ID/IDREF type, then it's OK
return;
}
if(!(exp.nameClass instanceof SimpleNameClass)) {
reportCompError(
new Locator[]{reader.getDeclaredLocationOf(exp)},
CERR_ID_TYPE_WITH_NON_SIMPLE_ATTNAME,
new Object[]{
texp.getName().localName,
getSemanticsStr(texp.getType().getIdType())} );
return;
}
StringPair attName = new StringPair((SimpleNameClass)exp.nameClass);
if( elementName==null ) {
reportCompError(
new Locator[]{
reader.getDeclaredLocationOf(exp),
reader.getDeclaredLocationOf(curElm)},
CERR_ID_TYPE_WITH_NON_SIMPLE_ELEMENTNAME,
new Object[]{
texp.getName().localName,
getSemanticsStr(texp.getType().getIdType())} );
return;
}
// the enclosing attribute name is simple, and
// the enclosing element name is simple, too.
// this is the only place we can have ID/IDREF types.
// store that this attribute is used for ID/IDREF.
if(curAtts==null)
curAtts = new IDAttMap(curElm);
curAtts.idatts.put(attName,texp.getName());
}
public void onData( DataExp exp ) { checkIdType(exp); }
public void onValue( ValueExp exp ) { checkIdType(exp); }
private void checkIdType( DataOrValueExp exp ) {
if(exp.getType().getIdType()!=Datatype.ID_TYPE_NULL) {
// ID/IDREF type in all other locations are subject to
// a compatibility error.
reportCompError(
new Locator[]{reader.getDeclaredLocationOf(exp)},
CERR_MALPLACED_ID_TYPE,
new Object[]{
exp.getName().localName,
getSemanticsStr(exp.getType().getIdType())});
}
}
});
if(!grammar.isIDcompatible)
// if an compatibility error has been found, abort further check.
return;
/*
2nd pass
========
make sure that no other attributes are competing with id attributes.
*/
Iterator itr = elements.iterator();
final Vector vec = new Vector(); // IDAttMaps of the competing elements
while( itr.hasNext() ) {
final ElementExp eexp = (ElementExp)itr.next();
// list up all competing elements.
vec.clear();
Iterator jtr = name2value.entrySet().iterator();
while(jtr.hasNext()) {
Map.Entry e = (Map.Entry)jtr.next();
if( eexp.getNameClass().accepts((StringPair)e.getKey()) )
vec.add( e.getValue()/*IDAttMap*/ );
}
if(vec.size()==0)
continue; // this element does not comete with anything.
// no need to check
// make sure that no attributes are actually competing.
eexp.contentModel.visit(remover).visit( new ExpressionWalker() {
public void onElement( ElementExp exp ) {
return; // do not recurse child elements.
}
public void onAttribute( AttributeExp exp ) {
if(exp.exp instanceof DataOrValueExp) {
DataOrValueExp texp = (DataOrValueExp)exp.exp;
if(texp.getType().getIdType()!=Datatype.ID_TYPE_NULL) {
// if the schema is OK with the 1st pass check
// and if this element contains the ID type, then
// this element must be simple-named.
// so at most one IDAttMap can match it.
_assert(vec.size()==1);
// by the same assumption, the attribute name must be
// simple.
SimpleNameClass attName = (SimpleNameClass)exp.nameClass;
IDAttMap iam = (IDAttMap)vec.get(0);
if(!texp.getName().equals(iam.idatts.get(new StringPair(attName))))
reportCompError(
new Locator[]{
reader.getDeclaredLocationOf(exp),
reader.getDeclaredLocationOf(iam.sampleDecl)},
CERR_COMPETING,
new Object[]{
texp.getName().localName,
getSemanticsStr(texp.getType().getIdType())
}
);
return;
}