source: trunk/www/common/plugin/parse_file.jsp @ 7494

Last change on this file since 7494 was 7494, checked in by Nicklas Nordborg, 5 years ago

Merged patch release 3.12.3 to the trunk.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 15.5 KB
Line 
1<%-- $Id: parse_file.jsp 7494 2018-06-04 06:42:46Z 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 pageEncoding="UTF-8" session="false"
27  contentType="text/html; charset=UTF-8" 
28  import="net.sf.basedb.core.SessionControl"
29  import="net.sf.basedb.core.DbControl"
30  import="net.sf.basedb.core.Config"
31  import="net.sf.basedb.core.Item"
32  import="net.sf.basedb.core.File"
33  import="net.sf.basedb.core.Path"
34  import="net.sf.basedb.core.Location"
35  import="net.sf.basedb.core.PluginConfigurationRequest"
36  import="net.sf.basedb.core.plugin.Plugin"
37  import="net.sf.basedb.util.parser.FlatFileParser"
38  import="net.sf.basedb.util.parser.WrappedConfigureByExample"
39  import="net.sf.basedb.clients.web.Base"
40  import="net.sf.basedb.util.Values"
41  import="net.sf.basedb.util.fuzzy.StringMatcher"
42  import="net.sf.basedb.util.fuzzy.StringMatcher.FuzzyMatch"
43  import="net.sf.basedb.clients.web.util.HTML"
44  import="java.util.regex.Pattern"
45  import="java.util.List"
46  import="java.util.ArrayList"
47  import="java.util.Set"
48  import="java.io.InputStream"
49  import="org.json.simple.JSONArray"
50  import="org.json.simple.JSONObject"
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    #fileData td
178    {
179      white-space: nowrap;
180      max-width: 20em;
181      min-width: 4em;
182      overflow: hidden;
183      text-overflow: ellipsis;
184    }
185    #fileData td:first-child
186    {
187      font-weight: bold;
188    }
189    .skipped
190    {
191      padding: 1px 2px 1px 2px;
192      color: #777777;
193      font-style: italic;
194    }
195    </style>
196  </base:head>
197  <base:body>
198  <div class="absolutefull bottomborder">
199
200  <t:tabcontrol 
201    id="parsedFile"
202    subclass="absolutefull dialogtabcontrol"
203    position="top" active="filedata"
204    >
205  <t:tab
206    id="filedata"
207    title="File data"
208    >
209   
210    <%
211    if (file == null)
212    {
213      %>
214      <div class="absolutefull bg-filled-50">
215      <div class="messagecontainer error">
216        No file selected. Please select a file to test above.
217      </div>
218      </div>
219      <%
220    }
221    else
222    {
223      if (messages.size() > 0)
224      {
225        %>
226        <div class="bg-filled-50" style="padding: 5px;">
227        <div class="messagecontainer error" style="margin: 0;">
228        <b>Could not parse the file <code><%=HTML.encodeTags(path)%></code></b>
229        <ol>
230        <li><%=Values.getString(messages, "<li>", true)%>
231        </ol>
232        </div>
233        </div>
234        <%
235      }
236      %>
237      <div class="itemlist" style="<%=messages.size()==0 ? "" : "border-top-width: 1px;"%>">
238        <div class="data">
239        <table style="border: 0;" id="fileData">
240          <thead class="bg-filled-100">
241          <tr>
242            <th>Line</th>
243            <th>Columns</th>
244            <th>Type</th>
245            <th>Use as</th>
246            <th colspan="99">File data</th>
247          </tr>
248          </thead>
249          <tbody class="rows">
250     
251        <%
252        int currentLine = 0;
253        int headerLines = parser.getLineCount();
254        String[] rowclass = new String[] { "bg-oddrow", "bg-evenrow" };
255        int rowClassIndex = 0;
256
257        while (currentLine < maxLines && currentLine < headerLines)
258        {
259          FlatFileParser.Line line = parser.getLine(currentLine);
260          linePatterns.add(Pattern.quote(line.line()));
261          String[] data = null;
262          int numMoreColumns = 0;
263          if (line.type() == FlatFileParser.LineType.HEADER)
264          {
265            data = new String[] { line.name(), line.value() };
266          }
267          else if (splitter != null)
268          {
269            data = parser.trimQuotes(splitter.split(line.line(), 99));
270            if (data.length == 99)
271            {
272              numMoreColumns = splitter.split(line.line()).length - 99;
273            }
274          }
275          else
276          {
277            data = new String[] { line.line() };
278          }
279          %>
280          <tr class="<%=rowclass[rowClassIndex]%> highlight">
281            <td class="cell"><%=line.lineNo()%></td>
282            <td class="cell"><%=data.length+numMoreColumns%></td>
283            <td class="cell"><%=line.type()%></td>
284            <td class="cell">
285              <select class="auto-init" 
286                data-auto-init="line-pattern"
287                data-line-no="<%=currentLine%>">
288              <option value="">
289              <option value="dataHeader">Data header
290              <option value="dataFooter">Data footer
291              </select>
292            </td>
293            <%
294            int colNo = 0;
295            for (String d : data)
296            {
297              %>
298              <td class="cell"><%=HTML.encodeTags(d) %></td>
299              <%
300              colNo++;
301              if (colNo == 99) break;
302            }
303            if (colNo < 99)
304            {
305              %>
306              <td class="cell" colspan="<%=99-colNo%>"></td>
307              <%
308            }
309            %>
310          </tr>
311          <%
312          currentLine++;
313          rowClassIndex = 1 - rowClassIndex;
314        }
315        if (currentLine < maxLines)
316        {
317          if (lastLine == FlatFileParser.LineType.DATA) parser.nextData();
318          while (currentLine < maxLines && parser.hasMoreData())
319          {
320            FlatFileParser.Data data = parser.nextData();
321            linePatterns.add(Pattern.quote(data.line()));
322            if (parser.getNumSkippedLines() > 0)
323            {
324              %>
325              <tr>
326                <td class="skipped bg-filled-100" colspan="103">
327                Skipped <%=parser.getNumSkippedLines()%> lines
328                (<%=parser.getIgnoredLines()%> ignored; <%=parser.getUnknownLines()%> unknown)
329                </td>
330              </tr>
331              <%
332            }
333            %>
334            <tr class="<%=rowclass[rowClassIndex]%> highlight">
335              <td class="cell"><%=data.lineNo()%></td>
336              <td class="cell"><%=data.columns()%></td>
337              <td class="cell">Data</td>
338              <td class="cell">
339                <select class="auto-init" 
340                  data-auto-init="line-pattern"
341                  data-line-no="<%=currentLine%>">
342                <option value="">
343                <option value="dataHeader">Data header
344                <option value="dataFooter">Data footer
345                </select>
346              </td>
347              <%
348              for (int i = 0; i < data.columns() && i < 99; ++i)
349              {
350                %>
351                <td class="cell"><%=HTML.encodeTags(data.get(i))%></td>
352                <%
353              }
354              if (data.columns() < 99)
355              {
356                %>
357                <td class="cell" colspan="<%=99-data.columns()%>"></td>
358                <%
359              }
360              %>
361            </tr>
362            <%
363            currentLine++;
364            rowClassIndex = 1 - rowClassIndex;
365          }
366          if (parser.getNumSkippedLines() > 0)
367          {
368            %>
369            <tr>
370              <td class="error" colspan="99">
371              Skipped <%=parser.getNumSkippedLines()%> lines
372              (<%=parser.getIgnoredLines()%> ignored; <%=parser.getUnknownLines()%> unknown)
373              </td>
374            </tr>
375            <%
376          }
377        }
378        %>
379        </tbody>
380        </table>
381      </div>
382      </div>
383      <%
384    }
385    %>
386    </t:tab>
387
388    <t:tab
389      id="mappings"
390      title="Column mappings"
391      visible="<%=dataIsFound && request.getParameter("mappingParameterNames") != null%>"
392      >
393      <%
394      StringBuilder sb = new StringBuilder();
395      List<String> headers = parser.getColumnHeaders();
396      int index = 0;
397      if (headers != null)
398      {
399        for (String header : headers)
400        {
401          sb.append("<option value=\"" + index + "\">" + HTML.encodeTags(header));
402          index++;
403        }
404      }
405      else
406      {
407        int maxDataColumns = Values.getInt(request.getParameter("maxDataColumns"), -1);
408        while (index < maxDataColumns)
409        {
410          sb.append("<option value=\"" + index + "\">" + index);
411          index++;
412        }
413      }
414      String mappings = sb.toString();
415      String[] mappingParameters = request.getParameter("mappingParameterNames").split(",");
416      if (headers != null)
417      {
418        List<String> labels = new ArrayList<String>();
419        for (String name : mappingParameters)
420        {
421          labels.add(request.getParameter("mapping." + name + ".label"));
422        }
423        StringMatcher sm = new StringMatcher();
424        List<FuzzyMatch> matches = sm.getBestPairs(labels, headers);
425        int i = 0;
426        for (FuzzyMatch fm : matches)
427        {
428          String name = mappingParameters[i];
429          if (fm != null)
430          {
431            JSONObject jsonFuzzyMatch = new JSONObject();
432            jsonFuzzyMatch.put("name", mappingParameters[i]);
433            jsonFuzzyMatch.put("columnIndex", headers.indexOf(fm.getValue()));
434            jsonFuzzyMatch.put("score", fm.getScore());
435            jsonFuzzy.add(jsonFuzzyMatch);
436          }
437          else
438          {
439            jsonFuzzy.add(null);
440          }
441          ++i;
442        }
443      }
444      %>
445      <form name="mappings">
446      <div class="absolutefull bg-filled-100" style="height: 2em;">
447        <table>
448        <tr>
449          <td style="padding-left: 4px;">
450            <b>Mapping style:</b>
451            <input type="radio" name="expressionStyle" id="expressionStyleSimple" value="1" checked><label for="expressionStyleSimple">Simple</label>
452            <input type="radio" name="expressionStyle" id="expressionStyleExpression" value="2"><label for="expressionStyleExpression">Expression</label>
453          </td>
454          <%
455          if (jsonFuzzy.size() > 0)
456          {
457            %>
458            <td style="padding-left: 4px;">
459            <base:button id="btnFuzzyMatches" title="Auto generate" 
460              tooltip="Generate mappings by finding the best match between Property and File column"/>
461            </td>
462            <td style="padding-left: 4px; width: 50%;">
463              Similarity score:
464              <input type="text" id="similarityScore" name="similarity" value="0.85">
465              (0 = bad; 1 = good)
466            </td>
467            <%
468          }
469          %>
470        </tr>
471        </table>
472      </div>
473     
474      <div class="absolutefull input100" style="top: 2em;">
475
476        <tbl:table id="col-mappings">
477          <tbl:columndef 
478            id="property"
479            title="Property"
480          />
481          <tbl:columndef 
482            id="expression"
483            title="Mapping expression"
484          />
485          <tbl:columndef 
486            id="columns"
487            title="File columns"
488          />
489          <tbl:data>
490            <tbl:headers>
491              <tbl:headerrow>
492                <tbl:columnheaders />
493              </tbl:headerrow>
494            </tbl:headers>           
495            <tbl:rows>
496            <%
497            for (String name : mappingParameters)
498            {
499              %>
500              <tbl:row>
501                <tbl:cell column="property"><%=HTML.encodeTags(request.getParameter("mapping." + name + ".label"))%></tbl:cell>
502                <tbl:cell column="expression">
503               
504                    <table style="width: 100%;">
505                    <tr>
506                      <td>
507                      <input type="text" class="text auto-init" data-auto-init="column-mapping"
508                        name="mapping.<%=name%>.expression"
509                        maxlength="80" 
510                        value="<%=HTML.encodeTags(request.getParameter("mapping." + name + ".expression"))%>">
511                      </td>
512                    <td style="width: 22px;">
513                      <base:icon image="cancel.png" subclass="auto-init" id="<%="clear."+name %>"
514                        data-auto-init="column-mapping-clear" data-mapping="<%=name%>"
515                        tooltip="Clear this expression"/>
516                    </td>
517                    </tr>
518                    </table>
519                </tbl:cell>
520               
521                <tbl:cell column="columns">
522                  <select name="list.<%=name%>" class="auto-init"
523                    data-auto-init="column-mapping-preset" data-mapping="<%=name%>">
524                  <option value="">
525                  <%=mappings%>
526                  </select>
527                </tbl:cell>
528             
529              </tbl:row>
530              <%
531            }
532            %>
533            </tbl:rows>
534          </tbl:data>
535        </tbl:table>
536      </div>
537    </form>
538    </t:tab>
539     
540    </t:tabcontrol>
541   
542      <div id="page-data" class="datacontainer"
543        data-line-patterns="<%=HTML.encodeTags(linePatterns.toJSONString())%>"
544        <%
545        if (parser != null && parser.getColumnHeaders() != null)
546        {
547          %>
548          data-column-headers="<%=HTML.encodeTags(JSONArray.toJSONString(parser.getColumnHeaders())) %>"
549          <%
550        }
551        %>
552        data-fuzzy-matches="<%=HTML.encodeTags(jsonFuzzy.toJSONString()) %>"
553        ></div>
554    </div>
555  </base:body>
556  </base:page>
557  <%
558}
559finally
560{
561  if (fileInputStream != null) fileInputStream.close();
562  if (dc != null) dc.close();
563}
564%>
565
Note: See TracBrowser for help on using the repository browser.