Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.gml / src / main / java / org / gvsig / fmap / dal / store / gml / virtualrows / XMLFileAsList.java @ 47655

History | View | Annotate | Download (32.1 KB)

1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package org.gvsig.fmap.dal.store.gml.virtualrows;
7

    
8
import java.io.BufferedReader;
9
import java.io.Closeable;
10
import java.io.File;
11
import java.io.IOException;
12
import java.io.Reader;
13
import java.nio.ByteBuffer;
14
import java.nio.CharBuffer;
15
import java.nio.charset.Charset;
16
import java.nio.charset.StandardCharsets;
17
import java.util.AbstractList;
18
import java.util.ArrayList;
19
import java.util.HashMap;
20
import java.util.List;
21
import java.util.Map;
22
import java.util.Objects;
23
import javax.xml.parsers.SAXParser;
24
import javax.xml.parsers.SAXParserFactory;
25
import org.apache.commons.collections4.CollectionUtils;
26
import org.apache.commons.io.FilenameUtils;
27
import org.apache.commons.io.IOUtils;
28
import org.apache.commons.io.input.CloseShieldReader;
29
import org.apache.commons.lang3.StringUtils;
30
import org.gvsig.fmap.dal.store.simplereader.virtualrows.LimitedReader;
31
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RandomAccessFileReader;
32
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile;
33
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile.Record;
34
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile.RecordType;
35
import static org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFile.RecordTypeBuilder.recordTypeBuilder;
36
import org.gvsig.fmap.dal.store.simplereader.virtualrows.RecordsFileImpl;
37
import org.gvsig.fmap.geom.Geometry;
38
import org.gvsig.fmap.geom.GeometryLocator;
39
import org.gvsig.tools.ToolsLocator;
40
import org.gvsig.tools.i18n.I18nManager;
41
import org.gvsig.tools.library.impl.DefaultLibrariesInitializer;
42
import org.gvsig.tools.task.SimpleTaskStatus;
43
import org.gvsig.tools.task.UserCancelTaskException;
44
import org.gvsig.tools.util.GetItemWithSize64;
45
import org.xml.sax.Attributes;
46
import org.xml.sax.InputSource;
47
import org.xml.sax.Locator;
48
import org.xml.sax.SAXException;
49
import org.xml.sax.helpers.DefaultHandler;
50

    
51
/**
52
 *
53
 * @author jjdelcerro
54
 */
55
@SuppressWarnings("UseSpecificCatch")
56
public class XMLFileAsList
57
        extends AbstractList<List<String>>
