mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-29 11:20:15 +02:00
* xmlread.pp: split handling of node and validation stacks. Validation stack is now maintained only in validation mode.
git-svn-id: trunk@16973 -
This commit is contained in:
parent
6c4c151815
commit
e46c51e1bf
@ -249,6 +249,8 @@ type
|
||||
FElementDef: TElementDecl;
|
||||
FCurCP: TContentParticle;
|
||||
FFailed: Boolean;
|
||||
FSaViolation: Boolean;
|
||||
FContentType: TElementContentType; // =ctAny when FElementDef is nil
|
||||
function IsElementAllowed(Def: TElementDecl): Boolean;
|
||||
function Incomplete: Boolean;
|
||||
end;
|
||||
@ -284,8 +286,6 @@ type
|
||||
FDocType: TDTDModel;
|
||||
FPEMap: THashTable;
|
||||
FForwardRefs: TFPList;
|
||||
FCurrContentType: TElementContentType;
|
||||
FSaViolation: Boolean;
|
||||
FDTDStartPos: PWideChar;
|
||||
FIntSubset: TWideCharBuf;
|
||||
FAttrTag: Cardinal;
|
||||
@ -347,6 +347,7 @@ type
|
||||
FPrefixedAttrs: Integer;
|
||||
FSpecifiedAttrs: Integer;
|
||||
FNodeStack: TNodeDataDynArray;
|
||||
FValidatorNesting: Integer;
|
||||
FValidators: TValidatorDynArray;
|
||||
FAttrChunks: TFPList;
|
||||
FFreeAttrChunk: PNodeData;
|
||||
@ -413,7 +414,6 @@ type
|
||||
|
||||
procedure PushVC(aElDef: TElementDecl);
|
||||
procedure PopVC;
|
||||
procedure UpdateConstraints;
|
||||
procedure ValidateDTD;
|
||||
procedure ValidateCurrentNode;
|
||||
procedure ValidationError(const Msg: string; const args: array of const; LineOffs: Integer = -1);
|
||||
@ -1316,6 +1316,7 @@ begin
|
||||
FNameTable := doc.Names;
|
||||
FState := rsProlog;
|
||||
FNesting := 0;
|
||||
FValidatorNesting := 0;
|
||||
FCurrNode := @FNodeStack[0];
|
||||
FFragmentMode := False;
|
||||
NSPrepare;
|
||||
@ -1344,6 +1345,7 @@ begin
|
||||
FNameTable := doc.Names;
|
||||
FState := rsRoot;
|
||||
FNesting := 0;
|
||||
FValidatorNesting := 0;
|
||||
FCurrNode := @FNodeStack[0];
|
||||
FFragmentMode := True;
|
||||
FXML11 := doc.InheritsFrom(TXMLDocument) and (TXMLDocument(doc).XMLVersion = '1.1');
|
||||
@ -2673,7 +2675,6 @@ begin
|
||||
case FCurrNode^.FNodeType of
|
||||
ntElement:
|
||||
begin
|
||||
{ TODO: pushing *validation* context must be moved here }
|
||||
if (FNesting = 1) and (not FFragmentMode) then
|
||||
begin
|
||||
if Assigned(FDocType) then
|
||||
@ -2688,9 +2689,11 @@ begin
|
||||
if (ElDef = nil) or (ElDef.ContentType = ctUndeclared) then
|
||||
DoErrorPos(esError, 'Using undeclared element ''%s''',[FCurrNode^.FQName^.Key], FCurrNode^.FLoc);
|
||||
|
||||
if not FValidators[FNesting-1].IsElementAllowed(ElDef) then
|
||||
if not FValidators[FValidatorNesting].IsElementAllowed(ElDef) then
|
||||
DoErrorPos(esError, 'Element ''%s'' is not allowed in this context',[FCurrNode^.FQName^.Key], FCurrNode^.FLoc);
|
||||
|
||||
PushVC(ElDef);
|
||||
|
||||
{ Validate attributes }
|
||||
for i := 1 to FAttrCount do
|
||||
begin
|
||||
@ -2720,32 +2723,37 @@ begin
|
||||
|
||||
ntEndElement:
|
||||
begin
|
||||
if FValidators[FNesting].Incomplete then
|
||||
if FValidators[FValidatorNesting].Incomplete then
|
||||
ValidationError('Element ''%s'' is missing required sub-elements', [FCurrNode^.FQName^.Key], -1);
|
||||
if FValidatorNesting > 0 then
|
||||
Dec(FValidatorNesting);
|
||||
end;
|
||||
|
||||
ntText, ntWhitespace:
|
||||
case FCurrContentType of
|
||||
ntText, ntSignificantWhitespace:
|
||||
case FValidators[FValidatorNesting].FContentType of
|
||||
ctChildren:
|
||||
if FCurrNode^.FNodeType = ntText then
|
||||
ValidationError('Character data is not allowed in element-only content',[])
|
||||
else
|
||||
if FSaViolation then
|
||||
begin
|
||||
if FValidators[FValidatorNesting].FSaViolation then
|
||||
StandaloneError(-1);
|
||||
FCurrNode^.FNodeType := ntWhitespace;
|
||||
end;
|
||||
ctEmpty:
|
||||
ValidationError('Character data is not allowed in EMPTY elements', []);
|
||||
end;
|
||||
|
||||
ntCDATA:
|
||||
if FCurrContentType = ctChildren then
|
||||
if FValidators[FValidatorNesting].FContentType = ctChildren then
|
||||
ValidationError('CDATA sections are not allowed in element-only content',[]);
|
||||
|
||||
ntProcessingInstruction:
|
||||
if FCurrContentType = ctEmpty then
|
||||
if FValidators[FValidatorNesting].FContentType = ctEmpty then
|
||||
ValidationError('Processing instructions are not allowed within EMPTY elements', []);
|
||||
|
||||
ntComment:
|
||||
if FCurrContentType = ctEmpty then
|
||||
if FValidators[FValidatorNesting].FContentType = ctEmpty then
|
||||
ValidationError('Comments are not allowed within EMPTY elements', []);
|
||||
|
||||
ntDocumentType:
|
||||
@ -2765,12 +2773,12 @@ end;
|
||||
|
||||
procedure TXMLReader.HandleEntityEnd;
|
||||
begin
|
||||
FValidators[FNesting-1] := FValidators[FNesting];
|
||||
ContextPop(True);
|
||||
PopVC;
|
||||
if FNesting > 0 then Dec(FNesting);
|
||||
FCurrNode := @FNodeStack[FNesting+1];
|
||||
FCurrNode^.FNodeType := ntEndEntity;
|
||||
// TODO: other properties of FCurrNode
|
||||
FNext := xtText;
|
||||
end;
|
||||
|
||||
procedure TXMLReader.ResolveEntity;
|
||||
@ -2787,7 +2795,8 @@ procedure TXMLReader.DoStartEntity;
|
||||
var
|
||||
src: TXMLCharSource;
|
||||
begin
|
||||
PushVC(nil);
|
||||
Inc(FNesting);
|
||||
FCurrNode := AllocNodeData(FNesting);
|
||||
if Assigned(FCurrEntity) then
|
||||
ContextPush(FCurrEntity)
|
||||
else
|
||||
@ -2797,10 +2806,6 @@ begin
|
||||
src.Kind := skManualPop;
|
||||
Initialize(src);
|
||||
end;
|
||||
|
||||
{ Compensate for an extra entry in node stack }
|
||||
FValidators[FNesting] := FValidators[FNesting-1];
|
||||
UpdateConstraints;
|
||||
FNext := xtText;
|
||||
end;
|
||||
|
||||
@ -2873,7 +2878,7 @@ const
|
||||
);
|
||||
|
||||
textNodeTypes: array[Boolean] of TXMLNodeType = (
|
||||
ntWhitespace,
|
||||
ntSignificantWhitespace,
|
||||
ntText
|
||||
);
|
||||
|
||||
@ -2892,9 +2897,9 @@ begin
|
||||
ntText:
|
||||
cursor.InternalAppend(doc.CreateTextNodeBuf(FValue.Buffer, FValue.Length, False));
|
||||
|
||||
ntWhitespace:
|
||||
ntWhitespace, ntSignificantWhitespace:
|
||||
if FPreserveWhitespace then
|
||||
cursor.InternalAppend(doc.CreateTextNodeBuf(FValue.Buffer, FValue.Length, FCurrContentType = ctChildren))
|
||||
cursor.InternalAppend(doc.CreateTextNodeBuf(FValue.Buffer, FValue.Length, FCurrNode^.FNodeType = ntWhitespace))
|
||||
else
|
||||
Continue;
|
||||
|
||||
@ -3062,7 +3067,7 @@ begin
|
||||
if FState <> rsRoot then
|
||||
FatalError('Illegal at document level');
|
||||
|
||||
if FCurrContentType = ctEmpty then
|
||||
if FValidators[FValidatorNesting].FContentType = ctEmpty then
|
||||
ValidationError('References are illegal in EMPTY elements', []);
|
||||
|
||||
if ParseRef(FValue) or ResolvePredefined then
|
||||
@ -3157,8 +3162,9 @@ begin
|
||||
FAttrCount := 0;
|
||||
FPrefixedAttrs := 0;
|
||||
FSpecifiedAttrs := 0;
|
||||
PushVC(ElDef); // this increases FNesting
|
||||
|
||||
Inc(FNesting);
|
||||
FCurrNode := AllocNodeData(FNesting);
|
||||
FCurrNode^.FQName := ElName;
|
||||
FCurrNode^.FNodeType := ntElement;
|
||||
FCurrNode^.FColonPos := FColonPos;
|
||||
@ -3592,9 +3598,6 @@ function TXMLReader.AllocAttributeData: PNodeData;
|
||||
begin
|
||||
Result := AllocNodeData(FNesting + FAttrCount + 1);
|
||||
Result^.FNodeType := ntAttribute;
|
||||
Result^.FPrefix := nil;
|
||||
Result^.FNsUri := nil;
|
||||
Result^.FIDEntry := nil;
|
||||
Result^.FIsDefault := False;
|
||||
Inc(FAttrCount);
|
||||
end;
|
||||
@ -3606,6 +3609,9 @@ begin
|
||||
SetLength(FNodeStack, AIndex * 2 + 2);
|
||||
|
||||
Result := @FNodeStack[AIndex];
|
||||
Result^.FPrefix := nil;
|
||||
Result^.FNsUri := nil;
|
||||
Result^.FIDEntry := nil;
|
||||
end;
|
||||
|
||||
function TXMLReader.AllocAttributeValueChunk(APrev: PNodeData): PNodeData;
|
||||
@ -3671,21 +3677,23 @@ end;
|
||||
|
||||
procedure TXMLReader.PushVC(aElDef: TElementDecl);
|
||||
begin
|
||||
Inc(FNesting);
|
||||
FCurrNode := AllocNodeData(FNesting);
|
||||
FCurrNode^.FPrefix := nil;
|
||||
FCurrNode^.FNsUri := nil;
|
||||
FCurrNode^.FIDEntry := nil;
|
||||
Inc(FValidatorNesting);
|
||||
if FValidatorNesting >= Length(FValidators) then
|
||||
SetLength(FValidators, FValidatorNesting * 2);
|
||||
|
||||
if FNesting >= Length(FValidators) then
|
||||
with FValidators[FValidatorNesting] do
|
||||
begin
|
||||
SetLength(FValidators, FNesting * 2);
|
||||
FElementDef := aElDef;
|
||||
FCurCP := nil;
|
||||
FFailed := False;
|
||||
FContentType := ctAny;
|
||||
FSaViolation := False;
|
||||
if Assigned(aElDef) then
|
||||
begin
|
||||
FContentType := aElDef.ContentType;
|
||||
FSaViolation := FStandalone and aElDef.ExternallyDeclared;
|
||||
end;
|
||||
end;
|
||||
|
||||
FValidators[FNesting].FElementDef := aElDef;
|
||||
FValidators[FNesting].FCurCP := nil;
|
||||
FValidators[FNesting].FFailed := False;
|
||||
UpdateConstraints;
|
||||
end;
|
||||
|
||||
procedure TXMLReader.PopVC;
|
||||
@ -3694,24 +3702,9 @@ begin
|
||||
FState := rsEpilog;
|
||||
if FNesting > 0 then Dec(FNesting);
|
||||
FCurrNode := @FNodeStack[FNesting];
|
||||
UpdateConstraints;
|
||||
FNext := xtText;
|
||||
end;
|
||||
|
||||
procedure TXMLReader.UpdateConstraints;
|
||||
begin
|
||||
if FValidate and Assigned(FValidators[FNesting].FElementDef) then
|
||||
begin
|
||||
FCurrContentType := FValidators[FNesting].FElementDef.ContentType;
|
||||
FSaViolation := FStandalone and (FValidators[FNesting].FElementDef.ExternallyDeclared);
|
||||
end
|
||||
else
|
||||
begin
|
||||
FCurrContentType := ctAny;
|
||||
FSaViolation := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TElementValidator }
|
||||
|
||||
function TElementValidator.IsElementAllowed(Def: TElementDecl): Boolean;
|
||||
|
Loading…
Reference in New Issue
Block a user