private void DtdValidateAttributes (DTDAttListDeclaration decl, bool validate)
{
while (reader.MoveToNextAttribute ()) {
string attrName = reader.Name;
AttributeSlot slot = GetAttributeSlot ();
slot.Name = reader.Name;
slot.LocalName = reader.LocalName;
slot.Prefix = reader.Prefix;
XmlReader targetReader = reader;
string attrValue = String.Empty;
// For attribute node, it always resolves
// entity references on attributes.
while (attributeValueEntityStack.Count >= 0) {
if (!targetReader.ReadAttributeValue ()) {
if (attributeValueEntityStack.Count > 0) {
targetReader = attributeValueEntityStack.Pop () as XmlReader;
continue;
} else
break;
}
switch (targetReader.NodeType) {
case XmlNodeType.EntityReference:
DTDEntityDeclaration edecl = DTD.EntityDecls [targetReader.Name];
if (edecl == null) {
HandleError (String.Format ("Referenced entity {0} is not declared.", targetReader.Name),
XmlSeverityType.Error);
} else {
XmlTextReader etr = new XmlTextReader (edecl.EntityValue, XmlNodeType.Attribute, ParserContext);
attributeValueEntityStack.Push (targetReader);
targetReader = etr;
continue;
}
break;
case XmlNodeType.EndEntity:
break;
default:
attrValue += targetReader.Value;
break;
}
}
reader.MoveToElement ();
reader.MoveToAttribute (attrName);
slot.Value = FilterNormalization (attrName, attrValue);
if (!validate)
continue;
// Validation
DTDAttributeDefinition def = decl [reader.Name];
if (def == null) {
HandleError (String.Format ("Attribute {0} is not declared.", reader.Name),
XmlSeverityType.Error);
continue;
}
// check enumeration constraint
if (def.EnumeratedAttributeDeclaration.Count > 0)
if (!def.EnumeratedAttributeDeclaration.Contains (slot.Value))
HandleError (String.Format ("Attribute enumeration constraint error in attribute {0}, value {1}.",
reader.Name, attrValue), XmlSeverityType.Error);
if (def.EnumeratedNotations.Count > 0)
if (!def.EnumeratedNotations.Contains (
slot.Value))
HandleError (String.Format ("Attribute notation enumeration constraint error in attribute {0}, value {1}.",
reader.Name, attrValue), XmlSeverityType.Error);
// check type constraint
string normalized = null;
if (def.Datatype != null)
normalized = FilterNormalization (def.Name, attrValue);
else
normalized = attrValue;
DTDEntityDeclaration ent;
// Common process to get list value
string [] list = null;
switch (def.Datatype.TokenizedType) {
case XmlTokenizedType.IDREFS:
case XmlTokenizedType.ENTITIES:
case XmlTokenizedType.NMTOKENS:
try {
list = def.Datatype.ParseValue (normalized, NameTable, null) as string [];
} catch (Exception) {
HandleError ("Attribute value is invalid against its data type.", XmlSeverityType.Error);
list = new string [0];
}
break;
default:
try {
def.Datatype.ParseValue (normalized, NameTable, null);
} catch (Exception ex) {
HandleError (String.Format ("Attribute value is invalid against its data type '{0}'. {1}", def.Datatype, ex.Message), XmlSeverityType.Error);
}
break;
}
switch (def.Datatype.TokenizedType) {
case XmlTokenizedType.ID:
if (this.idList.Contains (normalized)) {
HandleError (String.Format ("Node with ID {0} was already appeared.", attrValue),
XmlSeverityType.Error);
} else {
if (missingIDReferences.Contains (normalized))
missingIDReferences.Remove (normalized);
idList.Add (normalized);
}
break;
case XmlTokenizedType.IDREF:
if (!idList.Contains (normalized))
missingIDReferences.Add (normalized);
break;
case XmlTokenizedType.IDREFS:
for (int i = 0; i < list.Length; i++) {
string idref = list [i];
if (!idList.Contains (idref))
missingIDReferences.Add (idref);
}
break;
case XmlTokenizedType.ENTITY:
ent = dtd.EntityDecls [normalized];
if (ent == null)
HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
else if (ent.NotationName == null)
HandleError ("The entity specified by entity type value must be an unparsed entity. The entity definition has no NDATA in attribute: " + reader.Name + ".", XmlSeverityType.Error);
break;
case XmlTokenizedType.ENTITIES:
for (int i = 0; i < list.Length; i++) {
string entref = list [i];
ent = dtd.EntityDecls [FilterNormalization (reader.Name, entref)];
if (ent == null)
HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
else if (ent.NotationName == null)
HandleError ("The entity specified by ENTITIES type value must be an unparsed entity. The entity definition has no NDATA in attribute: " + reader.Name + ".", XmlSeverityType.Error);
}
break;
// case XmlTokenizedType.NMTOKEN: nothing to do
// case XmlTokenizedType.NMTOKENS: nothing to do
}
if (isStandalone && !def.IsInternalSubset &&
attrValue != normalized)
HandleError ("In standalone document, attribute value characters must not be checked against external definition.", XmlSeverityType.Error);
if (def.OccurenceType ==
DTDAttributeOccurenceType.Fixed &&
attrValue != def.DefaultValue)
HandleError (String.Format ("Fixed attribute {0} in element {1} has invalid value {2}.",
def.Name, decl.Name, attrValue),
XmlSeverityType.Error);
}
if (validate)
VerifyDeclaredAttributes (decl);
MoveToElement ();
}