source: branches/3.3-stable/www/common/plugin/parse_file.jsp @ 6588

Last change on this file since 6588 was 6588, checked in by Nicklas Nordborg, 8 years ago

Fixes #1882: Test with file dialog should revert to "File data" tab when "Parse the file" is clicked

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 14.9 KB
Line 
1<%-- $Id: parse_file.jsp 6588 2014-11-03 15:12:32Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2006 Johan Enell, Nicklas Nordborg
4  Copyright (C) 2007 Nicklas Nordborg
5
6  This file is part of BASE - BioArray Software Environment.
7  Available at http://base.thep.lu.se/
8
9  BASE is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License
11  as published by the Free Software Foundation; either version 3
12  of the License, or (at your option) any later version.
13
14  BASE is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with BASE. If not, see <http://www.gnu.org/licenses/>.
21  ------------------------------------------------------------------
22
23  @author Nicklas
24  @version 2.0
25--%>
26<%@page import="org.json.simple.JSONObject"%>
27<%@ page pageEncoding="UTF-8" session="false"
28  contentType="text/html; charset=UTF-8" 
29  import="net.sf.basedb.core.SessionControl"
30  import="net.sf.basedb.core.DbControl"
31  import="net.sf.basedb.core.Config"
32  import="net.sf.basedb.core.Item"
33  import="net.sf.basedb.core.File"
34  import="net.sf.basedb.core.Path"
35  import="net.sf.basedb.core.Location"
36  import="net.sf.basedb.core.PluginConfigurationRequest"
37  import="net.sf.basedb.core.plugin.Plugin"
38  import="net.sf.basedb.util.parser.FlatFileParser"
39  import="net.sf.basedb.util.parser.WrappedConfigureByExample"
40  import="net.sf.basedb.clients.web.Base"
41  import="net.sf.basedb.util.Values"
42  import="net.sf.basedb.util.fuzzy.StringMatcher"
43  import="net.sf.basedb.util.fuzzy.StringMatcher.FuzzyMatch"
44  import="net.sf.basedb.clients.web.util.HTML"
45  import="java.util.regex.Pattern"
46  import="java.util.List"
47  import="java.util.ArrayList"
48  import="java.util.Set"
49  import="java.io.InputStream"
50  import="org.json.simple.JSONArray"
51%>
52<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
53<%@ taglib prefix="m" uri="/WEB-INF/menu.tld" %>
54<%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %>
55<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
56
57<%
58request.setCharacterEncoding("UTF-8");
59final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
60final String ID = sc.getId();
61final DbControl dc = sc.newDbControl();
62final float scale = Base.getScale(sc);
63InputStream fileInputStream = null;
64try
65{
66  String path = request.getParameter("path");
67  String charsetName = Values.getString(request.getParameter("charset"), Config.getCharset());
68  PluginConfigurationRequest pcRequest = (PluginConfigurationRequest)sc.getSessionSetting("plugin.configure.request");
69  Plugin plugin = pcRequest.getPlugin();
70 
71  File file = null;
72  FlatFileParser parser = null;
73  FlatFileParser.LineType lastLine = null;
74  Pattern splitter = null;
75  boolean dataIsFound = false;
76  int maxLines = Values.getInt(request.getParameter("maxLines"), FlatFileParser.DEFAULT_MAX_UNKNOWN_LINES);
77 
78  List<String> messages = new ArrayList<String>();
79  JSONArray linePatterns = new JSONArray();
80  JSONArray jsonFuzzy = new JSONArray();
81 
82  if (path != null)
83  {
84    Path p = new Path(path, Path.Type.FILE);
85    file = File.getByPath(dc, p, false);
86    parser = new FlatFileParser();
87    parser.setMaxUnknownLines(maxLines);
88   
89    String header = Values.getStringOrNull(request.getParameter("header"));
90    if (header != null)
91    {
92      try
93      {
94        parser.setHeaderRegexp(Pattern.compile(header));
95      }
96      catch (Throwable t)
97      {
98        messages.add("Invalid regular expression for header: " + HTML.encodeTags(header));
99      }
100    }
101   
102    String dataSplitter = Values.getStringOrNull(request.getParameter("dataSplitter"));
103    if (dataSplitter != null)
104    {
105      try
106      {
107        splitter = Pattern.compile(dataSplitter);
108        parser.setDataSplitterRegexp(splitter);
109      }
110      catch (Throwable t)
111      {
112        messages.add("Invalid regular expression for data splitter: " + HTML.encodeTags(dataSplitter));
113      }
114    }
115
116    String dataHeader = Values.getStringOrNull(request.getParameter("dataHeader"));
117    if (dataHeader != null)
118    {
119      try
120      {
121        parser.setDataHeaderRegexp(Pattern.compile(dataHeader));
122      }
123      catch (Throwable t)
124      {
125        messages.add("Invalid regular expression for data header: " + HTML.encodeTags(dataHeader));
126      }
127    }
128   
129    String dataFooter = Values.getStringOrNull(request.getParameter("dataFooter"));
130    if (dataFooter != null)
131    {
132      try
133      {
134        parser.setDataFooterRegexp(Pattern.compile(dataFooter));
135      }
136      catch (Throwable t)
137      {
138        messages.add("Invalid regular expression for data footer: " + HTML.encodeTags(dataFooter));
139      }
140    }
141   
142    String ignore = Values.getStringOrNull(request.getParameter("ignore"));
143    if (ignore != null)
144    {
145      try
146      {
147        parser.setIgnoreRegexp(Pattern.compile(ignore));
148      }
149      catch (Throwable t)
150      {
151        messages.add("Invalid regular expression for ignore: " + HTML.encodeTags(ignore));
152      }
153    }
154
155    parser.setTrimQuotes(Values.getBoolean(request.getParameter("trimQuotes")));
156    parser.setMinDataColumns(Values.getInt(request.getParameter("minDataColumns"), 0));
157    parser.setMaxDataColumns(Values.getInt(request.getParameter("maxDataColumns"), -1));
158   
159    fileInputStream = file.getDownloadStream(0);
160    if (plugin instanceof WrappedConfigureByExample)
161    {
162      WrappedConfigureByExample wex = (WrappedConfigureByExample)plugin;
163      fileInputStream = wex.wrapInputStream(fileInputStream);
164    }
165    parser.setInputStream(fileInputStream, charsetName);
166    lastLine = parser.parseHeaders();
167    dataIsFound = lastLine == FlatFileParser.LineType.DATA || lastLine == FlatFileParser.LineType.DATA_HEADER;
168    if (!dataIsFound)
169    {
170      messages.add("Start of data couldn't be found. Please try again with different settings.");
171    }
172  }
173  %>
174  <base:page type="iframe" title="Test with file">
175  <base:head scripts="tabcontrol-2.js,~parse_file.js" styles="table.css,tabcontrol.css">
176    <style>
177    table.special
178    {
179      border-collapse: collapse;
180    }
181    table.special > tbody > tr.highlight > td
182    {
183      border-top: 1px solid transparent;
184    }
185    table.special > tbody > tr.highlight:hover > td
186    {
187      background-color: #F8F8E8 !important;
188      border-top: 1px solid #2288AA !important;
189      border-bottom: 1px solid #2288AA !important;
190    }
191    </style>
192  </base:head>
193  <base:body>
194  <div class="absolutefull bottomborder">
195
196  <t:tabcontrol 
197    id="parsedFile"
198    subclass="absolutefull dialogtabcontrol"
199    position="top" active="filedata"
200    >
201  <t:tab
202    id="filedata"
203    title="File data"
204    >
205    <div>
206    <%
207    if (file == null)
208    {
209      %>&nbsp;
210      <div class="messagecontainer error">
211        No file selected. Please select a file to test above.
212      </div>
213      <%
214    }
215    else
216    {
217      if (messages.size() > 0)
218      {
219        %>
220        <div class="messagecontainer error">
221        <b>Could not parse the file <code><%=HTML.encodeTags(path)%></code></b>
222        <ol>
223        <li><%=Values.getString(messages, "<li>", true)%>
224        </ol>
225        </div>
226        <%
227      }
228      %>
229      <div class="itemlist">
230        <div class="data" style="<%=messages.size()==0 ? "border-top: 0;" : ""%>">
231        <table>
232          <thead>
233          <tr>
234            <th>Line</th>
235            <th>Columns</th>
236            <th>Type</th>
237            <th>Use as</th>
238            <th colspan="99">File data</th>
239          </tr>
240          </thead>
241          <tbody class="rows">
242     
243        <%
244        int currentLine = 0;
245        int headerLines = parser.getLineCount();
246        String[] rowclass = new String[] { "oddrow", "evenrow" };
247        int rowClassIndex = 0;
248
249        while (currentLine <= maxLines && currentLine < headerLines)
250        {
251          FlatFileParser.Line line = parser.getLine(currentLine);
252          linePatterns.add(Pattern.quote(line.line()));
253          String[] data = null;
254          if (line.type() == FlatFileParser.LineType.HEADER)
255          {
256            data = new String[] { line.name(), line.value() };
257          }
258          else if (splitter != null)
259          {
260            data = parser.trimQuotes(splitter.split(line.line(), 99));
261          }
262          else
263          {
264            data = new String[] { line.line() };
265          }
266          %>
267          <tr class="<%=rowclass[rowClassIndex]%> highlight">
268            <td class="cell"><%=line.lineNo()%></td>
269            <td class="cell"><%=data.length%></td>
270            <td class="cell"><%=line.type()%></td>
271            <td class="cell">
272              <select class="auto-init" 
273                data-auto-init="line-pattern"
274                data-line-no="<%=currentLine%>">
275              <option value="">
276              <option value="dataHeader">Data header
277              <option value="dataFooter">Data footer
278              </select>
279            </td>
280            <%
281            int colNo = 0;
282            for (String d : data)
283            {
284              %>
285              <td class="cell"><%=HTML.encodeTags(d) %></td>
286              <%
287              colNo++;
288              if (colNo == 99) break;
289            }
290            if (colNo < 99)
291            {
292              %>
293              <td class="cell" colspan="<%=99-colNo%>"></td>
294              <%
295            }
296            %>
297          </tr>
298          <%
299          currentLine++;
300          rowClassIndex = 1 - rowClassIndex;
301        }
302        if (currentLine < maxLines)
303        {
304          if (lastLine == FlatFileParser.LineType.DATA) parser.nextData();
305          while (currentLine <= maxLines && parser.hasMoreData())
306          {
307            FlatFileParser.Data data = parser.nextData();
308            linePatterns.add(Pattern.quote(data.line()));
309            if (parser.getNumSkippedLines() > 0)
310            {
311              %>
312              <tr>
313                <td class="error" colspan="103">
314                Skipped <%=parser.getNumSkippedLines()%> lines
315                (<%=parser.getIgnoredLines()%> ignored; <%=parser.getUnknownLines()%> unknown)
316                </td>
317              </tr>
318              <%
319            }
320            %>
321            <tr class="<%=rowclass[rowClassIndex]%> highlight">
322              <td class="cell"><%=data.lineNo()%></td>
323              <td class="cell"><%=data.columns()%></td>
324              <td class="cell">Data</td>
325              <td class="cell">
326                <select class="auto-init" 
327                  data-auto-init="line-pattern"
328                  data-line-no="<%=currentLine%>">
329                <option value="">
330                <option value="dataHeader">Data header
331                <option value="dataFooter">Data footer
332                </select>
333              </td>
334              <%
335              for (int i = 0; i < data.columns(); ++i)
336              {
337                %>
338                <td class="cell"><%=HTML.encodeTags(data.get(i))%></td>
339                <%
340              }
341              if (data.columns() < 99)
342              {
343                %>
344                <td class="cell" colspan="<%=99-data.columns()%>"></td>
345                <%
346              }
347              %>
348            </tr>
349            <%
350            currentLine++;
351            rowClassIndex = 1 - rowClassIndex;
352          }
353          if (parser.getNumSkippedLines() > 0)
354          {
355            %>
356            <tr>
357              <td class="error" colspan="99">
358              Skipped <%=parser.getNumSkippedLines()%> lines
359              (<%=parser.getIgnoredLines()%> ignored; <%=parser.getUnknownLines()%> unknown)
360              </td>
361            </tr>
362            <%
363          }
364        }
365        %>
366        </tbody>
367        </table>
368      </div>
369      </div>
370      <%
371    }
372    %>
373      </div>
374    </t:tab>
375
376    <t:tab
377      id="mappings"
378      title="Column mappings"
379      visible="<%=dataIsFound && request.getParameter("mappingParameterNames") != null%>"
380      >
381      <%
382      StringBuilder sb = new StringBuilder();
383      List<String> headers = parser.getColumnHeaders();
384      int index = 0;
385      if (headers != null)
386      {
387        for (String header : headers)
388        {
389          sb.append("<option value=\"" + index + "\">" + HTML.encodeTags(header));
390          index++;
391        }
392      }
393      else
394      {
395        int maxDataColumns = Values.getInt(request.getParameter("maxDataColumns"), -1);
396        while (index < maxDataColumns)
397        {
398          sb.append("<option value=\"" + index + "\">" + index);
399          index++;
400        }
401      }
402      String mappings = sb.toString();
403      String[] mappingParameters = request.getParameter("mappingParameterNames").split(",");
404      if (headers != null)
405      {
406        List<String> labels = new ArrayList<String>();
407        for (String name : mappingParameters)
408        {
409          labels.add(request.getParameter("mapping." + name + ".label"));
410        }
411        StringMatcher sm = new StringMatcher();
412        List<FuzzyMatch> matches = sm.getBestPairs(labels, headers);
413        int i = 0;
414        for (FuzzyMatch fm : matches)
415        {
416          String name = mappingParameters[i];
417          if (fm != null)
418          {
419            JSONObject jsonFuzzyMatch = new JSONObject();
420            jsonFuzzyMatch.put("name", mappingParameters[i]);
421            jsonFuzzyMatch.put("columnIndex", headers.indexOf(fm.getValue()));
422            jsonFuzzyMatch.put("score", fm.getScore());
423            jsonFuzzy.add(jsonFuzzyMatch);
424          }
425          else
426          {
427            jsonFuzzy.add(null);
428          }
429          ++i;
430        }
431      }
432      %>
433      <form name="mappings">
434      <div class="absolutefull" style="height: 2em;">
435        <table>
436        <tr>
437          <td style="padding-left: 2px;">
438            <b>Mapping style:</b>
439            <input type="radio" name="expressionStyle" id="expressionStyleSimple" value="1" checked><label for="expressionStyleSimple">Simple</label>
440            <input type="radio" name="expressionStyle" id="expressionStyleExpression" value="2"><label for="expressionStyleExpression">Expression</label>
441          </td>
442          <%
443          if (jsonFuzzy.size() > 0)
444          {
445            %>
446            <td style="padding-left: 4px;">
447            <base:button id="btnFuzzyMatches" title="Auto generate" 
448              tooltip="Generate mappings by finding the best match between Property and File column"/>
449            </td>
450            <td style="padding-left: 4px; width: 50%;">
451              Similarity score:
452              <input type="text" id="similarityScore" name="similarity" value="0.85">
453              (0 = bad; 1 = good)
454            </td>
455            <%
456          }
457          %>
458        </tr>
459        </table>
460      </div>
461     
462      <div class="absolutefull topborder" style="top: 2em;">
463
464        <table class="fullform input100 special larger">
465        <tbody class="sectionheader">
466          <tr>
467            <th class="rightborder">Property</th>
468            <th class="rightborder">Mapping expression</th>
469            <th>File columns</th>
470          </tr>
471        </tbody>
472        <%
473        for (String name : mappingParameters)
474        {
475          %>
476          <tr class="highlight">
477            <th><%=HTML.encodeTags(request.getParameter("mapping." + name + ".label"))%></th>
478            <td>
479              <table style="width: 100%;">
480              <tr>
481                <td>
482                <input type="text" class="text auto-init" data-auto-init="column-mapping"
483                  name="mapping.<%=name%>.expression"
484                  maxlength="80" 
485                  value="<%=HTML.encodeTags(request.getParameter("mapping." + name + ".expression"))%>">
486                </td>
487              <td style="width: 22px;">
488                <base:icon image="cancel.png" subclass="auto-init" id="<%="clear."+name %>"
489                  data-auto-init="column-mapping-clear" data-mapping="<%=name%>"
490                  tooltip="Clear this expression"/>
491              </td>
492              </tr>
493              </table>
494            </td>
495            <td style="width: 15em;">
496              <select name="list.<%=name%>" class="auto-init" 
497                data-auto-init="column-mapping-preset" data-mapping="<%=name%>">
498              <option value="">
499              <%=mappings%>
500              </select>
501            </td>
502          </tr>
503          <%
504        }
505        %>
506        <tr class="dynamic">
507          <th></th>
508          <td></td>
509          <td></td>
510        </tr>
511        </table>
512      </div>
513    </form>
514    </t:tab>
515     
516    </t:tabcontrol>
517   
518      <div id="page-data" class="datacontainer"
519        data-line-patterns="<%=HTML.encodeTags(linePatterns.toJSONString())%>"
520        <%
521        if (parser != null && parser.getColumnHeaders() != null)
522        {
523          %>
524          data-column-headers="<%=HTML.encodeTags(JSONArray.toJSONString(parser.getColumnHeaders())) %>"
525          <%
526        }
527        %>
528        data-fuzzy-matches="<%=HTML.encodeTags(jsonFuzzy.toJSONString()) %>"
529        ></div>
530    </div>
531  </base:body>
532  </base:page>
533  <%
534}
535finally
536{
537  if (fileInputStream != null) fileInputStream.close();
538  if (dc != null) dc.close();
539}
540%>
541
Note: See TracBrowser for help on using the repository browser.