58
        implements Closeable, GetItemWithSize64<List<String>> {
59
    
60
    public static final int COMBINE_NONE = 0;
61
    public static final int COMBINE_FIRST_NOT_NULL = 1;
62

    
63
    private static final int IDXFIELD_BEGINLINE = 0; //INTEGER
64
    private static final int IDXFIELD_BEGINCOLUMN = 1; //INTEGER
65
    private static final int IDXFIELD_BEGINRECORDPOS = 2; //LONG
66
    private static final int IDXFIELD_ENDLINE = 3; //INTEGER
67
    private static final int IDXFIELD_ENDCOLUMN = 4; //INTEGER
68
    
69
    private static final int IDXFIELD_BEGINGEOMLINE = 5; //INTEGER
70
    private static final int IDXFIELD_BEGINGEOMCOLUMN = 6; //INTEGER
71
    private static final int IDXFIELD_BEGINGEOMPOS = 7; //LONG
72
    private static final int IDXFIELD_ENDGEOMLINE = 8; //INTEGER
73
    private static final int IDXFIELD_ENDGEOMCOLUMN = 9; //INTEGER
74
    private static final int IDXFIELD_ENDGEOMPOS = 10; //LONG
75

    
76
            
77
    private final RandomAccessFileReader reader;
78
    private final String recordPath;
79
    private RecordsFile index;
80
    private List<String> fieldPaths;
81
    private final List<String> geomPaths;
82
    private int combineMode;
83

    
84
    
85
    //                                                         ruta   recordnum                       ruta   recordnum
86
 // public XMLFileAsList(File text, Charset charset, List<Pair<String,Integer>> recordPath, List<Pair<String,Integer>> fieldPaths) throws IOException {
87
    public XMLFileAsList(File text, Charset charset, String recordPath, List<String> geomPath, List<String> fieldPaths) throws IOException {
88
        this.reader = new RandomAccessFileReader(text, charset);
89
        this.index = null;
90
        this.recordPath = recordPath;
91
        this.geomPaths = geomPath;
92
        this.fieldPaths = fieldPaths;
93
    }
94

    
95
//    public XMLFileAsList(File text, File index, Charset charset, String recordPath, List<String> geomPath, List<String> fieldPaths, SimpleTaskStatus status) throws IOException {
96
//        this.reader = new RandomAccessFileReader(text, charset);
97
//        this.recordPath = recordPath;
98
//        this.geomPaths = geomPath;
99
//        this.fieldPaths = fieldPaths;
100
//        if (index.exists()) {
101
//            // TODO: Force to create index if text newer than index
102
//            this.index = new RecordsFileImpl(index);
103
//        } else {
104
//            this.createIndex(index, status);
105
//        }
106
//    }
107

    
108
    public XMLFileAsList(RandomAccessFileReader reader, RecordsFile index, String recordPath, List<String> geomPath, List<String> fieldPaths) throws IOException {
109
        this.reader = reader;
110
        this.index = index;
111
        this.recordPath = recordPath;
112
        this.geomPaths = geomPath;
113
        this.fieldPaths = fieldPaths;
114
    }
115

    
116
    @Override
117
    public void close() {
118
        IOUtils.closeQuietly(this.reader);
119
        IOUtils.closeQuietly(this.index);
120
    }
121

    
122
    private List<String> getRecord(long position, List<String> fieldPaths) {
123
        class StopParserSAXException extends SAXException {
124
        }
125

    
126
        class ParseRecordsHandler extends DefaultHandler {
127

    
128
            Locator locator;
129
            List<String> path = new ArrayList<>();
130
            Map<String, String> record = new HashMap<>();
131
            StringBuilder value = new StringBuilder();
132
            List<String> values = new ArrayList<>();
133
            private int endLineNumber;
134
            private int endColumnNumber;
135

    
136
            @Override
137
            public void setDocumentLocator(Locator locator) {
138
                this.locator = locator;
139
            }
140

    
141
            @Override
142
            public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
143
                localName = removeNamespace(qName);
144
                path.add(localName);
145
                String path_s = StringUtils.join(path, "/");
146
                if (StringUtils.equalsIgnoreCase(path_s, recordPath)) {
147
                    return;
148
                }
149
                this.value.setLength(0);
150
                for (int i = 0; i < attributes.getLength(); i++) {
151
                    String attrPath = path_s+"/"+removeNamespace(attributes.getQName(i));
152
                    for (String fieldPath : fieldPaths) {
153
                        if (StringUtils.equalsIgnoreCase(attrPath, fieldPath)) {
154
                            record.put(fieldPath, attributes.getValue(i));
155
                            // No break to handle repeated columns
156
                        }
157
                    }
158
                }
159
            }
160

    
161
            @Override
162
            public void characters(char[] ch, int start, int length) throws SAXException {
163
                value.append(new String(ch, start, length));
164
            }
165

    
166
            private String removeNamespace(String s){
167
                if(s.indexOf(':') < 0){
168
                    return s;
169
                }
170
                String[] ss = s.split(":");
171
                return ss[1];
172
            }
173
            
174
            @Override
175
            public void endElement(String uri, String localName, String qName) throws SAXException {
176
                localName = removeNamespace(qName);
177
                String path_s = StringUtils.join(path, "/");
178

    
179
                for (String fieldPath : fieldPaths) {
180
                    if (StringUtils.equalsIgnoreCase(path_s, fieldPath)) {
181
                        record.put(fieldPath, this.value.toString());
182
                        // No break to handle repeated columns
183
                    }
184
                }
185

    
186
                if (this.locator.getLineNumber() >= this.endLineNumber
187
                        && this.locator.getColumnNumber() >= this.endColumnNumber) {
188
                    for (String fieldPath : fieldPaths) {
189
                        values.add(record.get(fieldPath));
190
                    }
191
                    throw new StopParserSAXException();
192
                }
193

    
194
                path.remove(path.size() - 1);
195
            }
196
        }
197

    
198
//        System.out.println("RECORD "+position);
199
        ParseRecordsHandler handler = null;
200
        Record record = this.index.get64(position);
201
        try {
202
            long recordPosition = record.getLong(IDXFIELD_BEGINRECORDPOS);
203
            this.reader.seek(recordPosition);
204
            // TODO: guardarse el tama?o del registro en el indice y en funcion de eso usar un buffersize mas peque?o aqui si procede
205
            int bufferSize = 1024*8; 
206
            BufferedReader breader = new BufferedReader(this.reader, bufferSize);
207

    
208
            InputSource is = new InputSource(CloseShieldReader.wrap(breader));
209
            SAXParserFactory spf = SAXParserFactory.newInstance();
210
            spf.setNamespaceAware(false);
211
            SAXParser saxParser = spf.newSAXParser();
212
            handler = new ParseRecordsHandler();
213
            handler.endLineNumber=(int) (record.getInt(IDXFIELD_ENDLINE)-record.getInt(IDXFIELD_BEGINLINE)+1);
214
            handler.endColumnNumber=(int) record.getInt(IDXFIELD_ENDCOLUMN);
215

    
216
            saxParser.parse(is, handler);
217
        } catch (StopParserSAXException ex) {
218
            //Do nothing
219
        } catch (Exception ex) {
220
            throw new RuntimeException("Can't parse record " + position, ex);
221
        }
222
        if (handler == null) {
223
            return null;
224
        }
225
        try {
226
            Geometry geom = null;
227
            if(CollectionUtils.isNotEmpty(this.geomPaths)) {
228
                for (int i = 0; i < this.geomPaths.size(); i++) {
229
                    long geomPosition = record.getLong(IDXFIELD_BEGINGEOMPOS+i*6);
230
                    long endGeomPosition = record.getLong(IDXFIELD_ENDGEOMPOS+i*6);
231
                    if(geomPosition == 0 || endGeomPosition == 0){
232
                        if(this.combineMode != COMBINE_FIRST_NOT_NULL){
233
                            handler.values.add(null);
234
                        }
235
                        continue;
236
                    }
237
                    this.reader.seek(geomPosition);
238
                    if(position == 0){
239
                        char[] cbuff = new char[(int)(endGeomPosition-geomPosition)];
240
                        this.reader.read(cbuff);
241
//                        System.out.println("["+new String(cbuff)+"]");
242
                        this.reader.seek(geomPosition);
243
                    }
244
                    Reader limitedReader = new LimitedReader(reader, (int)(endGeomPosition-geomPosition));
245
                    // TODO: calcular el buffersize como el min(8k,endGeomPosition-geomPosition+1)
246
                    int bufferSize = 1024*8; 
247
                    BufferedReader breader = new BufferedReader(limitedReader, bufferSize);
248
                    geom = GeometryLocator.getGeometryManager().createFrom(breader, null);
249
                    if(this.combineMode == COMBINE_FIRST_NOT_NULL){
250
                        if(geom != null){
251
                            handler.values.add(geom.convertToHexWKB());
252
                            break;
253
                        }
254
                    } else {
255
                        handler.values.add(geom.convertToHexWKB());
256
                    }
257
                }
258
                if(this.combineMode == COMBINE_FIRST_NOT_NULL && geom == null){
259
                    handler.values.add(null);
260
                }
261
            }
262
            
263
        } catch (Exception ex) {
264
            throw new RuntimeException("Can't parse record " + position, ex);
265
        }
266
        return handler.values;
267
    }
