* fcl-xml, moved check for required attribute presence to ValidateCurrentNode

* improved wording of some validation errors
- removed ExpectName function

git-svn-id: trunk@20435 -
This commit is contained in:
sergei 2012-02-27 04:03:09 +00:00
parent 4a128cc006
commit f44734d1bc
2 changed files with 31 additions and 27 deletions

View File

@ -98,6 +98,7 @@ type
private private
FAttrDefs: TFPList; FAttrDefs: TFPList;
FNeedsDefaultPass: Boolean; FNeedsDefaultPass: Boolean;
FHasRequiredAtts: Boolean;
function GetAttrDefCount: Integer; function GetAttrDefCount: Integer;
function AttrDefByIndex(index: Integer): TAttributeDef; function AttrDefByIndex(index: Integer): TAttributeDef;
public public
@ -111,6 +112,7 @@ type
property AttrDefCount: Integer read GetAttrDefCount; property AttrDefCount: Integer read GetAttrDefCount;
property AttrDefs[index: Integer]: TAttributeDef read AttrDefByIndex; property AttrDefs[index: Integer]: TAttributeDef read AttrDefByIndex;
property NeedsDefaultPass: Boolean read FNeedsDefaultPass; property NeedsDefaultPass: Boolean read FNeedsDefaultPass;
property HasRequiredAtts: Boolean read FHasRequiredAtts;
end; end;
TEntityDecl = class(TDTDObject) TEntityDecl = class(TDTDObject)
@ -378,6 +380,8 @@ begin
aDef.FIndex := FAttrDefs.Add(aDef); aDef.FIndex := FAttrDefs.Add(aDef);
if aDef.Default in [adRequired, adDefault, adFixed] then if aDef.Default in [adRequired, adDefault, adFixed] then
FNeedsDefaultPass := True; FNeedsDefaultPass := True;
if aDef.Default = adRequired then
FHasRequiredAtts := True;
end; end;
{ TAttributeDef } { TAttributeDef }

View File

