ExtractColumnValues reads the given CSV or JSON file and returns the values of the named column/field. Format is detected by extension, with a content-sniff fallback. Empty and whitespace-only values are dropped. CSV parsing reuses the tabular parser (BOM decoding, comma/tab auto-detection, case-ins
(path, column string)
| 120 | // tabular parser (BOM decoding, comma/tab auto-detection, case-insensitive |
| 121 | // header match). |
| 122 | func ExtractColumnValues(path, column string) ([]string, error) { |
| 123 | content, err := os.ReadFile(path) |
| 124 | if err != nil { |
| 125 | return nil, fmt.Errorf("reading policy input file: %w", err) |
| 126 | } |
| 127 | |
| 128 | // Strip a leading UTF-8 BOM (common on Windows-authored files) so both |
| 129 | // format detection and JSON parsing see clean bytes. The CSV path strips |
| 130 | // it again inside tabular.Parse, which is harmless. |
| 131 | content = bytes.TrimPrefix(content, []byte("\xef\xbb\xbf")) |
| 132 | |
| 133 | switch strings.ToLower(filepath.Ext(path)) { |
| 134 | case ".json": |
| 135 | return extractJSONColumn(content, column) |
| 136 | case ".csv", ".tsv", ".txt": |
| 137 | return extractCSVColumn(content, column) |
| 138 | default: |
| 139 | // Content sniff: a leading "[" or "{" means JSON, otherwise treat as CSV. |
| 140 | if t := bytes.TrimSpace(content); len(t) > 0 && (t[0] == '[' || t[0] == '{') { |
| 141 | return extractJSONColumn(content, column) |
| 142 | } |
| 143 | return extractCSVColumn(content, column) |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | func extractCSVColumn(content []byte, column string) ([]string, error) { |
| 148 | table, err := tabular.Parse(content) |