github.com/matislovas/ratago@v0.0.0-20240408115641-cc0857415a7a/xslt/sort.go (about) 1 package xslt 2 3 import ( 4 "sort" 5 6 "github.com/matislovas/gokogiri/xml" 7 ) 8 9 func (i *XsltInstruction) Sort(nodes []xml.Node, context *ExecutionContext) { 10 ns := &NodeSorter{nodes, i.sorting, context} 11 sort.Sort(ns) 12 } 13 14 type NodeSorter struct { 15 nodes []xml.Node 16 crit []*sortCriteria 17 context *ExecutionContext 18 } 19 20 func (s *NodeSorter) Len() int { 21 return len(s.nodes) 22 } 23 24 func (s *NodeSorter) Swap(i, j int) { 25 s.nodes[i], s.nodes[j] = s.nodes[j], s.nodes[i] 26 } 27 28 func (s *NodeSorter) Less(i, j int) bool { 29 //make this loop through the by array 30 // return as soon as non-equal result 31 return execSortFunction(s.nodes[i], s.nodes[j], s.crit, s.context) 32 } 33 34 type sortCriteria struct { 35 sel string 36 reverse bool 37 numeric bool 38 } 39 40 func compileSortFunction(i *XsltInstruction) (s *sortCriteria) { 41 s = new(sortCriteria) 42 s.sel = i.Node.Attr("select") 43 if s.sel == "" { 44 s.sel = "string(.)" 45 } 46 order := i.Node.Attr("order") 47 if order == "descending" { 48 s.reverse = true 49 } 50 datatype := i.Node.Attr("data-type") 51 if datatype == "number" { 52 s.numeric = true 53 } 54 return s 55 } 56 57 func execSortFunction(n1, n2 xml.Node, crits []*sortCriteria, context *ExecutionContext) bool { 58 59 for _, crit := range crits { 60 if crit.numeric { 61 if execNumericSortFunction(n1, n2, crit, context) { 62 return true 63 } 64 continue 65 } 66 67 s1, _ := context.EvalXPath(n1, crit.sel) 68 s1, _ = context.XPathContext.ResultAsString() 69 s2, _ := context.EvalXPath(n2, crit.sel) 70 s2, _ = context.XPathContext.ResultAsString() 71 72 if s1.(string) == s2.(string) { 73 continue 74 } 75 76 if !crit.reverse { 77 return s1.(string) < s2.(string) 78 } else { 79 return s1.(string) > s2.(string) 80 } 81 } 82 return false 83 //case-order 84 //lang 85 //data-type (text) 86 } 87 func execNumericSortFunction(n1, n2 xml.Node, crit *sortCriteria, context *ExecutionContext) bool { 88 89 s1, _ := context.EvalXPath(n1, crit.sel) 90 s1, _ = context.XPathContext.ResultAsNumber() 91 s2, _ := context.EvalXPath(n2, crit.sel) 92 s2, _ = context.XPathContext.ResultAsNumber() 93 94 if !crit.reverse { 95 if s1.(float64) < s2.(float64) { 96 return true 97 } 98 } else { 99 if s1.(float64) > s2.(float64) { 100 return true 101 } 102 } 103 return false 104 } 105 106 /* 107 package collate_test 108 109 import ( 110 "fmt" 111 "testing" 112 113 "code.google.com/p/go.text/collate" 114 "code.google.com/p/go.text/language" 115 ) 116 117 func ExampleCollator_Strings() { 118 c := collate.New(language.Und) 119 strings := []string{ 120 "ad", 121 "ab", 122 "äb", 123 "ac", 124 } 125 c.SortStrings(strings) 126 fmt.Println(strings) 127 // Output: [ab äb ac ad] 128 } 129 130 type sorter []string 131 132 func (s sorter) Len() int { 133 return len(s) 134 } 135 136 func (s sorter) Swap(i, j int) { 137 s[j], s[i] = s[i], s[j] 138 } 139 140 func (s sorter) Bytes(i int) []byte { 141 return []byte(s[i]) 142 } 143 144 func TestSort(t *testing.T) { 145 c := collate.New(language.En) 146 strings := []string{ 147 "bcd", 148 "abc", 149 "ddd", 150 } 151 c.Sort(sorter(strings)) 152 res := fmt.Sprint(strings) 153 want := "[abc bcd ddd]" 154 if res != want { 155 t.Errorf("found %s; want %s", res, want) 156 } 157 } 158 */