1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 namespace System.Xml.Xsl.XsltOld
6 {
7     using System;
8     using System.Diagnostics;
9     using System.Collections;
10     using System.Xml;
11     using System.Xml.XPath;
12 
13     internal class ForEachAction : ContainerAction
14     {
15         private const int ProcessedSort = 2;
16         private const int ProcessNextNode = 3;
17         private const int PositionAdvanced = 4;
18         private const int ContentsProcessed = 5;
19 
20         private int _selectKey = Compiler.InvalidQueryKey;
21         private ContainerAction _sortContainer;
22 
Compile(Compiler compiler)23         internal override void Compile(Compiler compiler)
24         {
25             CompileAttributes(compiler);
26             CheckRequiredAttribute(compiler, _selectKey != Compiler.InvalidQueryKey, "select");
27 
28             compiler.CanHaveApplyImports = false;
29             if (compiler.Recurse())
30             {
31                 CompileSortElements(compiler);
32                 CompileTemplate(compiler);
33                 compiler.ToParent();
34             }
35         }
36 
CompileAttribute(Compiler compiler)37         internal override bool CompileAttribute(Compiler compiler)
38         {
39             string name = compiler.Input.LocalName;
40             string value = compiler.Input.Value;
41             if (Ref.Equal(name, compiler.Atoms.Select))
42             {
43                 _selectKey = compiler.AddQuery(value);
44             }
45             else
46             {
47                 return false;
48             }
49 
50             return true;
51         }
52 
Execute(Processor processor, ActionFrame frame)53         internal override void Execute(Processor processor, ActionFrame frame)
54         {
55             Debug.Assert(processor != null && frame != null);
56 
57             switch (frame.State)
58             {
59                 case Initialized:
60                     if (_sortContainer != null)
61                     {
62                         processor.InitSortArray();
63                         processor.PushActionFrame(_sortContainer, frame.NodeSet);
64                         frame.State = ProcessedSort;
65                         break;
66                     }
67                     goto case ProcessedSort;
68                 case ProcessedSort:
69                     frame.InitNewNodeSet(processor.StartQuery(frame.NodeSet, _selectKey));
70                     if (_sortContainer != null)
71                     {
72                         Debug.Assert(processor.SortArray.Count != 0);
73                         frame.SortNewNodeSet(processor, processor.SortArray);
74                     }
75                     frame.State = ProcessNextNode;
76                     goto case ProcessNextNode;
77 
78                 case ProcessNextNode:
79                     Debug.Assert(frame.State == ProcessNextNode);
80                     Debug.Assert(frame.NewNodeSet != null);
81 
82                     if (frame.NewNextNode(processor))
83                     {
84                         frame.State = PositionAdvanced;
85                         goto case PositionAdvanced;
86                     }
87                     else
88                     {
89                         frame.Finished();
90                         break;
91                     }
92 
93                 case PositionAdvanced:
94                     processor.PushActionFrame(frame, frame.NewNodeSet);
95                     frame.State = ContentsProcessed;
96                     break;
97 
98                 case ContentsProcessed:
99                     frame.State = ProcessNextNode;
100                     goto case ProcessNextNode;
101             }
102         }
103 
CompileSortElements(Compiler compiler)104         protected void CompileSortElements(Compiler compiler)
105         {
106             NavigatorInput input = compiler.Input;
107             do
108             {
109                 switch (input.NodeType)
110                 {
111                     case XPathNodeType.Element:
112                         if (Ref.Equal(input.NamespaceURI, input.Atoms.UriXsl) &&
113                             Ref.Equal(input.LocalName, input.Atoms.Sort))
114                         {
115                             if (_sortContainer == null)
116                             {
117                                 _sortContainer = new ContainerAction();
118                             }
119                             _sortContainer.AddAction(compiler.CreateSortAction());
120                             continue;
121                         }
122                         return;
123                     case XPathNodeType.Text:
124                         return;
125                     case XPathNodeType.SignificantWhitespace:
126                         this.AddEvent(compiler.CreateTextEvent());
127                         continue;
128                     default:
129                         continue;
130                 }
131             }
132             while (input.Advance());
133         }
134     }
135 }
136