source: josm/trunk/src/org/openstreetmap/josm/data/gpx/GpxExtension.java@ 16436

Last change on this file since 16436 was 16436, checked in by simon04, 4 years ago

see #19251 - Java 8: use Stream

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.gpx;
3
4import java.util.Objects;
5import java.util.Optional;
6
7import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace;
8import org.xml.sax.Attributes;
9
10/**
11 * A GpxExtension that has attributes and child extensions (implements {@link IWithAttributes} and {@link GpxConstants}).
12 * @since 15496
13 */
14public class GpxExtension extends WithAttributes {
15 private final String qualifiedName, prefix, key;
16 private IWithAttributes parent;
17 private String value;
18 private boolean visible = true;
19
20 /**
21 * Constructs a new {@link GpxExtension}.
22 * @param prefix the prefix
23 * @param key the key
24 * @param value the value
25 */
26 public GpxExtension(String prefix, String key, String value) {
27 this.prefix = Optional.ofNullable(prefix).orElse("");
28 this.key = key;
29 this.value = value;
30 this.qualifiedName = (this.prefix.isEmpty() ? "" : this.prefix + ":") + key;
31 }
32
33 /**
34 * Creates a new {@link GpxExtension}
35 *
36 * @param namespaceURI the URI of the XML namespace, used to determine supported extensions
37 * (josm, gpxx, gpxd) regardless of the prefix that could legally vary from file to file.
38 * @param qName the qualified name of the XML element including prefix
39 * @param atts the attributes
40 */
41 public GpxExtension(String namespaceURI, String qName, Attributes atts) {
42 qualifiedName = qName;
43 int dot = qName.indexOf(':');
44 String p = findPrefix(namespaceURI);
45 if (p == null) {
46 if (dot != -1) {
47 prefix = qName.substring(0, dot);
48 } else {
49 prefix = "";
50 }
51 } else {
52 prefix = p;
53 }
54 key = qName.substring(dot + 1);
55 for (int i = 0; i < atts.getLength(); i++) {
56 attr.put(atts.getLocalName(i), atts.getValue(i));
57 }
58 }
59
60 /**
61 * Finds the default prefix used by JOSM for the given namespaceURI as the document is free specify another one.
62 * @param namespaceURI namespace URI
63 * @return the prefix
64 */
65 public static String findPrefix(String namespaceURI) {
66 if (XML_URI_EXTENSIONS_DRAWING.equals(namespaceURI))
67 return "gpxd";
68
69 if (XML_URI_EXTENSIONS_GARMIN.equals(namespaceURI))
70 return "gpxx";
71
72 if (XML_URI_EXTENSIONS_JOSM.equals(namespaceURI))
73 return "josm";
74
75 return null;
76 }
77
78 /**
79 * Finds the namespace for the given default prefix, if supported with schema location
80 * @param prefix the prefix used by JOSM
81 * @return the {@link XMLNamespace} element, location and URI can be <code>null</code> if not found.
82 */
83 public static XMLNamespace findNamespace(String prefix) {
84 switch (prefix) {
85 case "gpxx":
86 return new XMLNamespace("gpxx", XML_URI_EXTENSIONS_GARMIN, XML_XSD_EXTENSIONS_GARMIN);
87 case "gpxd":
88 return new XMLNamespace("gpxd", XML_URI_EXTENSIONS_DRAWING, XML_XSD_EXTENSIONS_DRAWING);
89 case "josm":
90 return new XMLNamespace("josm", XML_URI_EXTENSIONS_JOSM, XML_XSD_EXTENSIONS_JOSM);
91 }
92 return null;
93 }
94
95 /**
96 * @return the qualified name of the XML element
97 */
98 public String getQualifiedName() {
99 return qualifiedName;
100 }
101
102 /**
103 * @return the prefix of the XML namespace
104 */
105 public String getPrefix() {
106 return prefix;
107 }
108
109 /**
110 * @return the key (local element name) of the extension
111 */
112 public String getKey() {
113 return key;
114 }
115
116 /**
117 * @return the flattened extension key of this extension, used for conversion to OSM layers
118 */
119 public String getFlatKey() {
120 String ret = "";
121 if (parent != null && parent instanceof GpxExtension) {
122 GpxExtension ext = (GpxExtension) parent;
123 ret = ext.getFlatKey() + ":";
124 }
125 return ret + getKey();
126 }
127
128 /**
129 * Searches recursively for the extension with the given key in all children
130 * @param sPrefix the prefix to look for
131 * @param sKey the key to look for
132 * @return the extension if found, otherwise <code>null</code>
133 */
134 public GpxExtension findExtension(String sPrefix, String sKey) {
135 if (prefix.equalsIgnoreCase(sPrefix) && key.equalsIgnoreCase(sKey)) {
136 return this;
137 } else {
138 return getExtensions().stream()
139 .map(child -> child.findExtension(sPrefix, sKey))
140 .filter(Objects::nonNull)
141 .findFirst().orElse(null);
142 }
143 }
144
145 /**
146 * @return the value of the extension
147 */
148 public String getValue() {
149 return value;
150 }
151
152 /**
153 * @param value the value to set
154 */
155 public void setValue(String value) {
156 this.value = value;
157 }
158
159 /**
160 * Removes this extension from its parent and all then-empty parents
161 * @throws IllegalStateException if parent not set
162 */
163 public void remove() {
164 if (parent == null)
165 throw new IllegalStateException("Extension " + qualifiedName + " has no parent, can't remove it.");
166
167 parent.getExtensions().remove(this);
168 if (parent instanceof GpxExtension) {
169 GpxExtension gpx = ((GpxExtension) parent);
170 if ((gpx.getValue() == null || gpx.getValue().trim().isEmpty())
171 && gpx.getAttributes().isEmpty()
172 && gpx.getExtensions().isEmpty()) {
173 gpx.remove();
174 }
175 }
176 }
177
178 /**
179 * Hides this extension and all then-empty parents so it isn't written
180 * @see #isVisible()
181 */
182 public void hide() {
183 visible = false;
184 if (parent != null && parent instanceof GpxExtension) {
185 GpxExtension gpx = (GpxExtension) parent;
186 if ((gpx.getValue() == null || gpx.getValue().trim().isEmpty())
187 && gpx.getAttributes().isEmpty()
188 && !gpx.getExtensions().isVisible()) {
189 gpx.hide();
190 }
191 }
192 }
193
194 /**
195 * Shows this extension and all parents so it can be written
196 * @see #isVisible()
197 */
198 public void show() {
199 visible = true;
200 if (parent != null && parent instanceof GpxExtension) {
201 ((GpxExtension) parent).show();
202 }
203 }
204
205 /**
206 * @return if this extension should be written, used for hiding colors during export without removing them
207 */
208 public boolean isVisible() {
209 return visible;
210 }
211
212 /**
213 * @return the parent element of this extension, can be another extension or gpx elements (data, track, segment, ...)
214 */
215 public IWithAttributes getParent() {
216 return parent;
217 }
218
219 /**
220 * Sets the parent for this extension
221 * @param parent the parent
222 * @throws IllegalStateException if parent already set
223 */
224 public void setParent(IWithAttributes parent) {
225 if (this.parent != null)
226 throw new IllegalStateException("Parent of extension " + qualifiedName + " is already set");
227
228 this.parent = parent;
229 }
230
231 @Override
232 public int hashCode() {
233 return Objects.hash(prefix, key, value, attr, visible, super.hashCode());
234 }
235
236 @Override
237 public boolean equals(Object obj) {
238 if (this == obj)
239 return true;
240 if (obj == null)
241 return false;
242 if (!super.equals(obj))
243 return false;
244 if (!(obj instanceof GpxExtension))
245 return false;
246 GpxExtension other = (GpxExtension) obj;
247 if (visible != other.visible)
248 return false;
249 if (prefix == null) {
250 if (other.prefix != null)
251 return false;
252 } else if (!prefix.equals(other.prefix))
253 return false;
254 if (key == null) {
255 if (other.key != null)
256 return false;
257 } else if (!key.equals(other.key))
258 return false;
259 if (value == null) {
260 if (other.value != null)
261 return false;
262 } else if (!value.equals(other.value))
263 return false;
264 if (attr == null) {
265 if (other.attr != null)
266 return false;
267 } else if (!attr.equals(other.attr))
268 return false;
269 return true;
270 }
271}
Note: See TracBrowser for help on using the repository browser.