268

    
269
    @Override
270
    public List<String> get(int index) {
271
        return this.getRecord(index, fieldPaths);
272
    }
273

    
274
    @Override
275
    public List<String> get64(long position) {
276
        return this.getRecord(position, fieldPaths);
277
    }
278

    
279
    @Override
280
    public int size() {
281
        return this.index.size();
282
    }
283

    
284
    @Override
285
    public long size64() {
286
        return this.index.size64();
287
    }
288

    
289
    public int getCombineMode() {
290
        return combineMode;
291
    }
292
    
293
    public void setCombineMode(int combineMode) {
294
        this.combineMode = combineMode;
295
    }
296
    
297
    final public void createIndex(File indexFile, SimpleTaskStatus status) throws IOException {
298
        try {
299
            // 1. Creamos el indice vacio
300
            RecordsFile.RecordTypeBuilder builder = recordTypeBuilder()
301
                    .addInteger()
302
                    .addInteger()
303
                    .addLong()
304
                    .addInteger()
305
                    .addInteger();
306

    
307
            if (CollectionUtils.isNotEmpty(geomPaths)) {
308
                for (int i = 0; i < geomPaths.size(); i++) {
309
                    builder.addInteger()
310
                            .addInteger()
311
                            .addLong()
312
                            .addInteger()
313
                            .addInteger()
314
                            .addLong();
315
                }
316
            }
317
            RecordType recordType = builder.build();
318
            Record record = recordType.createRecord();
319
            final RecordsFile theIndex = new RecordsFileImpl();
320
            theIndex.create(indexFile, recordType);
321

    
322
            // 2. Rellenamos los campos numero de linea y columna de cada registro 
323
            //    en el indice.
324
            // Para ello nos recorremos el XML y vamos escribiendo en el indice.
325
            this.reader.rewind();
326
            InputSource is = new InputSource(CloseShieldReader.wrap(reader));
327
            SAXParserFactory spf = SAXParserFactory.newInstance();
328
            spf.setNamespaceAware(true);
329
            SAXParser saxParser = spf.newSAXParser();
330
            
331
            if (status != null) {
332
                I18nManager i18n = ToolsLocator.getI18nManager();
333
                status.push();
334
                status.message(i18n.getTranslation("_Creating_the_index_of_the_lines"));
335
                status.setIndeterminate();
336
            }
337

    
338
            List<String> path = new ArrayList<>();
339
            // TODO: Aqui habria que quedarse con la primera aparicion de
340
            // los campos solicitados que no pertenezcan al registro principal.
341
            // Probablemente habria que guardar esos valores en disco junto al
342
            // fichero de indice.
343
            saxParser.parse(is, new DefaultHandler() {
344
                Locator locator;
345
                private int beginLineNumber;
346
                private int beginColumnNumber;
347
                private int lastTagLineNumber;
348
                private int lastTagColumnNumber;
349

    
350
                @Override
351
                public void setDocumentLocator(Locator locator) {
352
                    this.locator = locator;
353
                }
354

    
355
                @Override
356
                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
357
                    path.add(localName);
358
                    String path_s = StringUtils.join(path, "/");
359

    
360
                    if (StringUtils.equalsIgnoreCase(path_s, recordPath)) {
361
                        record.setInt(IDXFIELD_BEGINLINE, locator.getLineNumber());
362
                        record.setInt(IDXFIELD_BEGINCOLUMN, locator.getColumnNumber());
363
                        record.setInt(IDXFIELD_ENDLINE, 0);
364
                        record.setInt(IDXFIELD_ENDCOLUMN, 0);
365
                        if (CollectionUtils.isNotEmpty(geomPaths)) {
366
                            for (int i = 0; i < geomPaths.size(); i++) {
367
                                record.setInt(IDXFIELD_BEGINGEOMLINE + 6 * i, 0);
368
                                record.setInt(IDXFIELD_BEGINGEOMCOLUMN + 6 * i, 0);
369
                                record.setLong(IDXFIELD_BEGINGEOMPOS + 6 * i, 0);
370
                                record.setInt(IDXFIELD_ENDGEOMLINE + 6 * i, 0);
371
                                record.setInt(IDXFIELD_ENDGEOMCOLUMN + 6 * i, 0);
372
                                record.setLong(IDXFIELD_ENDGEOMPOS + 6 * i, 0);
373
                            }
374
                        }
375
                        this.beginLineNumber = locator.getLineNumber();
376
                        this.beginColumnNumber = locator.getColumnNumber();
377
                    }
378
                    if (CollectionUtils.isNotEmpty(geomPaths)) {
379
                        for (int i = 0; i < geomPaths.size(); i++) {
380
                            String geomPath = geomPaths.get(i);
381
                            if (StringUtils.equalsIgnoreCase(path_s, recordPath + "/" + geomPath)) {
382
                                record.setInt(IDXFIELD_BEGINGEOMLINE + 6 * i, locator.getLineNumber());
383
                                record.setInt(IDXFIELD_BEGINGEOMCOLUMN + 6 * i, locator.getColumnNumber());
384
                                record.setLong(IDXFIELD_BEGINGEOMPOS + 6 * i, 0);
385
                                break;
386
                            }
387
                        }
388
                    }
389
                    if (status != null) {
390
                        if (status.isCancellationRequested()) {
391
                            throw new UserCancelTaskException();
392
                        }
393
                    }
394
                }
395

    
396
                @Override
397
                public void endElement(String uri, String localName, String qName) throws SAXException {
398
                    String path_s = StringUtils.join(path, "/");
399

    
400
                    if (StringUtils.equalsIgnoreCase(path_s, recordPath)) {
401
                        int line = lastTagLineNumber;//-this.beginLineNumber;
402
                        int column = this.lastTagColumnNumber;
403
                        if (line == 0) {
404
                            column = column - this.beginColumnNumber;
405
                        }
406
                        record.setInt(IDXFIELD_ENDLINE, line);
407
                        record.setInt(IDXFIELD_ENDCOLUMN, column);
408
                        theIndex.add(record);
409
                    }
410
                    if (CollectionUtils.isNotEmpty(geomPaths)) {
411
                        for (int i = 0; i < geomPaths.size(); i++) {
412
                            String geomPath = geomPaths.get(i);
413
                            if (StringUtils.equalsIgnoreCase(path_s, recordPath + "/" + geomPath)) {
414
                                record.setInt(IDXFIELD_ENDGEOMLINE + 6 * i, this.lastTagLineNumber);
415
                                record.setInt(IDXFIELD_ENDGEOMCOLUMN + 6 * i, this.lastTagColumnNumber);
416
                                break;
417
                            }
418
                        }
419
                    }
420
                    this.lastTagLineNumber = locator.getLineNumber();
421
                    this.lastTagColumnNumber = locator.getColumnNumber();
422
                    path.remove(path.size() - 1);
423

    
424
                    if (status != null) {
425
                        if (status.isCancellationRequested()) {
426
                            throw new UserCancelTaskException();
427
                        }
428
                    }
429

    
430
                }
431
            });
432
            if (status != null) {
433
                status.setRangeOfValues(0, theIndex.size64());
434
                status.setCurValue(0);
435
            }
436

    
437
            // 3. Nos recorremos el indice y calculamos la posicion de la linea
438
            //    para cada registro.
439
            this.reader.rewind();
440
            PositionCalculator positionCalculator = new PositionCalculator(reader);
441

    
442
            for (int j = 0; j < theIndex.size(); j++) {
443
                Record r = theIndex.get(j);
444
//                if(i==0){
445
//                    System.out.println("RECO BEGIN: "+r.getLong(IDXFIELD_BEGINLINE) + " " + r.getLong(IDXFIELD_BEGINCOLUMN));
446
//                    if(CollectionUtils.isNotEmpty(geomPaths)) {
447
//                        for (int i = 0; i < geomPaths.size(); i++) {
448
//                            System.out.println("GEOM"+i+"BEGIN: "+r.getLong(IDXFIELD_BEGINGEOMLINE+i*6) + " " + r.getLong(IDXFIELD_BEGINGEOMCOLUMN+i*6));
449
//                            System.out.println("GEOM"+i+"END  : "+r.getLong(IDXFIELD_ENDGEOMLINE+i*6) + " " +  r.getLong(IDXFIELD_ENDGEOMCOLUMN+i*6));
450
//                        }
451
//                    }
452
//                    System.out.println("RECO END  : "+r.getLong(IDXFIELD_ENDLINE) + " " +  r.getLong(IDXFIELD_ENDCOLUMN));
453
//                }
454
                positionCalculator.next(r.getInt(IDXFIELD_BEGINLINE), r.getInt(IDXFIELD_BEGINCOLUMN));
455
                r.setLong(IDXFIELD_BEGINRECORDPOS, positionCalculator.getColumnPosition());
456
//                System.out.println("RPOS      : " + r.getLong(IDXFIELD_BEGINRECORDPOS));
457
                if(CollectionUtils.isNotEmpty(geomPaths)) {
458
                    for (int i = 0; i < geomPaths.size(); i++) {
459
                        long beginGeomLine = r.getInt(IDXFIELD_BEGINGEOMLINE + i * 6);
460
                        long endGeomLine = r.getInt(IDXFIELD_ENDGEOMLINE + i * 6);
461
                        if (beginGeomLine == 0 || endGeomLine == 0) {
462
                            continue;
463
                        }
464
                        positionCalculator.next(beginGeomLine, r.getInt(IDXFIELD_BEGINGEOMCOLUMN + i * 6));
465
                        r.setLong(IDXFIELD_BEGINGEOMPOS + i * 6, positionCalculator.getColumnPosition());
466
                        positionCalculator.next(endGeomLine, r.getInt(IDXFIELD_ENDGEOMCOLUMN + i * 6));
467
                        r.setLong(IDXFIELD_ENDGEOMPOS + i * 6, positionCalculator.getColumnPosition());
468
//                        System.out.println("GPOS" + i + "     : " + r.getLong(IDXFIELD_BEGINGEOMPOS + i * 6) + " " + r.getLong(IDXFIELD_ENDGEOMPOS + i * 6));
469
                    }
470
                }
471
                theIndex.set(j, r);
472
                if (status != null) {
473
                    if (status.isCancellationRequested()) {
474
                        status.cancel();
475
                        removeIndex(indexFile);
476
                        return;
477
                    }
478
                    status.incrementCurrentValue();
479
                }
480

    
481
            }
482
            this.index = new RecordsFileImpl(indexFile);
483
            if (status != null) {
484
                status.terminate();
485
            }
486
        } catch (UserCancelTaskException ex) {
487
            if (status != null) {
488
                if (status.isCancellationRequested()) {
489
                    status.cancel();
490
                }
491
            }
492
            removeIndex(indexFile);
493
            throw ex;
494
        } catch (Exception ex) {
495
            if (status != null) {
496
                status.abort();
497
            }
498
            removeIndex(indexFile);
499
            throw new IOException("Can't create index " + Objects.toString(indexFile), ex);
500
        } finally {
501
            if (status != null) {
502
                status.pop();
503
            }
504
        }
