All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mike10004.seleniumhelp.Csvs Maven / Gradle / Ivy

There is a newer version: 0.58
Show newest version
package com.github.mike10004.seleniumhelp;

import com.google.common.base.Converter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.io.CharSink;
import com.google.common.io.CharSource;
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nullable;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

class Csvs {

    private Csvs() {}

    public interface HeaderStrategy {
        /**
         * Interface to enable arbitrary production of an array of column headers.
         * @param readerBeforeFirstRead the CSV reader before the first {@link CSVReader#readNext()} call
         * @return an array of column headers, or null if reading CSV should be stopped
         * @throws IOException
         */
        @Nullable String[] produceHeaders(CSVReader readerBeforeFirstRead) throws IOException;
    }

    private static final HeaderStrategy headersFromFirstRowStrategy = new HeaderStrategy() {
        @Override
        public String[] produceHeaders(CSVReader readerBeforeFirstRead) throws IOException {
            return readerBeforeFirstRead.readNext();
        }
    };

    public static HeaderStrategy headersFromFirstRow() {
        return headersFromFirstRowStrategy;
    }

    public static HeaderStrategy staticHeaders(final Iterable headers) {
        checkNotNull(headers);
        return new HeaderStrategy() {
            @Override
            public String[] produceHeaders(CSVReader readerBeforeFirstRead) throws IOException {
                return Iterables.toArray(headers, String.class);
            }
        };
    }

    public static List> readRowMaps(CharSource source, HeaderStrategy headerStrategy) throws IOException {
        String[] headers = null;
        List> rows = new ArrayList<>();
        try (CSVReader reader = new CSVReader(source.openStream())) {
            String[] row;
            while (true) {
                if (headers == null) {
                    headers = headerStrategy.produceHeaders(reader);
                    if (headers == null) {
                        break;
                    }
                } else {
                    row = reader.readNext();
                    if (row == null) {
                        break;
                    }
                    checkState(row.length == headers.length, "incongruent row length %d (%d headers)", row.length, headers.length);
                    Map rowMap = new LinkedHashMap<>(row.length);
                    for (int i = 0;i < row.length;i ++) {
                        rowMap.put(headers[i], row[i]);
                    }
                    rows.add(rowMap);
                }
            }
        }
        return rows;
    }

    public enum UnknownKeyStrategy {
        IGNORE, FAIL
    }

    static class UnknownKeyException extends IllegalArgumentException {
        public UnknownKeyException(String key) {
            super(StringUtils.abbreviate(key, 128));
        }
    }

    public static String[] makeRowFromMap(List headers, Map map, String defaultValue, UnknownKeyStrategy unknownKeyStrategy) {
        checkNotNull(unknownKeyStrategy, "unknownKeyStrategy");
        String[] row = new String[headers.size()];
        Arrays.fill(row, defaultValue);
        for (String key : map.keySet()) {
            int index = headers.indexOf(key);
            if (index >= 0) {
                Object value = map.get(key);
                @Nullable String valueStr = value == null ? null : value.toString();
                if (valueStr != null) {
                    row[index] = valueStr;
                }
            } else {
                if (unknownKeyStrategy == UnknownKeyStrategy.FAIL) {
                    throw new UnknownKeyException(key);
                } else if (unknownKeyStrategy == UnknownKeyStrategy.IGNORE) {
                    // yup, just ignore it
                } else {
                    throw new IllegalStateException("bug: unhandled enum constant " + unknownKeyStrategy);
                }
            }
        }
        return row;
    }

    public static int writeRowMapsWithHeaders(Iterable headers, Iterable> rows, String defaultValue, UnknownKeyStrategy unknownKeyStrategy, CharSink sink) throws IOException {
        return writeRowMaps(headers, true, rows, defaultValue, unknownKeyStrategy, sink);
    }

    public static int writeRowMaps(Iterable headers, Iterable> rows, String defaultValue, UnknownKeyStrategy unknownKeyStrategy, CharSink sink) throws IOException {
        return writeRowMaps(headers, false, rows, defaultValue, unknownKeyStrategy, sink);
    }

