Пример #1
0
 private static void dump(OutputStream out) throws IOException {
   writeLine(out, "=== Fields ===");
   for (String f : new TreeSet<String>(knownFields)) {
     writeLine(out, f);
   }
   for (CsvFormat fmt : new TreeSet<CsvFormat>(knownFormats)) {
     StringBuilder sb = new StringBuilder("=== Mapping ");
     sb.append(fmt.toString()).append(" ===");
     writeLine(out, sb.toString());
     for (CsvColumn col : fmt.columns) {
       if (col.field != null) {
         if (!knownFields.contains(col.field)) {
           LOG.debug("Mapping '%s' references unknown field='%s'\n", fmt.name, col.field);
         }
       }
       writeLine(out, col.toString());
     }
   }
 }
Пример #2
0
  /**
   * @param csv is the list of fields in a record from a CSV file
   * @param formats is the list of CsvFormats to be considered applicable
   * @return a map from field to value
   * @throws ParseException
   */
  private Map<String, String> toContact(List<String> csv, CsvFormat format) throws ParseException {
    ContactMap contactMap = new ContactMap();

    // NOTE: If there isn't a mapping for a field name defined in "format"
    // NOTE: a user defined attribute with that field name will be used.
    if (csv == null) {
      return contactMap.getContacts();
    }
    if (format.allFields()) {
      int end = csv.size();
      end = (end > fieldNames.size()) ? fieldNames.size() : end;
      for (int i = 0; i < end; i++) {
        contactMap.put(fieldNames.get(i), csv.get(i));
      }
    } else if (format.hasNoHeaders()) {
      int end = csv.size();
      end = (end > format.columns.size()) ? format.columns.size() : end;
      for (int i = 0; i < end; i++) {
        contactMap.put(format.columns.get(i).field, csv.get(i));
      }
    } else {
      /* Many CSV formats are output in a specific order and sometimes
       * contain duplicate field names with mappings to different
       * Zimbra contact fields.
       */
      Map<CsvColumn, Map<String, String>> pendMV = new HashMap<CsvColumn, Map<String, String>>();
      List<CsvColumn> unseenColumns = new ArrayList<CsvColumn>();
      unseenColumns.addAll(format.columns);
      for (int ndx = 0; ndx < fieldNames.size(); ndx++) {
        String csvFieldName = fieldNames.get(ndx);
        String fieldValue = (ndx >= csv.size()) ? null : csv.get(ndx);
        CsvColumn matchingCol = null;
        String matchingFieldLc = null;
        for (CsvColumn unseenC : unseenColumns) {
          matchingFieldLc = unseenC.matchingLcCsvFieldName(csvFieldName);
          if (matchingFieldLc == null) {
            continue;
          }
          if (unseenC.colType == ColType.MULTIVALUE) {
            Map<String, String> currMV = pendMV.get(matchingCol);
            if ((currMV != null) && currMV.get(matchingFieldLc) != null) {
              // already have field with this name that matches this column
              continue;
            }
          }
          matchingCol = unseenC;
          break;
        }
        if (matchingCol == null) {
          // unknown field - setup for adding as a user defined attribute
          LOG.debug(
              "Adding CSV contact attribute [%s=%s] - assuming is user defined.",
              csvFieldName, fieldValue);
          contactMap.put(csvFieldName, fieldValue);
          continue;
        }
        switch (matchingCol.colType) {
          case NAME:
            addNameField(fieldValue, matchingCol.field, contactMap);
            unseenColumns.remove(matchingCol);
            break;
          case DATE:
            addDateField(fieldValue, matchingCol.field, format.key(), contactMap);
            unseenColumns.remove(matchingCol);
            break;
          case TAG:
            contactMap.put(TAG, fieldValue);
            break;
          case MULTIVALUE:
            for (String cname : matchingCol.names) {
              if (cname.toLowerCase().equals(matchingFieldLc)) {
                Map<String, String> currMV = pendMV.get(matchingCol);
                if (currMV == null) {
                  currMV = new HashMap<String, String>();
                  pendMV.put(matchingCol, currMV);
                }
                currMV.put(matchingFieldLc, fieldValue);
                if (currMV.size() >= matchingCol.names.size()) {
                  addMultiValueField(matchingCol, currMV, contactMap);
                  pendMV.remove(currMV);
                  unseenColumns.remove(matchingCol);
                }
              }
            }
            break;
          default:
            contactMap.put(matchingCol.field, fieldValue);
            unseenColumns.remove(matchingCol);
        }
      }
      // Process multi-value fields where only some constituent fields were present
      for (Map.Entry<CsvColumn, Map<String, String>> entry : pendMV.entrySet()) {
        addMultiValueField(entry.getKey(), entry.getValue(), contactMap);
      }
    }

    Map<String, String> contact = contactMap.getContacts();

    // Bug 50069 - Lines with single blank in them got imported as a blank contact
    // Initial fix idea was for parseField to return the trimmed version of the string
    // However, this from rfc4180 - Common Format and MIME Type for Comma-Separated
    // Values (CSV) Files :
    //     "Spaces are considered part of a field and should not be ignored."
    // suggests that might be an invalid thing to do, so now just reject the contact
    // if the whole line would collapse to an empty string with trim.
    if (contact.size() == 1) {
      boolean onlyBlank = true;
      for (String val : contact.values()) {
        if (!val.trim().equals("")) {
          onlyBlank = false;
          break;
        }
      }
      if (onlyBlank) contact = new HashMap<String, String>();
    }
    return contact;
  }