505
    }
506
    
507
    private void removeIndex(File indexFile) {
508
        indexFile.delete();
509
    }
510

    
511
    private static class CharacterSize {
512

    
513
        private final Charset charset;
514
        private final CharBuffer charBuffer;
515

    
516
        public CharacterSize(Charset charset) {
517
            this.charset = charset;
518
            this.charBuffer = CharBuffer.allocate(1);
519
        }
520

    
521
        public int size(char ch) {
522
            this.charBuffer.put(0, ch);
523
            this.charBuffer.position(0);
524
            ByteBuffer buffer = this.charset.encode(this.charBuffer);
525
            return buffer.limit();
526
        }
527

    
528
        public int size(char[] cbuf, int off, int len) {
529
            CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
530
            ByteBuffer byteBuffer = this.charset.encode(cb);
531
            return byteBuffer.limit();
532
        }
533

    
534
        public int size(char[] cbuf) {
535
            CharBuffer cb = CharBuffer.wrap(cbuf, 0, cbuf.length);
536
            ByteBuffer byteBuffer = this.charset.encode(cb);
537
            return byteBuffer.limit();
538
        }
539

    
540
        public int size(String s) {
541
            CharBuffer cb = CharBuffer.wrap(s);
542
            ByteBuffer byteBuffer = this.charset.encode(cb);
543
            return byteBuffer.limit();
544
        }
545
    }