    private static int writeRowMaps(Iterable headers, boolean includeHeaders,
                                      Iterable> rows, String defaultValue, UnknownKeyStrategy unknownKeyStrategy, CharSink sink) throws IOException {
        List headersList = ImmutableList.copyOf(headers);
        int numOutputRows = 0;
        try (CSVWriter out = new CSVWriter(sink.openStream())) {
            if (includeHeaders) {
                out.writeNext(Iterables.toArray(headers, String.class));
            }
            numOutputRows++;
            for (Map rowInput : rows) {
                String[] rowOutput = makeRowFromMap(headersList, rowInput, defaultValue, unknownKeyStrategy);
                out.writeNext(rowOutput);
                numOutputRows++;
            }
        }
        return numOutputRows;
    }

    private static class CharBucket extends CharSink {

        private final StringWriter sw;

        public CharBucket(int initialSize) {
            this(new StringWriter(initialSize));
        }

        public CharBucket(StringWriter sw) {
            this.sw = checkNotNull(sw);
        }

        @Override
        public Writer openStream() throws IOException {
            return sw;
        }

        @Override
        public String toString() {
            return sw.toString();
        }
    }

    public static String writeRowMapsWithHeadersToString(Iterable headers, Iterable> rows, String defaultValue, UnknownKeyStrategy unknownKeyStrategy) throws IOException {
        return writeRowMapsToString(headers, true, rows, defaultValue, unknownKeyStrategy);
    }

    public static String writeRowMapsToString(Iterable headers, Iterable> rows, String defaultValue, UnknownKeyStrategy unknownKeyStrategy) throws IOException {
        return writeRowMapsToString(headers, false, rows, defaultValue, unknownKeyStrategy);
    }

    private static String writeRowMapsToString(Iterable headers, boolean includeHeaders, Iterable> rows, String defaultValue, UnknownKeyStrategy unknownKeyStrategy) throws IOException {
        CharBucket bucket = new CharBucket(256);
        writeRowMaps(headers, includeHeaders, rows, defaultValue, unknownKeyStrategy, bucket);
        return bucket.toString();
    }

    /**
     * Creates and returns a converter using the given column names, ignoring unknown keys and using the empty string
     * as the default value.
     * @param columnNames the column names
     * @return the converter
     */
    public Converter> rowToMapConverter(Iterable columnNames) {
        return rowToMapConverter(columnNames, UnknownKeyStrategy.IGNORE, "");
    }

    public Converter> rowToMapConverter(Iterable columnNames, UnknownKeyStrategy unknownKeyStrategy, @Nullable String defaultColumnValue) {
        return new RowToMapConverter(columnNames, unknownKeyStrategy, defaultColumnValue);
    }

    static class RowToMapConverter extends Converter> {

        private final ImmutableList columnNames;
        private final String defaultColumnValue;
        private final UnknownKeyStrategy unknownKeyStrategy;

        public RowToMapConverter(Iterable columnNames, UnknownKeyStrategy unknownKeyStrategy, @Nullable String defaultColumnValue) {
            this.columnNames = ImmutableList.copyOf(columnNames);
            this.unknownKeyStrategy = checkNotNull(unknownKeyStrategy);
            this.defaultColumnValue = defaultColumnValue;
        }

        @Override
        protected ImmutableMap doForward(String[] row) {
            checkArgument(row.length == columnNames.size(), "row incongruent with known headers: %d != %d (%s)", row.length, columnNames.size(), columnNames);
            ImmutableMap.Builder map = ImmutableMap.builder();
            for (int i = 0; i < row.length; i++) {
                map.put(columnNames.get(i), row[i]);
            }
            return map.build();
        }

        @Override
        protected String[] doBackward(Map map) {
            return Csvs.makeRowFromMap(columnNames, map, defaultColumnValue, unknownKeyStrategy);
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy