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