546

    
547
    private static class PositionCalculator {
548

    
549
        private final RandomAccessFileReader reader;
550
        private final BufferedReader breader;
551
        private long currentPosition;
552
        private long currentColumn;
553
        private long currentLine;
554
        private long currentColumnPosition;
555
        private long currentLinePosition;
556

    
557
        private final char[] ch;
558
        private final CharacterSize characterSize;
559

    
560
        public PositionCalculator(RandomAccessFileReader reader) {
561
            this.reader = reader;
562
            this.breader = new BufferedReader(this.reader, 1024 * 8);
563
            this.currentPosition = this.reader.getCurrentPosition();
564
            this.currentLine = 1;
565
            this.currentColumn = 1;
566
            this.ch = new char[1];
567
            this.characterSize = new CharacterSize(this.reader.getCharset());
568
        }
569

    
570
        public boolean next(long line, long column) throws IOException {
571
//            System.out.println();
572
//            System.out.println("----"+line+" "+column);
573
            if(this.currentLine>line){
574
                throw new IOException("Illegal column number " + column + " ("+this.currentColumn+") for line " + line+ " ("+this.currentLine+")");
575
            }
576
            if(this.currentLine==line && this.currentColumn > column){
577
                throw new IOException("Illegal column number " + column + " ("+this.currentColumn+") for line " + line);
578
            }
579
//            System.out.print(this.currentLine+":");
580
            while (this.currentLine < line) {
581
                if (breader.read(this.ch, 0, 1) < 1) {
582
                    return false;
583
                }
584
                char c = ch[0];
585
//                System.out.print(String.valueOf(c));
586
                this.currentPosition += characterSize.size(c);
587
                if (c == '\n') {
588
                    this.currentLine++;
589
                    this.currentColumn = 1;
590
//                    System.out.print(this.currentLine+":");
591
                }
592
            }
593
            this.currentLinePosition = this.currentPosition;
594
            while (true) {
595
                if (breader.read(this.ch, 0, 1) < 1) {
596
                    return false;
597
                }
598
                char c = ch[0];
599
//                System.out.print(String.valueOf(c));
600
                this.currentColumn++;
601
                this.currentPosition += characterSize.size(c);
602
                if(this.currentColumn >= column){
603
                    break;
604
                }
605
                if (c == '\n') {
606
                    throw new IOException("Illegal column number " + column + " ("+this.currentColumn+") for line " + line+ " ("+this.currentLine+")");
607
                }
608
            }
609
            this.currentColumnPosition = this.currentPosition;
610
//            System.out.println();
611
            return true;
612
        }
613

    
614
        public long getLinePosition() {
615
            return this.currentLinePosition;
616
        }
617

    
618
        public long getColumnPosition() {
619
            return this.currentColumnPosition;
620
        }
621

    
622
    }
