XPath: reworked step processing:

* For ancestor and ancestor-or-self axes, added checks for attribute nodes similar to parent axis.
* For reverse axes, collect and filter nodes in 'natural' (i.e. reversed) order, and only then reverse order while adding to result node set. This is much simpler to implement.
* Fixed memory leak (not destroying TXPathFilterNode.FExpr)

git-svn-id: trunk@15652 -
This commit is contained in:
sergei 2010-07-28 14:25:08 +00:00
parent 22038d7db6
commit ae7aef0861

View File

@ -1049,6 +1049,7 @@ destructor TXPathFilterNode.Destroy;
var
i: Integer;
begin
FExpr.Free;
for i := 0 to High(FPredicates) do
FPredicates[i].Free;
inherited Destroy;
@ -1121,7 +1122,6 @@ var
Node, Node2: TDOMNode;
Attr: TDOMNamedNodeMap;
i: Integer;
TempList: TFPList;
procedure DoNodeTest(Node: TDOMNode);
begin
@ -1169,12 +1169,29 @@ var
end;
end;
procedure AddDescendantsReverse(CurNode: TDOMNode);
var
Child: TDOMNode;
begin
Child := CurNode.LastChild;
while Assigned(Child) do
begin
AddDescendantsReverse(Child);
DoNodeTest(Child);
Child := Child.PreviousSibling;
end;
end;
begin
ResultNodes := TNodeSet.Create;
case Axis of
axisAncestor:
begin
Node := ANode.ParentNode;
// TODO: same check needed for XPATH_NAMESPACE_NODE
if ANode.nodeType = ATTRIBUTE_NODE then
Node := TDOMAttr(ANode).ownerElement
else
Node := ANode.ParentNode;
while Assigned(Node) do
begin
DoNodeTest(Node);
@ -1183,11 +1200,17 @@ begin
end;
axisAncestorOrSelf:
begin
Node := ANode;
repeat
DoNodeTest(ANode);
// TODO: same check needed for XPATH_NAMESPACE_NODE
if ANode.nodeType = ATTRIBUTE_NODE then
Node := TDOMAttr(ANode).ownerElement
else
Node := ANode.ParentNode;
while Assigned(Node) do
begin
DoNodeTest(Node);
Node := Node.ParentNode;
until not Assigned(Node);
end;
end;
axisAttribute:
begin
@ -1246,41 +1269,25 @@ begin
DoNodeTest(ANode.ParentNode);
axisPreceding:
begin
TempList := TFPList.Create;
try
Node := ANode;
// build list of ancestors
while Assigned(Node) do
Node := ANode;
repeat
Node2 := Node.PreviousSibling;
while Assigned(Node2) do
begin
TempList.Add(Node);
Node := Node.ParentNode;
AddDescendantsReverse(Node2);
DoNodeTest(Node2);
Node2 := Node2.PreviousSibling;
end;
// 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;
Node := Node.ParentNode;
until not Assigned(Node);
end;
axisPrecedingSibling:
begin
if Assigned(ANode.ParentNode) then
Node := ANode.PreviousSibling;
while Assigned(Node) do
begin
Node := ANode.ParentNode.FirstChild;
while Assigned(Node) and (Node <> ANode) do
begin
DoNodeTest(Node);
Node := Node.NextSibling;
end;
DoNodeTest(Node);
Node := Node.PreviousSibling;
end;
end;
axisSelf:
@ -1309,12 +1316,7 @@ begin
try
for j := 0 to Nodes.Count - 1 do
begin
// ContextPosition must honor the axis direction
if Axis in [axisAncestor, axisAncestorOrSelf,
axisPreceding, axisPrecedingSibling] then
NewContext.ContextPosition := Nodes.Count - j
else
NewContext.ContextPosition := j+1;
NewContext.ContextPosition := j+1;
NewContext.ContextNode := TDOMNode(Nodes[j]);
if not Predicates[i].EvalPredicate(NewContext, AEnvironment) then
Nodes[j] := nil;
@ -1342,7 +1344,15 @@ var
SelectNodes(AContextNode, StepNodes);
try
ApplyPredicates(StepNodes, AEnvironment);
for i := 0 to StepNodes.Count - 1 do
if Axis in [axisAncestor, axisAncestorOrSelf,
axisPreceding, axisPrecedingSibling] then
for i := StepNodes.Count - 1 downto 0 do
begin
Node := TDOMNode(StepNodes[i]);
if ResultNodeSet.IndexOf(Node) < 0 then
ResultNodeSet.Add(Node);
end
else for i := 0 to StepNodes.Count - 1 do
begin
Node := TDOMNode(StepNodes[i]);
if ResultNodeSet.IndexOf(Node) < 0 then
@ -2059,10 +2069,9 @@ begin
Exit; // allow '/' alone
end;
// Continue with parsing of [3] RelativeLocationPath
repeat
Result := AddStep(Result, ParseStep);
// Continue with parsing of [3] RelativeLocationPath
if CurToken = tkSlashSlash then
begin
NextToken;