Source code: com/aendvari/common/osm/SimpleOsmPath.java
1 /*
2 * SimpleOsmPath.java
3 *
4 * Copyright (c) 2001, 2002 Aendvari, Ltd. All Rights Reserved.
5 *
6 * See the file LICENSE for terms of use.
7 *
8 */
9
10 package com.aendvari.common.osm;
11
12 import java.util.Iterator;
13 import java.util.StringTokenizer;
14
15 import com.aendvari.common.osm.OsmNode;
16 import com.aendvari.common.osm.OsmException;
17
18 /**
19 * <p>Provides the ability to access nodes within an Object Space Model using an expression.</p>
20 *
21 * <p>This class allows only simple path expressions. It supports the ability to create a node
22 * at the specified path if one does not exist.</p>
23 *
24 * @author Trevor Milne
25 *
26 */
27
28 public class SimpleOsmPath
29 {
30 /* Constants. */
31
32
33 /** The delimiters used to separate segments of the path expression. */
34 protected static String segmentDelimiters = "./";
35
36
37 /* Expressions. */
38
39
40 /**
41 * Returns the node at the specified path. Optionally all non existing nodes found
42 * on the path can be created.
43 *
44 * @param context The context node specifying the root of the path.
45 * @param path Path of the node.
46 * @param build True to build non-existing nodes, false will
47 * return null if path is not valid.
48 *
49 * @return The node found using the path, null if the node cannot be found.
50 *
51 * @exception OsmException The operation failed. This method may fail while
52 * building non-existing nodes.
53 *
54 */
55
56 public static OsmNode getNode(OsmNode context, String path, boolean build) throws OsmException
57 {
58 // call different path searches depending on build/no build
59 if (build)
60 {
61 return getNodeBuild(context, path);
62 }
63 else
64 {
65 return getNodeNoBuild(context, path);
66 }
67 }
68
69 /**
70 * Parses an expression for segments separated by "/" or ".".
71 *
72 */
73
74 protected static class Tokenizer
75 {
76 /** The current position in the string. */
77 protected int position;
78
79 /** The string to parse. */
80 protected String expression;
81
82
83 /**
84 * Creates a <code>Tokenizer</code> to parse the supplied string.
85 *
86 * @param setExpression The expression to parse.
87 *
88 */
89
90 Tokenizer(String setExpression)
91 {
92 expression = setExpression;
93 position = 0;
94
95 // ignore leading separator(s)
96 while (position < expression.length())
97 {
98 char letter = expression.charAt(position);
99 if ((letter != '.') && (letter != '/')) break;
100
101 position++;
102 }
103 }
104
105 /**
106 * Returns the next available token.
107 *
108 * @return The next available token, null if no tokens remain.
109 *
110 */
111
112 String nextToken()
113 {
114 // check for end of value
115 if (position >= expression.length()) return null;
116
117 // search for end of next token
118 int nextPosition = position;
119
120 while (nextPosition < expression.length())
121 {
122 char letter = expression.charAt(nextPosition);
123 if ((letter == '.') || (letter == '/')) break;
124
125 nextPosition++;
126 }
127
128 // extract token
129 String token = expression.substring(position, nextPosition);
130
131 // start next token search at the right of the delimiter
132 position = (nextPosition + 1);
133
134 return token;
135 }
136 }
137
138 /**
139 * Returns the node at the specified path. Returns null if the path is not valid.
140 *
141 * @param parent The context node specifying the root of the path.
142 * @param path Path of the node.
143 *
144 * @return The node found using the path.
145 *
146 * @exception OsmException The operation failed.
147 *
148 */
149
150 protected static OsmNode getNodeNoBuild(OsmNode parent, String path) throws OsmException
151 {
152 Tokenizer tokens = new Tokenizer(path);
153
154 // scan segments of path
155 while (true)
156 {
157 // get next segment
158 String segment = tokens.nextToken();
159
160 // stop if no segments remain
161 if (segment == null)
162 {
163 break;
164 }
165
166 // search children for next segment
167 OsmNode children[] = new OsmNode[parent.children.size()];
168 parent.children.toArray(children);
169
170 // look for new parent
171 parent = null;
172
173 int childIndex;
174 for (childIndex = 0; childIndex < children.length; childIndex++)
175 {
176 OsmNode child = children[childIndex];
177
178 // make child new parent if names matches segment
179 if (child.name.equals(segment))
180 {
181 parent = child;
182 break;
183 }
184 }
185
186 // stop if segment can not be found
187 if (parent == null) break;
188 }
189
190 return parent;
191 }
192
193 /**
194 * Returns the node at the specified path. Builds all non existing nodes found
195 * on the path.
196 *
197 * @param parent The context node specifying the root of the path.
198 * @param path Path of the node.
199 *
200 * @return The node found using the path.
201 *
202 * @exception OsmException The operation failed.
203 *
204 */
205
206 protected static OsmNode getNodeBuild(OsmNode parent, String path) throws OsmException
207 {
208 Tokenizer tokens = new Tokenizer(path);
209 String segment = null;
210 OsmNode context = parent;
211
212 // scan segments of path
213 while (true)
214 {
215 // get next segment
216 segment = tokens.nextToken();
217
218 // stop if no segments remain
219 if (segment == null)
220 {
221 break;
222 }
223
224 // search children for next segment
225 OsmNode children[] = new OsmNode[parent.children.size()];
226 parent.children.toArray(children);
227
228 // look for new parent
229 parent = null;
230
231 int childIndex;
232 for (childIndex = 0; childIndex < children.length; childIndex++)
233 {
234 OsmNode child = children[childIndex];
235
236 // make child new parent if names matches segment
237 if (child.name.equals(segment))
238 {
239 parent = child;
240 context = child;
241
242 break;
243 }
244 }
245
246 // stop if segment can not be found
247 if (parent == null) break;
248 }
249
250 // if segment no found, then create nodes for remainder of path
251 if (parent == null)
252 {
253 // restore parent
254 parent = context;
255
256 // scan remaining segments of path
257 while (true)
258 {
259 // create new node for segment
260 OsmNode newChild = parent.getOwnerOsm().createNode(segment, null);
261 parent.appendChild(newChild);
262
263 // make child new parent
264 parent = newChild;
265
266 // get next segment
267 segment = tokens.nextToken();
268
269 // stop if no segments remain
270 if (segment == null)
271 {
272 break;
273 }
274 }
275 }
276
277 return parent;
278 }
279 }
280