623

    
624
    public static void main(String[] args) throws Exception {
625
        new DefaultLibrariesInitializer().fullInitialize();
626

    
627
//        final String XMLFILE1 = "/home/jjdelcerro/datos/geodata/vector/gml/navarra.gml";
628
//        final String XMLFILE2 = "/home/jjdelcerro/datos/geodata/vector/gml/Municipis/Municipis.gml";
629
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/1075305YJ2717N.gml";
630
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/Recinto.gml";
631
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/FG-GML-543863-AdmBdry-20190101-0001.gml";
632
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/Municipis.gml";
633
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/navarra.gml";
634
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/Falls.gml";
635
        
636
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/AerodromeArea.gml";
637
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/AerodromeType.gml"; //No tiene geometr?as
638
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/BuildingP.gml";
639
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/CablewayLink.gml";
640
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/ConditionOfFacility.gml"; //No tiene geometr?as
641
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/CrossingS.gml";
642
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/CrossingP.gml";
643
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/DamOrWeirL.gml";
644
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/EmbankmentL.gml";
645
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/EmbankmentS.gml";
646
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/FordP.gml";
647
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/FormOfWay.gml";
648
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/FunctionalRoadClass.gml"; //No tiene geometr?as
649
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/INSPIRE_GN.gml";
650
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/INSPIRE_AU.gml"; //Hay 3 geometr?as, LineString, Surface y MultiSurface
651
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RunwayArea.gml";
652
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayStationArea.gml";
653
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/DamOrWeirS.gml";
654
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/NominalTrackGauge.gml"; //No tiene geometr?as
655
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/NumberOfTracks.gml"; //No tiene geometr?as
656
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/Road.gml"; //No tiene geometr?as
657
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadServiceType.gml"; //No tiene geometr?as
658
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayArea.gml";
659
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayElectrification.gml"; //No tiene geometr?as
660
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayType.gml"; //No tiene geometr?as
661
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayLink.gml"; //Added Multicurve Strategy (ojo, en los registros, tras la geometr?a aparece otro atributo a null
662
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RailwayYardArea.gml";
663
        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadArea.gml"; //NO VA
664
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadLink.gml"; //Hay 2 geometr?as, Curve y Multicurve
665
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadServiceArea.gml";
666
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadSurfaceCategory.gml"; //No tiene geometr?as
667
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/RoadWidth.gml"; //No tiene geometr?as
668
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/ShorelineConstructionL.gml";
669
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/StandingWater.gml";
670
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/SurfaceComposition.gml";
671
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/VerticalPosition.gml"; //No tiene geometr?as
672
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/Watercourse.gml"; //Hay 2 geometr?as, Curve y Multicurve
673
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/WatercourseLink.gml";
674
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/WatercourseLinkSequence.gml"; //No tiene geometr?as
675
//        final String XMLFILE1 = "/home/fdiaz/projects/GMLS/sk/Wetland.gml";
676

    
677
        
678

    
679

    
680

    
681

    
682

    
683
        String gmlfile = XMLFILE1;
684
        File idxFile = new File(FilenameUtils.removeExtension(gmlfile)+".gmlidx");
685
        if(idxFile.exists()){
686
            idxFile.delete();
687
        }
688
        File gfsFile = new File(FilenameUtils.removeExtension(gmlfile)+".gfs");
689
        if(gfsFile.exists()){
690
            gfsFile.delete();
691
        }
692
        GfsFile gfs = new GfsFile();
693
        gfs.fetch(new File(gmlfile));
694
        gfs.save(gfsFile);
695
//        return;
696
        XMLFileAsList gml = new XMLFileAsList(
697
                new File(gmlfile), 
698
//                StandardCharsets.ISO_8859_1, 
699
                StandardCharsets.UTF_8, 
700
                gfs.getBaseElementPath(),
701
                gfs.getGeometryElementPaths(),
702
                gfs.getPropertiesPaths()
703
        );
704
        gml.createIndex(new File(FilenameUtils.removeExtension(gmlfile)+".gmlidx"), SimpleTaskStatus.FAKE_STATUS);
705
        System.out.println("File: "+gmlfile);
706
        for (int i = 0; i < gml.size(); i++) {
707
            List<String> item = gml.get(i);
708
            System.out.println("RECORD "+i+":"+item);
709
        }
710
        System.out.println(StringUtils.join(gfs.getPropertiesPaths(), "\n"));
711
        System.out.println("Geometries:\n"+StringUtils.join(gfs.getGeometryElementPaths(), "\n"));
712
    }
713
}