فهرست منبع

Further XPath improvements:

+ Implemented [more or less] correct parsing of last two variations of PathExpr [19].
  (only parsing - evaluation still has to be done).

git-svn-id: trunk@13116 -
sergei 16 سال پیش
والد
کامیت
d03e569ae9
1فایلهای تغییر یافته به همراه65 افزوده شده و 69 حذف شده
  1. 65 69
      packages/fcl-xml/src/xpath.pp

+ 65 - 69
packages/fcl-xml/src/xpath.pp

@@ -252,10 +252,11 @@ type
 
   TXPathLocationPathNode = class(TXPathExprNode)
   private
+    FLeft: TXPathExprNode;
     FFirstStep: TStep;
     FIsAbsolutePath: Boolean;
   public
-    constructor Create(AIsAbsolutePath: Boolean);
+    constructor Create(ALeft: TXPathExprNode; AIsAbsolutePath: Boolean);
     destructor destroy;override;
     function Evaluate(AContext: TXPathContext;
       AEnvironment: TXPathEnvironment): TXPathVariable; override;
@@ -357,7 +358,6 @@ type
     FTokenStart: DOMPChar;
     FTokenLength: Integer;
     procedure Error(const Msg: String);
-    function ParseLocationPath: TXPathLocationPathNode;  // [1]
     procedure ParseStep(var Dest: TStep);                // [4]
     function ParsePrimaryExpr: TXPathExprNode; // [15]
     function ParseUnionExpr: TXPathExprNode;   // [18]
@@ -1074,9 +1074,10 @@ begin
   inherited destroy;
 end;
 
-constructor TXPathLocationPathNode.Create(AIsAbsolutePath: Boolean);
+constructor TXPathLocationPathNode.Create(ALeft: TXPathExprNode; AIsAbsolutePath: Boolean);
 begin
   inherited Create;
+  FLeft := ALeft;
   FIsAbsolutePath := AIsAbsolutePath;
 end;
 
@@ -1332,12 +1333,15 @@ begin
 end;
 
 destructor TXPathLocationPathNode.destroy;
-var tmp:TStep;
+var
+  tmp:TStep;
 begin
- while FFirstStep<>nil do begin
-  tmp:=FFirstStep.NextStep;
-  FFirstStep.free;
-  FFirstStep:=tmp;
+  FLeft.Free;
+  while FFirstStep<>nil do
+  begin
+    tmp:=FFirstStep.NextStep;
+    FFirstStep.free;
+    FFirstStep:=tmp;
  end;
 end;
 
@@ -1713,64 +1717,6 @@ begin
   raise Exception.Create(Msg) at get_caller_addr(get_frame);
 end;
 
-function TXPathScanner.ParseLocationPath: TXPathLocationPathNode;  // [1]
-var
-  IsAbsolute: Boolean;
-  CurStep, NextStep: TStep;
-
-begin
-  CurStep := nil;
-  IsAbsolute := False;
-
-  case CurToken of
-    tkSlash:          // [2] AbsoluteLocationPath, first case
-      begin
-        NextToken;
-        CurStep := TStep.Create(axisSelf, ntAnyNode);
-        IsAbsolute := True;
-      end;
-    tkSlashSlash:     // [10] AbbreviatedAbsoluteLocationPath
-      begin
-        NextToken;
-        IsAbsolute := True;
-        CurStep := TStep.Create(axisDescendantOrSelf, ntAnyNode);
-      end;
-  end;
-
-  Result := TXPathLocationPathNode.Create(IsAbsolute);
-  Result.FFirstStep := CurStep;
-
-  // Parse [3] RelativeLocationPath
-  repeat
-    if CurToken <> tkEndOfStream then
-    begin
-      NextStep := TStep.Create(axisInvalid, ntAnyPrincipal); { args are dummy }
-      if Assigned(CurStep) then
-        CurStep.NextStep := NextStep
-      else
-        Result.FFirstStep := NextStep;
-      CurStep := NextStep;
-    end;
-
-    // Parse [4] Step
-    ParseStep(CurStep);
-
-    // Continue with parsing of [3] RelativeLocationPath
-    if CurToken = tkSlashSlash then
-    begin
-      NextToken;
-      // Found abbreviated step ("//" for "descendant-or-self::node()")
-      NextStep := TStep.Create(axisDescendantOrSelf, ntAnyNode);
-      CurStep.NextStep := NextStep;
-      CurStep := NextStep;
-    end
-    else if CurToken <> tkSlash then
-      break
-    else
-      NextToken;   // skip the slash
-  until False;
-end;
-
 procedure TXPathScanner.ParseStep(var Dest: TStep);  // [4]
 var
   NeedColonColon: Boolean;
@@ -1988,6 +1934,7 @@ function TXPathScanner.ParsePathExpr: TXPathExprNode;  // [19]
 var
   ScannerState: TXPathScannerState;
   IsFunctionCall: Boolean;
+  CurStep, NextStep: TStep;
 begin
   // Try to detect wether a LocationPath [1] or a FilterExpr [20] follows
   IsFunctionCall := False;
@@ -2003,15 +1950,64 @@ begin
     RestoreState(ScannerState);
   end;
 
+  Result := nil;
+  CurStep := nil;
   if IsFunctionCall or (CurToken in
     [tkDollar, tkLeftBracket, tkString, tkNumber]) then
   begin
     // second, third or fourth case of [19]
     Result := ParseFilterExpr;
-    // !!!: Doesn't handle "/" or "//" plus RelativeLocationPath yet!
+    if not (CurToken in [tkSlash, tkSlashSlash]) then
+      Exit;
+  end;
+  Result := TXPathLocationPathNode.Create(Result,
+    (Result = nil) and (CurToken in [tkSlash, tkSlashSlash]));
+
+  if CurToken = tkSlashSlash then
+  begin
+    CurStep := TStep.Create(axisDescendantOrSelf, ntAnyNode);
+    TXPathLocationPathNode(Result).FFirstStep := CurStep;
+    NextToken;
   end
-  else
-    Result := ParseLocationPath;
+  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;
+
+    // Parse [4] Step
+    ParseStep(CurStep);
+
+    // Continue with parsing of [3] RelativeLocationPath
+    if CurToken = tkSlashSlash then
+    begin
+      NextToken;
+      // Found abbreviated step ("//" for "descendant-or-self::node()")
+      NextStep := TStep.Create(axisDescendantOrSelf, ntAnyNode);
+      CurStep.NextStep := NextStep;
+      CurStep := NextStep;
+    end
+    else if CurToken <> tkSlash then
+      break
+    else
+      NextToken;   // skip the slash
+  until False;
 end;
 
 function TXPathScanner.ParseFilterExpr: TXPathExprNode;  // [20]