# Copyright 2011-2014 Splunk, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"): you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from __future__ import absolute_import import csv class DictReader(csv.DictReader, object): """ Splunk multi-value-aware CSV dictionary reader. """ def __init__(self, input_file): super(DictReader, self).__init__( input_file, dialect='splunklib.searchcommands') self.__fieldnames = None self.__mv_fieldnames = None @csv.DictReader.fieldnames.getter def fieldnames(self): if self._fieldnames is None: try: self._fieldnames = self.reader.next() except StopIteration: pass self.line_num = self.reader.line_num self.__mv_fieldnames = [] self.__fieldnames = [] for name in self._fieldnames: if name.startswith('__mv_'): # Store this pair: , __mv_ self.__mv_fieldnames.append((name[len('__mv_'):], name)) else: self.__fieldnames.append(name) return self.__fieldnames def next(self): row = super(DictReader, self).next() self.fieldnames # for side effects for fieldname, mv_fieldname in self.__mv_fieldnames: # Decode, store and then delete all `__mv_` fields in `row` list_value = DictReader._decode_list(row[mv_fieldname]) if list_value is not None: row[fieldname] = list_value if len(list_value) > 1 else list[0] del row[mv_fieldname] return row @staticmethod def _decode_list(mv): if len(mv) == 0: return None in_value = False value = '' i = 0 l = [] while i < len(mv): if not in_value: if mv[i] == '$': in_value = True elif mv[i] != ';': return None else: if mv[i] == '$' and i + 1 < len(mv) and mv[i + 1] == '$': value += '$' i += 1 elif mv[i] == '$': in_value = False l.append(value) value = '' else: value += mv[i] i += 1 return l