@ -328,7 +328,6 @@ type
procedure AddForwardRef(Buf: PWideChar; Length: Integer); procedure AddForwardRef(Buf: PWideChar; Length: Integer);
procedure ClearForwardRefs; procedure ClearForwardRefs;
procedure ValidateIdRefs; procedure ValidateIdRefs;
procedure StandaloneError(LineOffs: Integer = 0);
procedure CallErrorHandler(E: EXMLReadError); procedure CallErrorHandler(E: EXMLReadError);
function FindOrCreateElDef: TElementDecl; function FindOrCreateElDef: TElementDecl;
function SkipUntilSeq(const Delim: TSetOfChar; c1: WideChar): Boolean; function SkipUntilSeq(const Delim: TSetOfChar; c1: WideChar): Boolean;
@ -372,7 +371,6 @@ type
procedure RaiseNameNotFound; procedure RaiseNameNotFound;
function CheckName(aFlags: TCheckNameFlags = []): Boolean; function CheckName(aFlags: TCheckNameFlags = []): Boolean;
procedure CheckNCName; procedure CheckNCName;
function ExpectName: XMLString; // [5]
function ParseLiteral(var ToFill: TWideCharBuf; aType: TLiteralType; function ParseLiteral(var ToFill: TWideCharBuf; aType: TLiteralType;
Required: Boolean): Boolean; Required: Boolean): Boolean;
procedure ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean); // [10] procedure ExpectAttValue(attrData: PNodeData; NonCDATA: Boolean); // [10]
@ -1451,12 +1449,6 @@ begin
FatalError('Name starts with invalid character'); FatalError('Name starts with invalid character');
end; end;
function TXMLTextReader.ExpectName: XMLString;
begin
CheckName;
SetString(Result, FName.Buffer, FName.Length);
end;
function TXMLTextReader.ResolvePredefined: Boolean; function TXMLTextReader.ResolvePredefined: Boolean;
var var
wc: WideChar; wc: WideChar;
@ -2028,7 +2020,8 @@ begin
FDTDProcessed := True; // assume success FDTDProcessed := True; // assume success
FState := rsDTD; FState := rsDTD;
FDocType.FName := ExpectName; CheckName;
SetString(FDocType.FName, FName.Buffer, FName.Length);
SkipS(True); SkipS(True);
ParseExternalID(FDocType.FSystemID, FDocType.FPublicID, False); ParseExternalID(FDocType.FSystemID, FDocType.FPublicID, False);
SkipS; SkipS;
@ -2092,11 +2085,6 @@ begin
DoError(S, 'Parameter entities must be properly nested'); DoError(S, 'Parameter entities must be properly nested');
end; end;
procedure TXMLTextReader.StandaloneError(LineOffs: Integer);
begin
ValidationError('Standalone constriant violation', [], LineOffs);
end;
function TXMLTextReader.ParseQuantity: TCPQuant; function TXMLTextReader.ParseQuantity: TCPQuant;
begin begin
case FSource.FBuf^ of case FSource.FBuf^ of
@ -2249,8 +2237,9 @@ var
NameStr, SysID, PubID: XMLString; NameStr, SysID, PubID: XMLString;
begin begin
ExpectWhitespace; ExpectWhitespace;
NameStr := ExpectName; CheckName;
CheckNCName; CheckNCName;
SetString(NameStr, FName.Buffer, FName.Length);
ExpectWhitespace; ExpectWhitespace;
if not ParseExternalID(SysID, PubID, True) then if not ParseExternalID(SysID, PubID, True) then
FatalError('Expected external or public ID'); FatalError('Expected external or public ID');
@ -2457,8 +2446,9 @@ begin
if FSource.Matches('NDATA') then if FSource.Matches('NDATA') then
begin begin
ExpectWhitespace; ExpectWhitespace;
StoreLocation(FTokenStart); StoreLocation(FTokenStart); { needed for AddForwardRef }
Entity.FNotationName := ExpectName; CheckName;
SetString(Entity.FNotationName, FName.Buffer, FName.Length);
if FValidate then if FValidate then
AddForwardRef(FName.Buffer, FName.Length); AddForwardRef(FName.Buffer, FName.Length);
// SAX: DTDHandler.UnparsedEntityDecl(...); // SAX: DTDHandler.UnparsedEntityDecl(...);
@ -2676,6 +2666,9 @@ begin
PushVC(ElDef); PushVC(ElDef);
if ElDef = nil then
Exit;
{ Validate attributes } { Validate attributes }
for i := 1 to FAttrCount do for i := 1 to FAttrCount do
begin begin
@ -2687,11 +2680,10 @@ begin
else if ((AttDef.DataType <> dtCdata) or (AttDef.Default = adFixed)) then else if ((AttDef.DataType <> dtCdata) or (AttDef.Default = adFixed)) then
begin begin
if FStandalone and AttDef.ExternallyDeclared then if FStandalone and AttDef.ExternallyDeclared then
{ TODO: perhaps should use different and more descriptive messages }
if attr^.FDenormalized then if attr^.FDenormalized then
DoErrorPos(esError, 'Standalone constraint violation', attr^.FLoc2) DoErrorPos(esError, 'In a standalone document, externally defined attribute cannot cause value normalization', attr^.FLoc2)
else if i > FSpecifiedAttrs then else if i > FSpecifiedAttrs then
DoError(esError, 'Standalone constraint violation'); DoError(esError, 'In a standalone document, attribute cannot have a default value defined externally');
// TODO: what about normalization of AttDef.Value? (Currently it IS normalized) // TODO: what about normalization of AttDef.Value? (Currently it IS normalized)
if (AttDef.Default = adFixed) and (AttDef.Data^.FValueStr <> attr^.FValueStr) then if (AttDef.Default = adFixed) and (AttDef.Data^.FValueStr <> attr^.FValueStr) then
@ -2701,6 +2693,18 @@ begin
ValidateAttrValue(AttDef, attr); ValidateAttrValue(AttDef, attr);
end; end;
end; end;
{ Check presence of #REQUIRED attributes }
if ElDef.HasRequiredAtts then
for i := 0 to ElDef.AttrDefCount-1 do
begin
if FAttrDefIndex[i] = FAttrTag then
Continue;
AttDef := ElDef.AttrDefs[i];
if AttDef.Default = adRequired then
ValidationError('Required attribute ''%s'' of element ''%s'' is missing',
[AttDef.Data^.FQName^.Key, FCurrNode^.FQName^.Key], 0)
end;
end; end;
ntEndElement: ntEndElement:
@ -2719,7 +2723,7 @@ begin
else else
begin begin
if FValidators[FValidatorNesting].FSaViolation then if FValidators[FValidatorNesting].FSaViolation then
StandaloneError(-1); ValidationError('Standalone constraint violation',[]);
FCurrNode^.FNodeType := ntWhitespace; FCurrNode^.FNodeType := ntWhitespace;
end; end;
ctEmpty: ctEmpty:
@ -3428,10 +3432,9 @@ var
begin begin
for I := 0 to ElDef.AttrDefCount-1 do for I := 0 to ElDef.AttrDefCount-1 do
begin begin
AttDef := ElDef.AttrDefs[I]; if FAttrDefIndex[I] <> FAttrTag then // this one wasn't specified
if FAttrDefIndex[AttDef.Index] <> FAttrTag then // this one wasn't specified
begin begin
AttDef := ElDef.AttrDefs[I];
case AttDef.Default of case AttDef.Default of
adDefault, adFixed: begin adDefault, adFixed: begin
attrData := AllocAttributeData; attrData := AllocAttributeData;
@ -3456,9 +3459,6 @@ begin
end; end;
end; end;
end; end;
adRequired:
ValidationError('Required attribute ''%s'' of element ''%s'' is missing',
[AttDef.Data^.FQName^.Key, FNodeStack[FNesting].FQName^.Key], 0)
end; end;
end; end;
end; end;