Browse Source

* Patch from Sergei Gorelkin
* TXPathUnionNode.Evaluate: fixed two crashes. The object returned by
TXPathVariable.AsNodeSet is owned by that TXPathVariable and should
not be explicitly destroyed. Also TXPathVariable should not be
released if its AsNodeSet result will be used later.

* TXPathLocationPathNode.Evaluate/EvaluateStep:

- fixed crash in axisFollowing case branch (caused by wrong variable
being used in the loop).
- rewrote axisPreceding branch so it builds the result node list in
correct (document) order.
- Fixed predicate match condition that was always evaluating as True.

* TXPathScanner.ParseLocationPath: modified so it never returns nil.
This fixes crash in cases when '/' or '//' are used otherwise than
the whole expression (e.g. 'string(/)').

* Replaced manual searching in TList by calls to IndexOf() in two
places.

git-svn-id: trunk@12934 -

michael 16 years ago
parent
commit
8cf5d9abf2
1 changed files with 50 additions and 65 deletions
  1. 50 65
      packages/fcl-xml/src/xpath.pp

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

@@ -842,30 +842,25 @@ begin
     try
     try
       NodeSet := Op1Result.AsNodeSet;
       NodeSet := Op1Result.AsNodeSet;
       NodeSet2 := Op2Result.AsNodeSet;
       NodeSet2 := Op2Result.AsNodeSet;
-      try
-        for i := 0 to NodeSet2.Count - 1 do
-        begin
-          DoAdd := True;
-          CurNode := NodeSet2[i];
-          for j := 0 to NodeSet.Count - 1 do
-            if NodeSet[j] = CurNode then
-            begin
-              DoAdd := False;
-          break;
-            end;
-          if DoAdd then
-            NodeSet.Add(CurNode);
-        end;
-      finally
-        NodeSet2.Free;
+      for i := 0 to NodeSet2.Count - 1 do
+      begin
+        DoAdd := True;
+        CurNode := NodeSet2[i];
+        for j := 0 to NodeSet.Count - 1 do
+          if NodeSet[j] = CurNode then
+          begin
+            DoAdd := False;
+            break;
+          end;
+        if DoAdd then
+          NodeSet.Add(CurNode);
       end;
       end;
     finally
     finally
       Op2Result.Release;
       Op2Result.Release;
     end;
     end;
   finally
   finally
-    Op1Result.Release;
+    Result := Op1Result;
   end;
   end;
-  Result := TXPathNodeSetVariable.Create(NodeSet);
 end;
 end;
 
 
 
 
@@ -979,9 +974,6 @@ var
     StepNodes: TList;
     StepNodes: TList;
 
 
     procedure DoNodeTest(Node: TDOMNode);
     procedure DoNodeTest(Node: TDOMNode);
-    var
-      i: Integer;
-      DoAdd: Boolean;
     begin
     begin
       case AStep.NodeTestType of
       case AStep.NodeTestType of
         ntAnyPrincipal:
         ntAnyPrincipal:
@@ -1002,14 +994,7 @@ var
           if Node.NodeType <> PROCESSING_INSTRUCTION_NODE then
           if Node.NodeType <> PROCESSING_INSTRUCTION_NODE then
             exit;
             exit;
       end;
       end;
-      DoAdd := True;
-      for i := 0 to StepNodes.Count - 1 do
-        if TDOMNode(StepNodes[i]) = Node then
-        begin
-          DoAdd := False;
-          break;
-        end;
-      if DoAdd then
+      if StepNodes.IndexOf(Node) < 0 then
         StepNodes.Add(Node);
         StepNodes.Add(Node);
     end;
     end;
 
 
@@ -1030,12 +1015,12 @@ var
     Node, Node2: TDOMNode;
     Node, Node2: TDOMNode;
     Attr: TDOMNamedNodeMap;
     Attr: TDOMNamedNodeMap;
     i, j: Integer;
     i, j: Integer;
-    DoAdd: Boolean;
 
 
     NewContext: TXPathContext;
     NewContext: TXPathContext;
     NewStepNodes: TNodeSet;
     NewStepNodes: TNodeSet;
     Predicate: TXPathExprNode;
     Predicate: TXPathExprNode;
     PredicateResult: TXPathVariable;
     PredicateResult: TXPathVariable;
+    TempList: TList;
 
 
   begin
   begin
     StepNodes := TList.Create;
     StepNodes := TList.Create;
@@ -1090,7 +1075,7 @@ var
             begin
             begin
               DoNodeTest(Node2);
               DoNodeTest(Node2);
               AddDescendants(Node2);
               AddDescendants(Node2);
-              Node := Node.NextSibling;
+              Node2 := Node2.NextSibling;
             end;
             end;
             Node := Node.ParentNode;
             Node := Node.ParentNode;
           until not Assigned(Node);
           until not Assigned(Node);
@@ -1110,17 +1095,30 @@ var
           DoNodeTest(AContext.ContextNode);
           DoNodeTest(AContext.ContextNode);
       axisPreceding:
       axisPreceding:
         begin
         begin
-          Node := AContext.ContextNode;
-          repeat
-            Node2 := Node.PreviousSibling;
-            while Assigned(Node2) do
+          TempList := TList.Create;
+          try
+            Node := AContext.ContextNode;
+            // build list of ancestors
+            while Assigned(Node) do
             begin
             begin
-              DoNodeTest(Node2);
-              AddDescendants(Node2);
-              Node := Node.PreviousSibling;
+              TempList.Add(Node);
+              Node := Node.ParentNode;
             end;
             end;
