@@ -18,6 +18,8 @@ import (
1818 "bytes"
1919 "encoding/json"
2020 "fmt"
21+ "reflect"
22+ "strconv"
2123 "strings"
2224 "text/tabwriter"
2325
@@ -94,6 +96,11 @@ func (a *TableOutputFilter) FilterOutput(s string) (string, error) {
9496 return a .FormatTable (rowPath , colNames , v )
9597}
9698
99+ func isArrayOrSlice (value interface {}) bool {
100+ v := reflect .ValueOf (value )
101+ return v .Kind () == reflect .Array || v .Kind () == reflect .Slice
102+ }
103+
97104func (a * TableOutputFilter ) FormatTable (rowPath string , colNames []string , v interface {}) (string , error ) {
98105 // Add row number
99106 if v , ok := OutputFlag (a .ctx .Flags ()).GetFieldValue ("num" ); ok {
@@ -112,20 +119,80 @@ func (a *TableOutputFilter) FormatTable(rowPath string, colNames []string, v int
112119 return "" , fmt .Errorf ("jmespath: '%s' failed Need Array Expr" , rowPath )
113120 }
114121
122+ // delete date type is struct
123+ // 1 = object, 2 = array
124+ dataType := 1
125+ if len (rowsArray ) > 0 {
126+ _ , ok := rowsArray [0 ].(map [string ]interface {})
127+ if ! ok {
128+ // check if it is an array
129+ if isArrayOrSlice (rowsArray [0 ]) {
130+ dataType = 2
131+ }
132+ }
133+ }
134+
135+ colNamesArray := make ([]string , 0 )
136+ colIndexArray := make ([]int , 0 )
137+
138+ if dataType == 2 {
139+ // all colNames must be string:number format
140+ for _ , colName := range colNames {
141+ // Num ignore
142+ if colName == "Num" {
143+ colNamesArray = append (colNamesArray , colName )
144+ continue
145+ }
146+ if ! strings .Contains (colName , ":" ) {
147+ return "" , fmt .Errorf ("colNames: %s must be string:number format, like 'name:0', 0 is the array index" , colName )
148+ }
149+ // split colName to name and number, must be two parts
150+ parts := strings .Split (colName , ":" )
151+ if len (parts ) != 2 {
152+ return "" , fmt .Errorf ("colNames: %s must be string:number format, like 'name:0', 0 is the array index" , colName )
153+ }
154+ // check if number is a number, use regex match
155+ if ! isNumber (parts [1 ]) {
156+ return "" , fmt .Errorf ("colNames: %s must be string:number format, like 'name:0', 0 is the array index" , colName )
157+ }
158+ colNamesArray = append (colNamesArray , parts [0 ])
159+ num , err := strconv .Atoi (parts [1 ])
160+ if err != nil {
161+ return "" , fmt .Errorf ("colNames: %s must be string:number format, like 'name:0', 0 is the array index" , colName )
162+ }
163+ colIndexArray = append (colIndexArray , num )
164+ }
165+ }
166+
115167 var buf bytes.Buffer
116168 writer := bufio .NewWriter (& buf )
117169 format := strings .Repeat ("%v\t " , len (colNames )- 1 ) + "%v"
118170 w := tabwriter .NewWriter (writer , 0 , 0 , 1 , ' ' , tabwriter .Debug )
119- fmt .Fprintln (w , fmt .Sprintf (format , toIntfArray (colNames )... ))
171+ if dataType == 1 {
172+ fmt .Fprintln (w , fmt .Sprintf (format , toIntfArray (colNames )... ))
173+
174+ separator := ""
175+ for i , colName := range colNames {
176+ separator = separator + strings .Repeat ("-" , len (colName ))
177+ if i < len (colNames )- 1 {
178+ separator = separator + "\t "
179+ }
180+ }
181+
182+ fmt .Fprintln (w , separator )
183+ } else {
184+ fmt .Fprintln (w , fmt .Sprintf (format , toIntfArray (colNamesArray )... ))
120185
121- separator := ""
122- for i , colName := range colNames {
123- separator = separator + strings .Repeat ("-" , len (colName ))
124- if i < len (colNames )- 1 {
125- separator = separator + "\t "
186+ separator := ""
187+ for i , colNameArray := range colNamesArray {
188+ separator = separator + strings .Repeat ("-" , len (colNameArray ))
189+ if i < len (colNamesArray )- 1 {
190+ separator = separator + "\t "
191+ }
126192 }
193+
194+ fmt .Fprintln (w , separator )
127195 }
128- fmt .Fprintln (w , separator )
129196
130197 for i , row := range rowsArray {
131198 r := make ([]string , 0 )
@@ -138,10 +205,18 @@ func (a *TableOutputFilter) FormatTable(rowPath string, colNames []string, v int
138205 index = 1
139206 }
140207 }
141- for _ , colName := range colNames [index :] {
142- v , _ := jmespath .Search (colName , row )
143- s = fmt .Sprintf ("%v" , v )
144- r = append (r , s )
208+ if dataType == 1 {
209+ for _ , colName := range colNames [index :] {
210+ v , _ := jmespath .Search (colName , row )
211+ s = fmt .Sprintf ("%v" , v )
212+ r = append (r , s )
213+ }
214+ } else {
215+ for _ , colIndex := range colIndexArray {
216+ v , _ := jmespath .Search (fmt .Sprintf ("[%d]" , colIndex ), row )
217+ s = fmt .Sprintf ("%v" , v )
218+ r = append (r , s )
219+ }
145220 }
146221 fmt .Fprintln (w , fmt .Sprintf (format , toIntfArray (r )... ))
147222 }
@@ -150,6 +225,16 @@ func (a *TableOutputFilter) FormatTable(rowPath string, colNames []string, v int
150225 return buf .String (), nil
151226}
152227
228+ func isNumber (s string ) bool {
229+ for _ , c := range s {
230+ if c < '0' || c > '9' {
231+ return false
232+ }
233+ }
234+ return true
235+
236+ }
237+
153238func toIntfArray (stringArray []string ) []interface {} {
154239 intfArray := []interface {}{}
155240
0 commit comments