source: josm/trunk/src/org/openstreetmap/josm/io/NoteReader.java@ 8782

Last change on this file since 8782 was 8510, checked in by Don-vip, 9 years ago

checkstyle: enable relevant whitespace checks and fix them

  • Property svn:eol-style set to native
File size: 8.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import java.io.ByteArrayInputStream;
5import java.io.IOException;
6import java.io.InputStream;
7import java.nio.charset.StandardCharsets;
8import java.util.ArrayList;
9import java.util.Date;
10import java.util.List;
11
12import javax.xml.parsers.ParserConfigurationException;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.data.coor.LatLon;
16import org.openstreetmap.josm.data.notes.Note;
17import org.openstreetmap.josm.data.notes.NoteComment;
18import org.openstreetmap.josm.data.notes.NoteComment.Action;
19import org.openstreetmap.josm.data.osm.User;
20import org.openstreetmap.josm.tools.Utils;
21import org.openstreetmap.josm.tools.date.DateUtils;
22import org.xml.sax.Attributes;
23import org.xml.sax.InputSource;
24import org.xml.sax.SAXException;
25import org.xml.sax.helpers.DefaultHandler;
26
27/**
28 * Class to read Note objects from their XML representation. It can take
29 * either API style XML which starts with an "osm" tag or a planet dump
30 * style XML which starts with an "osm-notes" tag.
31 */
32public class NoteReader {
33
34 private InputSource inputSource;
35 private List<Note> parsedNotes;
36
37 /**
38 * Notes can be represented in two XML formats. One is returned by the API
39 * while the other is used to generate the notes dump file. The parser
40 * needs to know which one it is handling.
41 */
42 private enum NoteParseMode {API, DUMP}
43
44 /**
45 * SAX handler to read note information from its XML representation.
46 * Reads both API style and planet dump style formats.
47 */
48 private class Parser extends DefaultHandler {
49
50 private NoteParseMode parseMode;
51 private StringBuffer buffer = new StringBuffer();
52 private Note thisNote;
53 private long commentUid;
54 private String commentUsername;
55 private Action noteAction;
56 private Date commentCreateDate;
57 private boolean commentIsNew;
58 private List<Note> notes;
59 private String commentText;
60
61 @Override
62 public void characters(char[] ch, int start, int length) throws SAXException {
63 buffer.append(ch, start, length);
64 }
65
66 @Override
67 public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
68 buffer.setLength(0);
69 switch(qName) {
70 case "osm":
71 parseMode = NoteParseMode.API;
72 notes = new ArrayList<Note>(100);
73 return;
74 case "osm-notes":
75 parseMode = NoteParseMode.DUMP;
76 notes = new ArrayList<Note>(10000);
77 return;
78 }
79
80 if (parseMode == NoteParseMode.API) {
81 if ("note".equals(qName)) {
82 double lat = Double.parseDouble(attrs.getValue("lat"));
83 double lon = Double.parseDouble(attrs.getValue("lon"));
84 LatLon noteLatLon = new LatLon(lat, lon);
85 thisNote = new Note(noteLatLon);
86 }
87 return;
88 }
89
90 //The rest only applies for dump mode
91 switch(qName) {
92 case "note":
93 double lat = Double.parseDouble(attrs.getValue("lat"));
94 double lon = Double.parseDouble(attrs.getValue("lon"));
95 LatLon noteLatLon = new LatLon(lat, lon);
96 thisNote = new Note(noteLatLon);
97 thisNote.setId(Long.parseLong(attrs.getValue("id")));
98 String closedTimeStr = attrs.getValue("closed_at");
99 if (closedTimeStr == null) { //no closed_at means the note is still open
100 thisNote.setState(Note.State.open);
101 } else {
102 thisNote.setState(Note.State.closed);
103 thisNote.setClosedAt(DateUtils.fromString(closedTimeStr));
104 }
105 thisNote.setCreatedAt(DateUtils.fromString(attrs.getValue("created_at")));
106 break;
107 case "comment":
108 String uidStr = attrs.getValue("uid");
109 if (uidStr == null) {
110 commentUid = 0;
111 } else {
112 commentUid = Long.parseLong(uidStr);
113 }
114 commentUsername = attrs.getValue("user");
115 noteAction = Action.valueOf(attrs.getValue("action"));
116 commentCreateDate = DateUtils.fromString(attrs.getValue("timestamp"));
117 String isNew = attrs.getValue("is_new");
118 if (isNew == null) {
119 commentIsNew = false;
120 } else {
121 commentIsNew = Boolean.parseBoolean(isNew);
122 }
123 break;
124 }
125 }
126
127 @Override
128 public void endElement(String namespaceURI, String localName, String qName) {
129 if ("note".equals(qName)) {
130 notes.add(thisNote);
131 }
132 if ("comment".equals(qName)) {
133 User commentUser = User.createOsmUser(commentUid, commentUsername);
134 if (commentUid == 0) {
135 commentUser = User.getAnonymous();
136 }
137 if (parseMode == NoteParseMode.API) {
138 commentIsNew = false;
139 }
140 if (parseMode == NoteParseMode.DUMP) {
141 commentText = buffer.toString();
142 }
143 thisNote.addComment(new NoteComment(commentCreateDate, commentUser, commentText, noteAction, commentIsNew));
144 commentUid = 0;
145 commentUsername = null;
146 commentCreateDate = null;
147 commentIsNew = false;
148 commentText = null;
149 }
150 if (parseMode == NoteParseMode.DUMP) {
151 return;
152 }
153
154 //the rest only applies to API mode
155 switch (qName) {
156 case "id":
157 thisNote.setId(Long.parseLong(buffer.toString()));
158 break;
159 case "status":
160 thisNote.setState(Note.State.valueOf(buffer.toString()));
161 break;
162 case "date_created":
163 thisNote.setCreatedAt(DateUtils.fromString(buffer.toString()));
164 break;
165 case "date_closed":
166 thisNote.setClosedAt(DateUtils.fromString(buffer.toString()));
167 break;
168 case "date":
169 commentCreateDate = DateUtils.fromString(buffer.toString());
170 break;
171 case "user":
172 commentUsername = buffer.toString();
173 break;
174 case "uid":
175 commentUid = Long.parseLong(buffer.toString());
176 break;
177 case "text":
178 commentText = buffer.toString();
179 buffer.setLength(0);
180 break;
181 case "action":
182 noteAction = Action.valueOf(buffer.toString());
183 break;
184 case "note": //nothing to do for comment or note, already handled above
185 case "comment":
186 break;
187 }
188 }
189
190 @Override
191 public void endDocument() throws SAXException {
192 parsedNotes = notes;
193 }
194 }
195
196 /**
197 * Initializes the reader with a given InputStream
198 * @param source - InputStream containing Notes XML
199 * @throws IOException if any I/O error occurs
200 */
201 public NoteReader(InputStream source) throws IOException {
202 this.inputSource = new InputSource(source);
203 }
204
205 /**
206 * Initializes the reader with a string as a source
207 * @param source UTF-8 string containing Notes XML to parse
208 * @throws IOException if any I/O error occurs
209 */
210 public NoteReader(String source) throws IOException {
211 this.inputSource = new InputSource(new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)));
212 }
213
214 /**
215 * Parses the InputStream given to the constructor and returns
216 * the resulting Note objects
217 * @return List of Notes parsed from the input data
218 * @throws SAXException if any SAX parsing error occurs
219 * @throws IOException if any I/O error occurs
220 */
221 public List<Note> parse() throws SAXException, IOException {
222 DefaultHandler parser = new Parser();
223 try {
224 Utils.parseSafeSAX(inputSource, parser);
225 } catch (ParserConfigurationException e) {
226 Main.error(e); // broken SAXException chaining
227 throw new SAXException(e);
228 }
229 return parsedNotes;
230 }
231}
Note: See TracBrowser for help on using the repository browser.