mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-17 07:39:13 +02:00
XPath improvements:
+ Utility function TXPathScanner.SkipToken, saves some amount of typing. * Allow TXPathLocationPathNode to have FFirstStep = nil, and don't create a redundant initial step while parsing. git-svn-id: trunk@13253 -
This commit is contained in:
parent
2c3d6645be
commit
538f82091a
@ -372,6 +372,7 @@ type
|
||||
constructor Create(const AExpressionString: DOMString);
|
||||
function NextToken: TXPathToken;
|
||||
function PeekToken: TXPathToken;
|
||||
function SkipToken(tok: TXPathToken): Boolean;
|
||||
property CurToken: TXPathToken read FCurToken;
|
||||
property CurTokenString: DOMString read FCurTokenString;
|
||||
end;
|
||||
@ -1274,6 +1275,7 @@ var
|
||||
ResultNodeSet: TNodeSet;
|
||||
LeftResult: TXPathVariable;
|
||||
i: Integer;
|
||||
Node: TDOMNode;
|
||||
|
||||
procedure EvaluateStep(AStep: TStep; AContextNode: TDOMNode);
|
||||
var
|
||||
@ -1318,10 +1320,17 @@ begin
|
||||
LeftResult.Release;
|
||||
end;
|
||||
end
|
||||
else if FIsAbsolutePath and (AContext.ContextNode.NodeType <> DOCUMENT_NODE) then
|
||||
EvaluateStep(FFirstStep, AContext.ContextNode.OwnerDocument)
|
||||
else
|
||||
EvaluateStep(FFirstStep, AContext.ContextNode);
|
||||
begin
|
||||
if FIsAbsolutePath and (AContext.ContextNode.NodeType <> DOCUMENT_NODE) then
|
||||
Node := AContext.ContextNode.OwnerDocument
|
||||
else
|
||||
Node := AContext.ContextNode;
|
||||
if Assigned(FFirstStep) then
|
||||
EvaluateStep(FFirstStep, Node)
|
||||
else
|
||||
ResultNodeSet.Add(Node); // Assert(FIsAbsolutePath)
|
||||
end;
|
||||
except
|
||||
ResultNodeSet.Free;
|
||||
raise;
|
||||
@ -1551,6 +1560,13 @@ begin
|
||||
SetString(FCurTokenString, FTokenStart, FTokenLength);
|
||||
end;
|
||||
|
||||
function TXPathScanner.SkipToken(tok: TXPathToken): Boolean; { inline? }
|
||||
begin
|
||||
Result := (FCurToken = tok);
|
||||
if Result then
|
||||
NextToken;
|
||||
end;
|
||||
|
||||
function TXPathScanner.GetToken: TXPathToken;
|
||||
|
||||
procedure GetNumber(HasDot: Boolean);
|
||||
@ -1566,16 +1582,22 @@ function TXPathScanner.GetToken: TXPathToken;
|
||||
Result := tkNumber;
|
||||
end;
|
||||
|
||||
begin
|
||||
if FCurToken = tkEndOfStream then
|
||||
// TODO: no surrogate pairs/XML 1.1 support yet
|
||||
function ScanNCName: Boolean;
|
||||
begin
|
||||
Result := tkEndOfStream;
|
||||
exit;
|
||||
Result := Byte(FCurData^) in NamingBitmap[NamePages[hi(Word(FCurData^))]];
|
||||
if Result then
|
||||
begin
|
||||
FTokenLength := 1;
|
||||
while Byte(FCurData[1]) in NamingBitmap[NamePages[$100+hi(Word(FCurData[1]))]] do
|
||||
begin
|
||||
Inc(FCurData);
|
||||
Inc(FTokenLength);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ No, we cannot use a lookup table here, as future
|
||||
versions will use WideStrings -sg }
|
||||
|
||||
begin
|
||||
// Skip whitespace
|
||||
while (FCurData[0] < #255) and (char(ord(FCurData[0])) in [#9, #10, #13, ' ']) do
|
||||
Inc(FCurData);
|
||||
@ -1686,17 +1708,10 @@ begin
|
||||
'|':
|
||||
Result := tkPipe;
|
||||
else
|
||||
// TODO: no surrogate pairs/XML 1.1 support yet
|
||||
if Byte(FCurData^) in NamingBitmap[NamePages[hi(Word(FCurData^))]] then
|
||||
begin
|
||||
FTokenLength := 1;
|
||||
Result := tkIdentifier;
|
||||
while Byte(FCurData[1]) in NamingBitmap[NamePages[$100+hi(Word(FCurData[1]))]] do
|
||||
begin
|
||||
Inc(FCurData);
|
||||
Inc(FTokenLength);
|
||||
end;
|
||||
end
|
||||
if ScanNCName then
|
||||
// TODO: must handle 'NCName:*' and 'NCName:NCName' here,
|
||||
// these are single tokens which may not have whitespace inbetween.
|
||||
Result := tkIdentifier
|
||||
else
|
||||
Error(SScannerInvalidChar);
|
||||
end;
|
||||
@ -1719,9 +1734,8 @@ begin
|
||||
I := 0;
|
||||
// accumulate nodes in local buffer, then add all at once
|
||||
// this reduces amount of ReallocMem's
|
||||
while CurToken = tkLeftSquareBracket do
|
||||
while SkipToken(tkLeftSquareBracket) do
|
||||
begin
|
||||
NextToken;
|
||||
Buffer[I] := ParseOrExpr;
|
||||
Inc(I);
|
||||
if I > High(Buffer) then
|
||||
@ -1729,9 +1743,8 @@ begin
|
||||
AddNodes(Dest, Buffer);
|
||||
I := 0;
|
||||
end;
|
||||
if CurToken <> tkRightSquareBracket then
|
||||
if not SkipToken(tkRightSquareBracket) then
|
||||
Error(SParserExpectedRightSquareBracket);
|
||||
NextToken;
|
||||
end;
|
||||
if I > 0 then
|
||||
AddNodes(Dest, Slice(Buffer, I));
|
||||
@ -1801,9 +1814,7 @@ begin
|
||||
|
||||
NextToken; // skip identifier and the '::'
|
||||
NextToken;
|
||||
end
|
||||
else if CurToken <> tkEndOfStream then
|
||||
Dest.Axis := axisChild;
|
||||
end;
|
||||
|
||||
// Parse [7] NodeTest
|
||||
if CurToken = tkAsterisk then // [37] NameTest, first case
|
||||
@ -1925,32 +1936,23 @@ end;
|
||||
function TXPathScanner.ParseUnionExpr: TXPathExprNode; // [18]
|
||||
begin
|
||||
Result := ParsePathExpr;
|
||||
while CurToken = tkPipe do
|
||||
begin
|
||||
NextToken;
|
||||
while SkipToken(tkPipe) do
|
||||
Result := TXPathUnionNode.Create(Result, ParsePathExpr);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TXPathScanner.ParsePathExpr: TXPathExprNode; // [19]
|
||||
var
|
||||
IsFunctionCall: Boolean;
|
||||
CurStep, NextStep: TStep;
|
||||
begin
|
||||
// Try to detect wether a LocationPath [1] or a FilterExpr [20] follows
|
||||
IsFunctionCall := False;
|
||||
if (CurToken = tkIdentifier) and
|
||||
Result := nil;
|
||||
CurStep := nil;
|
||||
// Try to detect whether a LocationPath [1] or a FilterExpr [20] follows
|
||||
if ((CurToken = tkIdentifier) and (PeekToken = tkLeftBracket) and
|
||||
(CurTokenString <> 'comment') and
|
||||
(CurTokenString <> 'text') and
|
||||
(CurTokenString <> 'processing-instruction') and
|
||||
(CurTokenString <> 'node') and
|
||||
(PeekToken = tkLeftBracket) then
|
||||
IsFunctionCall := True;
|
||||
|
||||
Result := nil;
|
||||
CurStep := nil;
|
||||
if IsFunctionCall or (CurToken in
|
||||
[tkDollar, tkLeftBracket, tkString, tkNumber]) then
|
||||
(CurTokenString <> 'node')) or
|
||||
(CurToken in [tkDollar, tkLeftBracket, tkString, tkNumber]) then
|
||||
begin
|
||||
// second, third or fourth case of [19]
|
||||
Result := ParseFilterExpr;
|
||||
@ -1967,26 +1969,17 @@ begin
|
||||
NextToken;
|
||||
end
|
||||
else if CurToken = tkSlash then
|
||||
begin
|
||||
NextToken;
|
||||
// TODO: This looks unnecessary, but evaluate() should be fixed
|
||||
if TXPathLocationPathNode(Result).FLeft = nil then
|
||||
begin
|
||||
CurStep := TStep.Create(axisSelf, ntAnyNode);
|
||||
TXPathLocationPathNode(Result).FFirstStep := CurStep;
|
||||
end;
|
||||
end;
|
||||
|
||||
repeat
|
||||
if CurToken <> tkEndOfStream then
|
||||
begin
|
||||
NextStep := TStep.Create(axisInvalid, ntAnyPrincipal); { args are dummy }
|
||||
if Assigned(CurStep) then
|
||||
CurStep.NextStep := NextStep
|
||||
else
|
||||
TXPathLocationPathNode(Result).FFirstStep := NextStep;
|
||||
CurStep := NextStep;
|
||||
end;
|
||||
|
||||
while CurToken in [tkDot, tkDotDot, tkAt, tkAsterisk, tkIdentifier] do
|
||||
begin
|
||||
// axisChild is the default. ntAnyPrincipal is dummy.
|
||||
NextStep := TStep.Create(axisChild, ntAnyPrincipal);
|
||||
if Assigned(CurStep) then
|
||||
CurStep.NextStep := NextStep
|
||||
else
|
||||
TXPathLocationPathNode(Result).FFirstStep := NextStep;
|
||||
CurStep := NextStep;
|
||||
|
||||
// Parse [4] Step
|
||||
ParseStep(CurStep);
|
||||
@ -2000,11 +1993,9 @@ begin
|
||||
CurStep.NextStep := NextStep;
|
||||
CurStep := NextStep;
|
||||
end
|
||||
else if CurToken <> tkSlash then
|
||||
break
|
||||
else
|
||||
NextToken; // skip the slash
|
||||
until False;
|
||||
else if not SkipToken(tkSlash) then
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TXPathScanner.ParseFilterExpr: TXPathExprNode; // [20]
|
||||
@ -2120,11 +2111,8 @@ var
|
||||
NegCount: Integer;
|
||||
begin
|
||||
NegCount := 0;
|
||||
while CurToken = tkMinus do
|
||||
begin
|
||||
while SkipToken(tkMinus) do
|
||||
Inc(NegCount);
|
||||
NextToken;
|
||||
end;
|
||||
Result := ParseUnionExpr;
|
||||
|
||||
if Odd(NegCount) then
|
||||
|
Loading…
Reference in New Issue
Block a user