other/inca-xml2csv/trunk/src/net/sf/basedb/inca/IncaXml2Csv.java

Code
Comments
Other
Rev Date Author Line
3881 27 Apr 16 nicklas 1 package net.sf.basedb.inca;
3881 27 Apr 16 nicklas 2
3883 27 Apr 16 nicklas 3 import java.io.BufferedReader;
3883 27 Apr 16 nicklas 4 import java.io.Closeable;
3883 27 Apr 16 nicklas 5 import java.io.File;
3883 27 Apr 16 nicklas 6 import java.io.FileInputStream;
3883 27 Apr 16 nicklas 7 import java.io.IOException;
3885 27 Apr 16 nicklas 8 import java.io.InputStream;
3883 27 Apr 16 nicklas 9 import java.io.InputStreamReader;
3887 28 Apr 16 nicklas 10 import java.io.PrintWriter;
7374 06 Oct 23 nicklas 11 import java.util.HashMap;
7060 14 Mar 23 nicklas 12 import java.util.HashSet;
7374 06 Oct 23 nicklas 13 import java.util.Map;
7060 14 Mar 23 nicklas 14 import java.util.Set;
3883 27 Apr 16 nicklas 15
3884 27 Apr 16 nicklas 16 import javax.swing.JFileChooser;
3881 27 Apr 16 nicklas 17 import javax.swing.JOptionPane;
3890 28 Apr 16 nicklas 18 import javax.swing.filechooser.FileFilter;
3884 27 Apr 16 nicklas 19 import javax.swing.filechooser.FileNameExtensionFilter;
3881 27 Apr 16 nicklas 20
3881 27 Apr 16 nicklas 21 /**
3881 27 Apr 16 nicklas 22   Main class for the program.
3881 27 Apr 16 nicklas 23   @since 1.0
3881 27 Apr 16 nicklas 24 */
3881 27 Apr 16 nicklas 25 public class IncaXml2Csv 
3881 27 Apr 16 nicklas 26 {
3881 27 Apr 16 nicklas 27   
3881 27 Apr 16 nicklas 28   /**
3881 27 Apr 16 nicklas 29     The current version of this package.
3881 27 Apr 16 nicklas 30   */
7377 09 Oct 23 nicklas 31   public static final String VERSION = "1.5-dev";
3881 27 Apr 16 nicklas 32
3881 27 Apr 16 nicklas 33   
3881 27 Apr 16 nicklas 34   public static void main(String[] args)
3881 27 Apr 16 nicklas 35   {
3890 28 Apr 16 nicklas 36     File currentDir = new File(".");
3890 28 Apr 16 nicklas 37     
3887 28 Apr 16 nicklas 38     // Select SCANB file - check the command line first
3887 28 Apr 16 nicklas 39     File scanbFile = null;
3884 27 Apr 16 nicklas 40     if (args.length > 0)
3884 27 Apr 16 nicklas 41     {
3884 27 Apr 16 nicklas 42       scanbFile = new File(args[0]);
3884 27 Apr 16 nicklas 43       if (!scanbFile.isFile()) scanbFile = null;
3884 27 Apr 16 nicklas 44     }
3884 27 Apr 16 nicklas 45     if (scanbFile == null)
3884 27 Apr 16 nicklas 46     {
3884 27 Apr 16 nicklas 47       // Open a file selection dialog
3890 28 Apr 16 nicklas 48       scanbFile = selectFile("Select SCANB CSV file to read from", currentDir, new FileNameExtensionFilter("Tab-separated files (*.tsv; *.csv)", "tsv", "csv"));
3884 27 Apr 16 nicklas 49     }
3884 27 Apr 16 nicklas 50     // Exit
3884 27 Apr 16 nicklas 51     if (scanbFile == null) return;
3884 27 Apr 16 nicklas 52     
3890 28 Apr 16 nicklas 53     // Parse the SCANB file
3883 27 Apr 16 nicklas 54     BufferedReader scanbReader = null;
3885 27 Apr 16 nicklas 55     ScanBParser scanbParser = null;
3883 27 Apr 16 nicklas 56     try
3883 27 Apr 16 nicklas 57     {
3883 27 Apr 16 nicklas 58       scanbReader = readerFromFile(scanbFile);
3885 27 Apr 16 nicklas 59       scanbParser = new ScanBParser();
3883 27 Apr 16 nicklas 60       scanbParser.parse(scanbReader, scanbFile.getName());
3890 28 Apr 16 nicklas 61       
3890 28 Apr 16 nicklas 62       System.out.println(scanbFile.getName() + 
3890 28 Apr 16 nicklas 63           ": Parsed " + scanbParser.getParsedLines() + " lines; " + 
3890 28 Apr 16 nicklas 64           scanbParser.getPersonalNumbers() + " unique personal numbers");
3883 27 Apr 16 nicklas 65     }
3883 27 Apr 16 nicklas 66     catch (Exception ex)
3883 27 Apr 16 nicklas 67     {
3883 27 Apr 16 nicklas 68       JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
3887 28 Apr 16 nicklas 69       return;
3883 27 Apr 16 nicklas 70     }
3883 27 Apr 16 nicklas 71     finally
3883 27 Apr 16 nicklas 72     {
3883 27 Apr 16 nicklas 73       close(scanbReader);
3883 27 Apr 16 nicklas 74     }
3885 27 Apr 16 nicklas 75   
3887 28 Apr 16 nicklas 76     // Select INCA XML file - check the command line first
3887 28 Apr 16 nicklas 77     File incaXmlFile = null;
3885 27 Apr 16 nicklas 78     if (args.length > 1)
3885 27 Apr 16 nicklas 79     {
3885 27 Apr 16 nicklas 80       incaXmlFile = new File(args[1]);
3885 27 Apr 16 nicklas 81       if (!incaXmlFile.isFile()) incaXmlFile = null;
3885 27 Apr 16 nicklas 82     }
3885 27 Apr 16 nicklas 83     if (incaXmlFile == null)
3885 27 Apr 16 nicklas 84     {
3885 27 Apr 16 nicklas 85       // Open a file selection dialog
3890 28 Apr 16 nicklas 86       incaXmlFile = selectFile("Select INCA XML file to read from", currentDir, new FileNameExtensionFilter("XML files (*.xml)", "xml"));
3890 28 Apr 16 nicklas 87     }
3890 28 Apr 16 nicklas 88     // Exit
3890 28 Apr 16 nicklas 89     if (incaXmlFile == null) return;
3890 28 Apr 16 nicklas 90
3890 28 Apr 16 nicklas 91     // Select output CSV file - check command line first
3890 28 Apr 16 nicklas 92     File incaCsvFile = null;
3890 28 Apr 16 nicklas 93     if (args.length > 2)
3890 28 Apr 16 nicklas 94     {
3890 28 Apr 16 nicklas 95       incaCsvFile = new File(args[2]);
3890 28 Apr 16 nicklas 96     }
3890 28 Apr 16 nicklas 97     else
3890 28 Apr 16 nicklas 98     {
3890 28 Apr 16 nicklas 99       // Generate default file name derived from the INCA XML file with
3890 28 Apr 16 nicklas 100       // .xml replaced with .csv. The same directory as the SCANB CSV file is used
3890 28 Apr 16 nicklas 101       incaCsvFile = new File(scanbFile.getParentFile(), incaXmlFile.getName().replace(".xml", ".csv"));
3890 28 Apr 16 nicklas 102       
3885 27 Apr 16 nicklas 103       JFileChooser fc = new JFileChooser();
3890 28 Apr 16 nicklas 104       fc.setDialogTitle("Save to CSV");
3890 28 Apr 16 nicklas 105       fc.setCurrentDirectory(incaCsvFile);
3890 28 Apr 16 nicklas 106       fc.setSelectedFile(incaCsvFile);
3890 28 Apr 16 nicklas 107       fc.setFileFilter(new FileNameExtensionFilter("CSV files (*.csv)", "csv"));
3890 28 Apr 16 nicklas 108       fc.showSaveDialog(null);
3890 28 Apr 16 nicklas 109       incaCsvFile = fc.getSelectedFile();
3890 28 Apr 16 nicklas 110       
3890 28 Apr 16 nicklas 111       // Ask for confirmation to overwrite existing file
3890 28 Apr 16 nicklas 112       if (incaCsvFile != null && incaCsvFile.exists())
3890 28 Apr 16 nicklas 113       {
3890 28 Apr 16 nicklas 114         int action = JOptionPane.showConfirmDialog(null, 
3890 28 Apr 16 nicklas 115           incaCsvFile.getName() + " already exists. Overwrite?", 
3890 28 Apr 16 nicklas 116           "File exists!", 
3890 28 Apr 16 nicklas 117           JOptionPane.OK_CANCEL_OPTION);
3890 28 Apr 16 nicklas 118         if (action == JOptionPane.CANCEL_OPTION)
3890 28 Apr 16 nicklas 119         {
3890 28 Apr 16 nicklas 120           // "Cancel" was selected
3890 28 Apr 16 nicklas 121           incaCsvFile = null;
3890 28 Apr 16 nicklas 122         }
3890 28 Apr 16 nicklas 123       }
3885 27 Apr 16 nicklas 124     }
3885 27 Apr 16 nicklas 125     // Exit
3890 28 Apr 16 nicklas 126     if (incaCsvFile == null) return;
7374 06 Oct 23 nicklas 127     Masker dateMasker = new DateMasker();
3891 28 Apr 16 nicklas 128     
4191 31 Oct 16 nicklas 129     Map<String, Masker> blacklist = new HashMap<>();
7374 06 Oct 23 nicklas 130     blacklist.put("PersonalNo", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 131     blacklist.put("PERSNR", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 132     blacklist.put("ENAMN", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 133     blacklist.put("FNAMN", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 134     blacklist.put("FNAMN_ENAMN", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 135     blacklist.put("FODELSEDATUM", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 136     blacklist.put("GADRESS", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 137     blacklist.put("POSTNR_VALUE", ConstMasker.EMPTY_STRING);
3887 28 Apr 16 nicklas 138
4191 31 Oct 16 nicklas 139     // Since 1.1
7374 06 Oct 23 nicklas 140     blacklist.put("Lkf_koden", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 141     blacklist.put("A030PrepNr", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 142     blacklist.put("A090VPrepNr", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 143     blacklist.put("FORSAMLING_VALUE", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 144     blacklist.put("LKF_VALUE", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 145     blacklist.put("PatientOversikt", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 146     blacklist.put("PADRESS_DESCRIPTION", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 147     blacklist.put("R44T139_ID", ConstMasker.EMPTY_STRING);
4191 31 Oct 16 nicklas 148     blacklist.put("AVLIDDAT", dateMasker);
4191 31 Oct 16 nicklas 149     blacklist.put("A080OpDat", dateMasker);
4191 31 Oct 16 nicklas 150
4709 20 Mar 18 nicklas 151     // Since 2.0
7374 06 Oct 23 nicklas 152     blacklist.put("a_pad_diagprepnr", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 153     blacklist.put("a_pad_prepnr", ConstMasker.EMPTY_STRING);
7374 06 Oct 23 nicklas 154     blacklist.put("op_pad_prepnr", ConstMasker.EMPTY_STRING);
4709 20 Mar 18 nicklas 155     blacklist.put("op_kir_dat", dateMasker);
4709 20 Mar 18 nicklas 156     
7374 06 Oct 23 nicklas 157     // In 1.3 we use a whitelist instead of a blacklist
7060 14 Mar 23 nicklas 158     Set<String> whitelist = new HashSet<>();
7060 14 Mar 23 nicklas 159     whitelist.add("PAT_ID");
7060 14 Mar 23 nicklas 160     whitelist.add("a_inr_sjhkod");
7060 14 Mar 23 nicklas 161     
3890 28 Apr 16 nicklas 162     InputStream incaXmlIn = null;
3890 28 Apr 16 nicklas 163     IncaXmlParser incaXmlParser = null;
3887 28 Apr 16 nicklas 164     PrintWriter incaCsvOut = null;
3890 28 Apr 16 nicklas 165     IncaCsvWriter incaCsvWriter = null;
3885 27 Apr 16 nicklas 166     try
3885 27 Apr 16 nicklas 167     {
3890 28 Apr 16 nicklas 168       // Open input and output files
3890 28 Apr 16 nicklas 169       incaXmlIn = new FileInputStream(incaXmlFile);
3890 28 Apr 16 nicklas 170       incaCsvOut = new PrintWriter(incaCsvFile, "UTF-8");
3887 28 Apr 16 nicklas 171       
7374 06 Oct 23 nicklas 172       // Create parser and writer -- since 1.4 we use the blacklist again
7374 06 Oct 23 nicklas 173       // incaCsvWriter = new IncaCsvWriter(incaCsvOut, scanbParser, whitelist);
7374 06 Oct 23 nicklas 174       incaCsvWriter = new IncaCsvWriter(incaCsvOut, scanbParser, blacklist);
3890 28 Apr 16 nicklas 175       incaXmlParser = new IncaXmlParser(incaCsvWriter);
3887 28 Apr 16 nicklas 176
3890 28 Apr 16 nicklas 177       // Parse the XML file and write the CSV file
3890 28 Apr 16 nicklas 178       incaXmlParser.parse(incaXmlIn, incaXmlFile.getName());
3887 28 Apr 16 nicklas 179       
3890 28 Apr 16 nicklas 180       // Hmmm... don't know when this happens instead of an exception...
3887 28 Apr 16 nicklas 181       if (incaCsvOut.checkError())
3887 28 Apr 16 nicklas 182       {
3887 28 Apr 16 nicklas 183         throw new RuntimeException("Unknown error while writing to " + incaCsvFile.getName());
3887 28 Apr 16 nicklas 184       }
3890 28 Apr 16 nicklas 185       
3890 28 Apr 16 nicklas 186       System.out.println(incaXmlFile.getName() + 
3890 28 Apr 16 nicklas 187           ": Parsed " + incaXmlParser.getRows() + " <row> tags; " + 
3890 28 Apr 16 nicklas 188           incaXmlParser.getHeaders() + " variables per <row>");
3890 28 Apr 16 nicklas 189       
3890 28 Apr 16 nicklas 190       System.out.println(incaCsvFile.getName() + 
7060 14 Mar 23 nicklas 191           ": Wrote " + incaCsvWriter.getRows() + " rows ("+incaCsvWriter.getFullRows()+" full; "+incaCsvWriter.getMasked()+" masked); " + 
7060 14 Mar 23 nicklas 192           incaCsvWriter.getColumns() + " columns; "+
7060 14 Mar 23 nicklas 193           "Skipped "+incaCsvWriter.getSkipped() + " rows");
3890 28 Apr 16 nicklas 194       
3890 28 Apr 16 nicklas 195       System.out.println("Completed successfully.");
3885 27 Apr 16 nicklas 196     }
3885 27 Apr 16 nicklas 197     catch (Exception ex)
3885 27 Apr 16 nicklas 198     {
3885 27 Apr 16 nicklas 199       JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
3887 28 Apr 16 nicklas 200       return;
3885 27 Apr 16 nicklas 201     }
3885 27 Apr 16 nicklas 202     finally
3885 27 Apr 16 nicklas 203     {
3890 28 Apr 16 nicklas 204       close(incaXmlIn);
3887 28 Apr 16 nicklas 205       close(incaCsvOut);
3885 27 Apr 16 nicklas 206     }
3885 27 Apr 16 nicklas 207     
3890 28 Apr 16 nicklas 208     if (args.length < 3)
3890 28 Apr 16 nicklas 209     {
3890 28 Apr 16 nicklas 210       // Show a final status dialog if at least one file was selected
3890 28 Apr 16 nicklas 211       String msg = "<html><body style=\"font-weight: normal;\">";
3890 28 Apr 16 nicklas 212       msg += "<b>"+scanbFile.getName()+"</b><br>";
3890 28 Apr 16 nicklas 213       msg += "Parsed " + scanbParser.getParsedLines() + " lines; ";
3890 28 Apr 16 nicklas 214       msg += scanbParser.getPersonalNumbers() + " unique personal numbers";
3890 28 Apr 16 nicklas 215   
3890 28 Apr 16 nicklas 216       msg += "<br><br>";
3890 28 Apr 16 nicklas 217       
3890 28 Apr 16 nicklas 218       msg += "<b>" + incaXmlFile.getName() + "</b><br>";
3890 28 Apr 16 nicklas 219       msg += "Parsed " + incaXmlParser.getRows() + " &lt;row&gt; tags; ";
3890 28 Apr 16 nicklas 220       msg += incaXmlParser.getHeaders() + " variables per &lt;row&gt;";
3890 28 Apr 16 nicklas 221       
3890 28 Apr 16 nicklas 222       msg += "<br><br>";
3890 28 Apr 16 nicklas 223       
3890 28 Apr 16 nicklas 224       msg += "<b>" + incaCsvFile.getName() + "</b><br>";
7060 14 Mar 23 nicklas 225       msg += "Wrote " + incaCsvWriter.getRows() + " rows ("+incaCsvWriter.getFullRows()+" full; "+incaCsvWriter.getMasked()+" masked); ";
7060 14 Mar 23 nicklas 226       msg += incaCsvWriter.getColumns() + " columns; ";
7060 14 Mar 23 nicklas 227       msg += "Skipped "+incaCsvWriter.getSkipped()+" rows";
3890 28 Apr 16 nicklas 228       
3890 28 Apr 16 nicklas 229       msg += "</body></html>";
3890 28 Apr 16 nicklas 230       
3890 28 Apr 16 nicklas 231       JOptionPane.showMessageDialog(null, msg, "Completed successfully", JOptionPane.INFORMATION_MESSAGE);
3890 28 Apr 16 nicklas 232     }
3881 27 Apr 16 nicklas 233   }
3883 27 Apr 16 nicklas 234   
3883 27 Apr 16 nicklas 235   /**
3883 27 Apr 16 nicklas 236     Read from the given file assuming it is a text file in 
3883 27 Apr 16 nicklas 237     UTF-8 encoding.
3883 27 Apr 16 nicklas 238   */
3883 27 Apr 16 nicklas 239   private static BufferedReader readerFromFile(File file)
3883 27 Apr 16 nicklas 240     throws IOException
3883 27 Apr 16 nicklas 241   {
3883 27 Apr 16 nicklas 242     return new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
3883 27 Apr 16 nicklas 243   }
3883 27 Apr 16 nicklas 244   
3883 27 Apr 16 nicklas 245   /**
3883 27 Apr 16 nicklas 246     Close the file ignoring all exceptions.
3883 27 Apr 16 nicklas 247   */
3883 27 Apr 16 nicklas 248   private static void close(Closeable file)
3883 27 Apr 16 nicklas 249   {
3883 27 Apr 16 nicklas 250     if (file == null) return;
3883 27 Apr 16 nicklas 251     try
3883 27 Apr 16 nicklas 252     {
3883 27 Apr 16 nicklas 253       file.close();
3883 27 Apr 16 nicklas 254     }
3883 27 Apr 16 nicklas 255     catch (IOException ex)
3883 27 Apr 16 nicklas 256     {}
3883 27 Apr 16 nicklas 257   }
3883 27 Apr 16 nicklas 258   
3890 28 Apr 16 nicklas 259   private static File selectFile(String title, File currentDirectory, FileFilter fileFilter)
3890 28 Apr 16 nicklas 260   {
3890 28 Apr 16 nicklas 261     // Open a file selection dialog
3890 28 Apr 16 nicklas 262     JFileChooser fc = new JFileChooser();
3890 28 Apr 16 nicklas 263     fc.setDialogTitle(title);
3890 28 Apr 16 nicklas 264     fc.setCurrentDirectory(currentDirectory);
3890 28 Apr 16 nicklas 265     fc.setFileFilter(fileFilter);
3890 28 Apr 16 nicklas 266     fc.showOpenDialog(null);
3890 28 Apr 16 nicklas 267     return fc.getSelectedFile();
3890 28 Apr 16 nicklas 268   }
3890 28 Apr 16 nicklas 269   
3881 27 Apr 16 nicklas 270 }