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