comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/FixingsOverview.java @ 3818:dc18457b1cef

merged flys-artifacts/pre2.7-2012-03-16
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:14:59 +0200
parents 72f77b2210c2
children 938e2f6c0c9a
comparison
equal deleted inserted replaced
2456:60ab1054069d 3818:dc18457b1cef
1 package de.intevation.flys.artifacts.model;
2
3 import java.io.Serializable;
4
5 import java.text.SimpleDateFormat;
6
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.Date;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14
15 import org.apache.log4j.Logger;
16
17 import org.hibernate.SQLQuery;
18 import org.hibernate.Session;
19
20 import org.hibernate.type.StandardBasicTypes;
21
22 import org.w3c.dom.Document;
23 import org.w3c.dom.Element;
24
25 public class FixingsOverview
26 implements Serializable
27 {
28 private static Logger log = Logger.getLogger(FixingsOverview.class);
29
30 public static final double EPSILON = 1e-5;
31 public static final double EPSILON2 = 1e-1;
32
33 public static final String DATE_FORMAT = "dd.MM.yyyy HH:mm";
34
35 public static final String SQL_RIVER_ID =
36 "SELECT" +
37 " id AS river_id," +
38 " km_up " +
39 "FROM rivers " +
40 "WHERE" +
41 " name = :name";
42
43 public static final String SQL_GAUGES =
44 "SELECT" +
45 " g.id AS gauge_id," +
46 " r.a AS a," +
47 " r.b AS b " +
48 "FROM gauges g" +
49 " JOIN ranges r ON g.range_id = r.id " +
50 "WHERE" +
51 " g.river_id = :river_id " +
52 "ORDER BY r.a";
53
54 public static final String SQL_DISCHARGE_SECTORS =
55 "SELECT" +
56 " g.id AS gauge_id," +
57 " nmv.name AS name," +
58 " CAST(mv.value AS NUMERIC(38,2)) AS value " +
59 "FROM gauges g" +
60 " JOIN main_values mv ON g.id = mv.gauge_id" +
61 " JOIN named_main_values nmv ON nmv.id = mv.named_value_id" +
62 " JOIN main_value_types mvt ON nmv.type_id = mvt.id " +
63 "WHERE" +
64 " mvt.name = 'Q' AND (" +
65 " nmv.name = 'MNQ' OR" +
66 " nmv.name LIKE 'MNQ(%' OR" +
67 " nmv.name = 'MQ' OR" +
68 " nmv.name LIKE 'MQ(%' OR" +
69 " nmv.name = 'MHQ' OR" +
70 " nmv.name LIKE 'MHQ(%' OR" +
71 " nmv.name = 'HQ5' OR" +
72 " nmv.name LIKE 'HQ5(%') AND" +
73 " g.river_id = :river_id " +
74 "ORDER BY" +
75 " g.id";
76
77 public static final String SQL_FIXINGS =
78 "SELECT" +
79 " id AS wst_id," +
80 " description " +
81 "FROM wsts " +
82 "WHERE" +
83 " river_id = :river_id AND kind = 2";
84
85 public static final String SQL_FIXING_COLUMNS =
86 "SELECT" +
87 " wc.id AS wst_column_id," +
88 " ti.start_time AS start_time," +
89 " wc.name AS name " +
90 "FROM wst_columns wc" +
91 " JOIN time_intervals ti ON wc.time_interval_id = ti.id " +
92 "WHERE" +
93 " wc.wst_id = :wst_id " +
94 "ORDER BY position";
95
96 public static final String SQL_FIXING_COLUMN_Q_RANGES =
97 "SELECT" +
98 " wqr.q AS q," +
99 " r.a AS start_km," +
100 " r.b AS stop_km " +
101 "FROM wst_column_q_ranges wcqr" +
102 " JOIN wst_q_ranges wqr ON wcqr.wst_q_range_id = wqr.id" +
103 " JOIN ranges r ON wqr.range_id = r.id " +
104 "WHERE" +
105 " wcqr.wst_column_id = :column_id " +
106 "ORDER BY r.a";
107
108 public static final String SQL_FIXING_COLUMN_KM_RANGE =
109 "SELECT" +
110 " MIN(position) AS start_km," +
111 " MAX(position) AS stop_km " +
112 "FROM" +
113 " wst_column_values " +
114 "WHERE" +
115 " wst_column_id = :column_id";
116
117 public static class Range implements Serializable {
118
119 protected double start;
120 protected double end;
121
122 public Range() {
123 }
124
125 public Range(double start, double end) {
126 this.start = start;
127 this.end = end;
128 }
129
130 public double getStart() {
131 return start;
132 }
133
134 public double getEnd() {
135 return end;
136 }
137
138 public boolean disjoint(Range other) {
139 return start > other.end || other.start > end;
140 }
141
142 public boolean intersects(Range other) {
143 return !disjoint(other);
144 }
145
146 public void extend(Range other) {
147 if (other.start < start) start = other.start;
148 if (other.end > end ) end = other.end;
149 }
150
151 public boolean clip(Range other) {
152 if (disjoint(other)) return false;
153
154 if (other.start > start) start = other.start;
155 if (other.end < end ) end = other.end;
156
157 return true;
158 }
159
160 public boolean inside(double x) {
161 return x > start-EPSILON && x < end+EPSILON;
162 }
163 } // class Range
164
165 public static class GaugeRange extends Range {
166
167 private static final class Sector implements Serializable {
168
169 int sector;
170 double value;
171
172 Sector(int sector, double value) {
173 this.sector = sector;
174 this.value = value;
175 }
176
177 } // class Sector
178
179 protected int gaugeId;
180
181 protected Map<String, Double> mainValues;
182 protected List<Sector> sectors;
183
184 public GaugeRange() {
185 }
186
187 public GaugeRange(double start, double end, int gaugeId) {
188 super(start, end);
189 this.gaugeId = gaugeId;
190 mainValues = new HashMap<String, Double>();
191 sectors = new ArrayList<Sector>(3);
192 }
193
194 public void addMainValue(String label, Double value) {
195 int idx = label.indexOf('(');
196 if (idx >= 0) {
197 label = label.substring(0, idx);
198 }
199 mainValues.put(label, value);
200 }
201
202 protected Double getMainValue(String label) {
203 Double v = mainValues.get(label);
204 if (v == null) {
205 log.warn("Missing main value '"
206 + label + "' for gauge " + gaugeId);
207 }
208 return v;
209 }
210
211 public void buildClasses() {
212 Double mnq = getMainValue("MNQ");
213 Double mq = getMainValue("MQ");
214 Double mhq = getMainValue("MHQ");
215 Double hq5 = getMainValue("HQ5");
216
217 Double [][] pairs = {
218 { mnq, mq },
219 { mq, mhq },
220 { hq5, hq5 } };
221
222 for (int c = 0; c < pairs.length; ++c) {
223 Double [] pair = pairs[c];
224 if (pair[0] != null && pair[1] != null) {
225 double value = 0.5*(pair[0] + pair[1]);
226 sectors.add(new Sector(c, value));
227 }
228 }
229 }
230
231 public int classify(double value) {
232 for (Sector sector: sectors) {
233 if (value < sector.value) {
234 return sector.sector;
235 }
236 }
237 return sectors.size();
238 }
239 } // class GaugeRange
240
241 public static class GaugeFinder {
242
243 protected List<GaugeRange> gauges;
244 protected boolean isKmUp;
245
246 public GaugeFinder(List<GaugeRange> gauges) {
247 this(gauges, true);
248 }
249
250 public GaugeFinder(
251 List<GaugeRange> gauges,
252 boolean isKmUp
253 ) {
254 this.gauges = gauges;
255 this.isKmUp = isKmUp;
256 }
257
258 public boolean getIsKmUp() {
259 return isKmUp;
260 }
261
262 public void setIsKmUp(boolean isKmUp) {
263 this.isKmUp = isKmUp;
264 }
265
266 public GaugeRange find(Range range) {
267 double km = isKmUp ? range.start : range.end;
268 for (GaugeRange gauge: gauges) {
269 if (gauge.inside(km)) {
270 return gauge;
271 }
272 }
273 return null;
274 }
275
276 public GaugeRange find(int gaugeId) {
277 for (GaugeRange gauge: gauges) {
278 if (gauge.gaugeId == gaugeId) {
279 return gauge;
280 }
281 }
282 return null;
283 }
284
285 public boolean loadDischargeSectors(Session session, int riverId) {
286
287 SQLQuery query = session.createSQLQuery(SQL_DISCHARGE_SECTORS)
288 .addScalar("gauge_id", StandardBasicTypes.INTEGER)
289 .addScalar("name", StandardBasicTypes.STRING)
290 .addScalar("value", StandardBasicTypes.DOUBLE);
291
292 query.setInteger("river_id", riverId);
293
294 List<Object []> list = query.list();
295
296 if (list.isEmpty()) {
297 log.warn("River " + riverId + " has no discharge sectors.");
298 return false;
299 }
300
301 GaugeRange gauge = null;
302
303 for (Object [] row: list) {
304 int gaugeId = (Integer)row[0];
305 String label = (String) row[1];
306 Double value = (Double) row[2];
307
308 if (gauge == null || gauge.gaugeId != gaugeId) {
309 if ((gauge = find(gaugeId)) == null) {
310 log.warn("Cannot find gauge for id " + gaugeId + ".");
311 continue;
312 }
313 }
314
315 gauge.addMainValue(label, value);
316 }
317
318 for (GaugeRange g: gauges) {
319 g.buildClasses();
320 }
321
322 return true;
323 }
324 } // class GaugeFinder
325
326 public static class QRange extends Range {
327
328 protected double q;
329
330 public QRange() {
331 }
332
333 public QRange(double start, double end, double q) {
334 super(start, end);
335 this.q = q;
336 }
337 } // class QRange
338
339 public static class SectorRange extends Range {
340
341 protected int sector;
342
343 public SectorRange() {
344 }
345
346 public SectorRange(SectorRange other) {
347 start = other.start;
348 end = other.end;
349 sector = other.sector;
350 }
351
352 public SectorRange(double start, double end, int sector) {
353 super(start, end);
354 this.sector = sector;
355 }
356
357 public int getSector() {
358 return sector;
359 }
360
361 public boolean enlarge(SectorRange other) {
362 if (sector == other.sector
363 && Math.abs(end-other.start) < EPSILON2) {
364 end = other.end;
365 return true;
366 }
367 return false;
368 }
369 } // class SectorRange
370
371 public static class Fixing implements Serializable {
372
373 public static final Comparator<Column> DATE_CMP =
374 new Comparator<Column>() {
375 @Override
376 public int compare(Column a, Column b) {
377 return a.startTime.compareTo(b.startTime);
378 }
379 };
380
381 public interface Filter {
382
383 boolean accept(Column column);
384
385 } // interface Filter
386
387 public class Column extends Range {
388
389 protected int columnId;
390 protected Date startTime;
391 protected String name;
392
393 protected List<SectorRange> sectors;
394
395 public Column() {
396 }
397
398 public Column(int columnId, Date startTime, String name) {
399 this.columnId = columnId;
400 this.startTime = startTime;
401 this.name = name;
402
403 sectors = new ArrayList<SectorRange>();
404 }
405
406 public int getId() {
407 return columnId;
408 }
409
410 public Fixing getFixing() {
411 return Fixing.this;
412 }
413
414 public Date getStartTime() {
415 return startTime;
416 }
417
418 public String getName() {
419 return name;
420 }
421
422 public List<SectorRange> getSectors() {
423 return sectors;
424 }
425
426 public List<SectorRange> getSectors(Range range) {
427
428 List<SectorRange> result =
429 new ArrayList<SectorRange>(sectors.size());
430
431 for (SectorRange src: sectors) {
432 SectorRange dst = new SectorRange(src);
433 if (dst.clip(range)) {
434 result.add(dst);
435 }
436 }
437
438 return result;
439 }
440
441 public void buildSectors(GaugeRange gauge, List<QRange> qRanges) {
442
443 for (QRange qRange: qRanges) {
444 SectorRange sector = new SectorRange(
445 qRange.start, qRange.end,
446 gauge.classify(qRange.q));
447 if (sectors.isEmpty()
448 || !sectors.get(sectors.size()-1).enlarge(sector)) {
449 sectors.add(sector);
450 }
451 }
452 }
453
454 public void loadKmRange(SQLQuery query) {
455 query.setInteger("column_id", columnId);
456
457 List<Object []> kms = query.list();
458
459 if (kms.isEmpty()) {
460 log.warn("No km range for column " + columnId + ".");
461 }
462 else {
463 Object [] obj = kms.get(0);
464 start = (Double)obj[0];
465 end = (Double)obj[1];
466 }
467 }
468
469 public void loadQRanges(
470 SQLQuery query,
471 GaugeFinder gaugeFinder
472 ) {
473 query.setInteger("column_id", columnId);
474 List<Object []> list = query.list();
475
476 List<QRange> qRanges = new ArrayList<QRange>(list.size());
477
478 for (Object [] row: list) {
479 double q = (Double)row[0];
480 double start = (Double)row[1];
481 double end = (Double)row[2];
482 QRange qRange = new QRange(start, end, q);
483 if (qRange.clip(this)) {
484 qRanges.add(qRange);
485 }
486 }
487
488 GaugeRange gauge = gaugeFinder.find(this);
489
490 if (gauge != null) {
491 buildSectors(gauge, qRanges);
492 }
493 else {
494 log.warn("No gauge found for column " + columnId + ".");
495 }
496 }
497 } // class Column
498
499 protected int wstId;
500 protected String description;
501 protected List<Column> columns;
502
503 public Fixing() {
504 }
505
506 public int getId() {
507 return wstId;
508 }
509
510 public String getDescription() {
511 return description;
512 }
513
514 public Fixing(int wstId, String description) {
515 this.wstId = wstId;
516 this.description = description;
517 columns = new ArrayList<Column>();
518 }
519
520 public void loadColumns(SQLQuery query) {
521 query.setInteger("wst_id", wstId);
522 List<Object []> list = query.list();
523 for (Object [] row: list) {
524 int columnId = (Integer)row[0];
525 Date startTime = (Date) row[1];
526 String name = (String) row[2];
527 columns.add(new Column(columnId, startTime, name));
528 }
529 }
530
531 public void loadColumnsKmRange(SQLQuery query) {
532 for (Column column: columns) {
533 column.loadKmRange(query);
534 }
535 }
536
537 public void adjustExtent(Range extent) {
538 for (Column column: columns) {
539 extent.extend(column);
540 }
541 }
542
543 public void loadColumnsQRanges(
544 SQLQuery query,
545 GaugeFinder gaugeFinder
546 ) {
547 for (Column column: columns) {
548 column.loadQRanges(query, gaugeFinder);
549 }
550 }
551
552 public void addAllColumns(
553 List<Column> allColumns,
554 Range range,
555 Filter filter
556 ) {
557 for (Column column: columns) {
558 if (column.intersects(range) && filter.accept(column)) {
559 allColumns.add(column);
560 }
561 }
562 }
563 } // class Fixing
564
565
566 protected String riverName;
567 protected int riverId;
568 protected boolean isKmUp;
569 protected List<Fixing> fixings;
570 protected Range extent;
571
572 public FixingsOverview() {
573 fixings = new ArrayList<Fixing>();
574 extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE);
575 }
576
577 public FixingsOverview(String riverName) {
578 this();
579 this.riverName = riverName;
580 }
581
582 protected boolean loadRiver(Session session) {
583 SQLQuery query = session.createSQLQuery(SQL_RIVER_ID)
584 .addScalar("river_id", StandardBasicTypes.INTEGER)
585 .addScalar("km_up", StandardBasicTypes.BOOLEAN);
586
587 query.setString("name", riverName);
588
589 List<Object []> list = query.list();
590
591 if (list.isEmpty()) {
592 log.warn("No river '" + riverName + "' found.");
593 return false;
594 }
595
596 Object [] row = list.get(0);
597
598 riverId = (Integer)row[0];
599 isKmUp = (Boolean)row[1];
600
601 return true;
602 }
603
604 protected GaugeFinder loadGauges(Session session) {
605 SQLQuery query = session.createSQLQuery(SQL_GAUGES)
606 .addScalar("gauge_id", StandardBasicTypes.INTEGER)
607 .addScalar("a", StandardBasicTypes.DOUBLE)
608 .addScalar("b", StandardBasicTypes.DOUBLE);
609
610 query.setInteger("river_id", riverId);
611
612 List<Object []> list = query.list();
613
614 if (list.isEmpty()) {
615 log.warn("River " + riverId + " has no gauges.");
616 return null;
617 }
618
619 List<GaugeRange> gauges = new ArrayList<GaugeRange>();
620
621 for (Object [] row: list) {
622 int gaugeId = (Integer)row[0];
623 double start = (Double) row[1];
624 double end = (Double) row[2];
625 GaugeRange gauge = new GaugeRange(start, end, gaugeId);
626 gauges.add(gauge);
627 }
628
629 return new GaugeFinder(gauges, isKmUp);
630 }
631
632
633 protected void loadFixings(Session session) {
634 SQLQuery query = session.createSQLQuery(SQL_FIXINGS)
635 .addScalar("wst_id", StandardBasicTypes.INTEGER)
636 .addScalar("description", StandardBasicTypes.STRING);
637
638 query.setInteger("river_id", riverId);
639
640 List<Object []> list = query.list();
641
642 if (list.isEmpty()) {
643 log.warn("River " + riverId + " has no fixings.");
644 // Its pretty fine to have no fixings.
645 }
646
647 for (Object [] row: list) {
648 int wstId = (Integer)row[0];
649 String description = (String) row[1];
650 Fixing fixing = new Fixing(wstId, description);
651 fixings.add(fixing);
652 }
653 }
654
655 protected void loadFixingsColumns(Session session) {
656 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMNS)
657 .addScalar("wst_column_id", StandardBasicTypes.INTEGER)
658 .addScalar("start_time", StandardBasicTypes.DATE)
659 .addScalar("name", StandardBasicTypes.STRING);
660
661 for (Fixing fixing: fixings) {
662 fixing.loadColumns(query);
663 }
664 }
665
666 protected void loadFixingsColumnsKmRange(Session session) {
667 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_KM_RANGE)
668 .addScalar("start_km", StandardBasicTypes.DOUBLE)
669 .addScalar("stop_km", StandardBasicTypes.DOUBLE);
670
671 for (Fixing fixing: fixings) {
672 fixing.loadColumnsKmRange(query);
673 }
674 }
675
676 protected void loadFixingsColumnsQRanges(
677 Session session,
678 GaugeFinder gaugeFinder
679 ) {
680 SQLQuery query = session.createSQLQuery(SQL_FIXING_COLUMN_Q_RANGES)
681 .addScalar("q", StandardBasicTypes.DOUBLE)
682 .addScalar("start_km", StandardBasicTypes.DOUBLE)
683 .addScalar("stop_km", StandardBasicTypes.DOUBLE);
684
685 for (Fixing fixing: fixings) {
686 fixing.loadColumnsQRanges(query, gaugeFinder);
687 }
688 }
689
690 protected void adjustExtent() {
691 for (Fixing fixing: fixings) {
692 fixing.adjustExtent(extent);
693 }
694 }
695
696 public boolean load(Session session) {
697
698 if (!loadRiver(session)) {
699 return false;
700 }
701
702 GaugeFinder gaugeFinder = loadGauges(session);
703
704 if (gaugeFinder == null
705 || !gaugeFinder.loadDischargeSectors(session, riverId)) {
706 return false;
707 }
708
709 loadFixings(session);
710 loadFixingsColumns(session);
711 loadFixingsColumnsKmRange(session);
712
713 adjustExtent();
714
715 loadFixingsColumnsQRanges(session, gaugeFinder);
716
717 return true;
718 }
719
720 public static final Range FULL_EXTENT =
721 new Range(-Double.MAX_VALUE, Double.MAX_VALUE);
722
723 public static final Fixing.Filter ACCEPT = new Fixing.Filter() {
724 @Override
725 public boolean accept(Fixing.Column column) {
726 return true;
727 }
728 };
729
730 public static class NotFilter implements Fixing.Filter {
731 protected Fixing.Filter child;
732
733 public NotFilter(Fixing.Filter child) {
734 this.child = child;
735 }
736
737 @Override
738 public boolean accept(Fixing.Column column) {
739 return !child.accept(column);
740 }
741 } // class NotFilter
742
743 public static abstract class ComponentFilter implements Fixing.Filter {
744 protected List<Fixing.Filter> children;
745
746 public ComponentFilter(List<Fixing.Filter> children) {
747 this.children = children;
748 }
749 } // class ComponentFilter
750
751 public static class OrFilter extends ComponentFilter {
752
753 public OrFilter(List<Fixing.Filter> children) {
754 super(children);
755 }
756
757 @Override
758 public boolean accept(Fixing.Column column) {
759 for (Fixing.Filter child: children) {
760 if (child.accept(column)) {
761 return true;
762 }
763 }
764 return false;
765 }
766 } // class OrFilter
767
768 public static class AndFilter extends ComponentFilter {
769
770 public AndFilter(List<Fixing.Filter> children) {
771 super(children);
772 }
773
774 @Override
775 public boolean accept(Fixing.Column column) {
776 for (Fixing.Filter child: children) {
777 if (!child.accept(column)) {
778 return false;
779 }
780 }
781 return true;
782 }
783 } // class AndFilter
784
785 public static class IdFilter implements Fixing.Filter {
786
787 protected int columnId;
788
789 public IdFilter(int columnId) {
790 this.columnId = columnId;
791 }
792
793 @Override
794 public boolean accept(Fixing.Column column) {
795 return column.getId() == columnId;
796 }
797 } // class IdFilter
798
799 public static class DateFilter implements Fixing.Filter {
800
801 protected Date date;
802
803 public DateFilter(Date date) {
804 this.date = date;
805 }
806
807 @Override
808 public boolean accept(Fixing.Column column) {
809 return date.equals(column.getStartTime());
810 }
811 } // class DateFilter
812
813 public static class DateRangeFilter implements Fixing.Filter {
814
815 protected Date start;
816 protected Date end;
817
818 public DateRangeFilter(Date start, Date end) {
819 this.start = start;
820 this.end = end;
821 }
822
823 @Override
824 public boolean accept(Fixing.Column column) {
825 Date date = column.getStartTime();
826 return start.compareTo(date) <= 0 && end.compareTo(date) >= 0;
827 }
828 } // class DateRangeFilter
829
830 public static class SectorRangeFilter implements Fixing.Filter {
831
832 protected int min;
833 protected int max;
834
835 public SectorRangeFilter(int min, int max) {
836 this.min = Math.min(min, max);
837 this.max = Math.max(min, max);
838 }
839
840 @Override
841 public boolean accept(Fixing.Column column) {
842 for (SectorRange s: column.getSectors()) {
843 int v = s.getSector();
844 if (v >= min && v <= max) {
845 return true;
846 }
847 }
848 return false;
849 }
850 } // class SectorRangeFilter
851
852 public void generateOverview(Document document) {
853 generateOverview(document, FULL_EXTENT, ACCEPT);
854 }
855
856 public void generateOverview(
857 Document document,
858 Range range,
859 Fixing.Filter filter
860 ) {
861 List<Fixing.Column> allColumns = new ArrayList<Fixing.Column>();
862
863 for (Fixing fixing: fixings) {
864 fixing.addAllColumns(allColumns, range, filter);
865 }
866
867 Collections.sort(allColumns, Fixing.DATE_CMP);
868
869 Element fixingsElement = document.createElement("fixings");
870
871 Element riverElement = document.createElement("river");
872
873 riverElement.setAttribute("from", String.valueOf(extent.start));
874 riverElement.setAttribute("to", String.valueOf(extent.end));
875 riverElement.setAttribute("rid", String.valueOf(riverId));
876 riverElement.setAttribute("name", riverName);
877
878 fixingsElement.appendChild(riverElement);
879
880 SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
881
882 Element esE = document.createElement("events");
883
884 for (Fixing.Column column: allColumns) {
885
886 List<SectorRange> sectors = column.getSectors(range);
887
888 if (!sectors.isEmpty()) {
889 Element eE = document.createElement("event");
890 eE.setAttribute("name",
891 String.valueOf(column.getFixing().description));
892 eE.setAttribute("cid", String.valueOf(column.columnId));
893 eE.setAttribute("date", df.format(column.startTime));
894
895 for (SectorRange sector: sectors) {
896 Element sE = document.createElement("sector");
897
898 sE.setAttribute("from", String.valueOf(sector.start));
899 sE.setAttribute("to", String.valueOf(sector.end));
900 sE.setAttribute("class", String.valueOf(sector.sector));
901
902 eE.appendChild(sE);
903 }
904
905 esE.appendChild(eE);
906 }
907 }
908
909 fixingsElement.appendChild(esE);
910
911 document.appendChild(fixingsElement);
912 }
913 }
914 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org