-            Node := Node.ParentNode;
-          until not Assigned(Node);
+            // then process it in reverse order
+            for i := TempList.Count-1 downto 1 do
+            begin
+              Node := TDOMNode(TempList[i]);
+              Node2 := Node.FirstChild;
+              while Assigned(Node2) and (Node2 <> TDOMNode(TempList[i-1])) do
+              begin
+                DoNodeTest(Node2);
+                AddDescendants(Node2);
+                Node2 := Node2.NextSibling;
+              end;
+            end;
+          finally
+            TempList.Free;
+          end;
         end;
         end;
       axisPrecedingSibling:
       axisPrecedingSibling:
         begin
         begin
@@ -1158,7 +1156,8 @@ var
           try
           try
             if (PredicateResult.InheritsFrom(TXPathNumberVariable) and
             if (PredicateResult.InheritsFrom(TXPathNumberVariable) and
               (PredicateResult.AsNumber = j + 1)) or
               (PredicateResult.AsNumber = j + 1)) or
-              PredicateResult.AsBoolean then
+              (not PredicateResult.InheritsFrom(TXPathNumberVariable) and
+               PredicateResult.AsBoolean) then
                 NewStepNodes.Add(Node);
                 NewStepNodes.Add(Node);
           finally
           finally
             PredicateResult.Release;
             PredicateResult.Release;
@@ -1190,14 +1189,7 @@ var
       for i := 0 to StepNodes.Count - 1 do
       for i := 0 to StepNodes.Count - 1 do
       begin
       begin
         Node := TDOMNode(StepNodes[i]);
         Node := TDOMNode(StepNodes[i]);
-        DoAdd := True;
-        for j := 0 to ResultNodeSet.Count - 1 do
-          if TDOMNode(ResultNodeSet[j]) = Node then
-          begin
-            DoAdd := False;
-            break;
-          end;
-        if DoAdd then
+        if ResultNodeSet.IndexOf(Node) < 0 then
           ResultNodeSet.Add(Node);
           ResultNodeSet.Add(Node);
       end;
       end;
     end;
     end;
@@ -1628,7 +1620,7 @@ end;
 function TXPathScanner.ParseLocationPath: TXPathLocationPathNode;  // [1]
 function TXPathScanner.ParseLocationPath: TXPathLocationPathNode;  // [1]
 var
 var
   IsAbsolute, NeedColonColon: Boolean;
   IsAbsolute, NeedColonColon: Boolean;
-  FirstStep, CurStep, NextStep: TStep;
+  CurStep, NextStep: TStep;
 
 
   procedure NeedBrackets;
   procedure NeedBrackets;
   begin
   begin
@@ -1640,17 +1632,13 @@ var
 
 
 begin
 begin
   CurStep := nil;
   CurStep := nil;
-  Result := nil;
+  IsAbsolute := False;
 
 
   case CurToken of
   case CurToken of
     tkSlash:          // [2] AbsoluteLocationPath, first case
     tkSlash:          // [2] AbsoluteLocationPath, first case
       begin
       begin
-        if NextToken = tkEndOfStream then
-          CurStep := TStep.Create(axisSelf, ntAnyNode)
-        else
-        if not (CurToken in
-          [tkDot, tkDotDot, tkAsterisk, tkAt, tkIdentifier, tkEndOfStream]) then
-          exit;
+        NextToken;
+        CurStep := TStep.Create(axisSelf, ntAnyNode);
         IsAbsolute := True;
         IsAbsolute := True;
       end;
       end;
     tkSlashSlash:     // [10] AbbreviatedAbsoluteLocationPath
     tkSlashSlash:     // [10] AbbreviatedAbsoluteLocationPath
@@ -1659,12 +1647,12 @@ begin
         IsAbsolute := True;
         IsAbsolute := True;
         CurStep := TStep.Create(axisDescendantOrSelf, ntAnyNode);
         CurStep := TStep.Create(axisDescendantOrSelf, ntAnyNode);
       end;
       end;
-    else
-      IsAbsolute := False;
   end;
   end;
 
 
+  Result := TXPathLocationPathNode.Create(IsAbsolute);
+  Result.FFirstStep := CurStep;
+
   // Parse [3] RelativeLocationPath
   // Parse [3] RelativeLocationPath
-  FirstStep := CurStep;
   repeat
   repeat
     if CurToken <> tkEndOfStream then
     if CurToken <> tkEndOfStream then
     begin
     begin
@@ -1672,7 +1660,7 @@ begin
       if Assigned(CurStep) then
       if Assigned(CurStep) then
         CurStep.NextStep := NextStep
         CurStep.NextStep := NextStep
       else
       else
-        FirstStep := NextStep;
+        Result.FFirstStep := NextStep;
       CurStep := NextStep;
       CurStep := NextStep;
     end;
     end;
 
 
@@ -1804,7 +1792,7 @@ begin
             end;
             end;
           tkEndOfStream:	// Enable support of "/" and "//" as path
           tkEndOfStream:	// Enable support of "/" and "//" as path
         else
         else
-          Error(SParserInvalidNodeTest);
+          Exit;
         end;
         end;
 
 
         // Parse predicates
         // Parse predicates
@@ -1833,9 +1821,6 @@ begin
     else
     else
       NextToken;   // skip the slash
       NextToken;   // skip the slash
   until False;
   until False;
-
-  Result := TXPathLocationPathNode.Create(IsAbsolute);
-  Result.FFirstStep := FirstStep;
 end;
 end;
 
 
 function TXPathScanner.ParsePrimaryExpr: TXPathExprNode;  // [15]
 function TXPathScanner.ParsePrimaryExpr: TXPathExprNode;  // [15]