3 ###########################################################################
5 ## Copyrights Etienne Chové <chove@crans.org> 2009-2010 ##
7 ## This program is free software: you can redistribute it and/or modify ##
8 ## it under the terms of the GNU General Public License as published by ##
9 ## the Free Software Foundation, either version 3 of the License, or ##
10 ## (at your option) any later version. ##
12 ## This program is distributed in the hope that it will be useful, ##
13 ## but WITHOUT ANY WARRANTY; without even the implied warranty of ##
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ##
15 ## GNU General Public License for more details. ##
17 ## You should have received a copy of the GNU General Public License ##
18 ## along with this program. If not, see <http://www.gnu.org/licenses/>. ##
20 ###########################################################################
22 ## HomePage : http://wiki.openstreetmap.org/wiki/PythonOsmApi
24 ###########################################################################
26 ###########################################################################
27 ## 0.2.19 2010-05-24 Add debug message on ApiError ##
28 ## 0.2.18 2010-04-20 Fix ChangesetClose and _http_request ##
29 ## 0.2.17 2010-01-02 Capabilities implementation ##
30 ## 0.2.16 2010-01-02 ChangesetsGet by Alexander Rampp ##
31 ## 0.2.15 2009-12-16 xml encoding error for < and > ##
32 ## 0.2.14 2009-11-20 changesetautomulti parameter ##
33 ## 0.2.13 2009-11-16 modify instead update for osc ##
34 ## 0.2.12 2009-11-14 raise ApiError on 4xx errors -- Xoff ##
35 ## 0.2.11 2009-10-14 unicode error on ChangesetUpload ##
36 ## 0.2.10 2009-10-14 RelationFullRecur definition ##
37 ## 0.2.9 2009-10-13 automatic changeset management ##
38 ## ChangesetUpload implementation ##
39 ## 0.2.8 2009-10-13 *(Create|Update|Delete) use not unique _do method ##
40 ## 0.2.7 2009-10-09 implement all missing fonctions except ##
41 ## ChangesetsGet and GetCapabilities ##
42 ## 0.2.6 2009-10-09 encoding clean-up ##
43 ## 0.2.5 2009-10-09 implements NodesGet, WaysGet, RelationsGet ##
44 ## ParseOsm, ParseOsc ##
45 ## 0.2.4 2009-10-06 clean-up ##
46 ## 0.2.3 2009-09-09 keep http connection alive for multiple request ##
47 ## (Node|Way|Relation)Get return None when object ##
48 ## have been deleted (raising error before) ##
49 ## 0.2.2 2009-07-13 can identify applications built on top of the lib ##
50 ## 0.2.1 2009-05-05 some changes in constructor -- chove@crans.org ##
51 ## 0.2 2009-05-01 initial import ##
52 ###########################################################################
54 __version__
= '0.2.19'
56 import httplib
, base64
, xml
.dom
.minidom
, time
, sys
, urllib
58 class ApiError(Exception):
60 def __init__(self
, status
, reason
, payload
):
63 self
.payload
= payload
66 return "Request failed: " + str(self
.status
) + " - " + self
.reason
+ " - " + self
.payload
68 ###########################################################################
78 created_by
= "PythonOsmApi/"+__version__
,
79 api
= "www.openstreetmap.org",
80 changesetauto
= False,
81 changesetautotags
= {},
82 changesetautosize
= 500,
83 changesetautomulti
= 1,
92 self
._username
= username
94 self
._username
= open(passwordfile
).readline().split(":")[0].strip()
98 self
._password
= password
100 for l
in open(passwordfile
).readlines():
101 l
= l
.strip().split(":")
102 if l
[0] == self
._username
:
103 self
._password
= l
[1]
105 # Changest informations
106 self
._changesetauto
= changesetauto
# auto create and close changesets
107 self
._changesetautotags
= changesetautotags
# tags for automatic created changesets
108 self
._changesetautosize
= changesetautosize
# change count for auto changeset
109 self
._changesetautosize
= changesetautosize
# change count for auto changeset
110 self
._changesetautomulti
= changesetautomulti
# close a changeset every # upload
111 self
._changesetautocpt
= 0
112 self
._changesetautodata
= [] # data to upload for auto group
119 self
._created
_by
= created_by
121 self
._created
_by
= appid
+ " (" + created_by
+ ")"
124 self
._CurrentChangesetId
= 0
127 self
._conn
= httplib
.HTTPConnection(self
._api
, 80)
130 if self
._changesetauto
:
131 self
._changesetautoflush
(True)
134 #######################################################################
136 #######################################################################
138 def Capabilities(self
):
139 """ Returns ApiCapabilities. """
140 uri
= "/api/capabilities"
141 data
= self
._get
(uri
)
142 data
= xml
.dom
.minidom
.parseString(data
)
143 print data
.getElementsByTagName("osm")
144 data
= data
.getElementsByTagName("osm")[0].getElementsByTagName("api")[0]
146 for elem
in data
.childNodes
:
147 if elem
.nodeType
<> elem
.ELEMENT_NODE
:
149 result
[elem
.nodeName
] = {}
151 for k
, v
in elem
.attributes
.items():
153 result
[elem
.nodeName
][k
] = float(v
)
155 result
[elem
.nodeName
][k
] = v
158 #######################################################################
160 #######################################################################
162 def NodeGet(self
, NodeId
, NodeVersion
= -1):
163 """ Returns NodeData for node #NodeId. """
164 uri
= "/api/0.6/node/"+str(NodeId
)
165 if NodeVersion
<> -1: uri
+= "/"+str(NodeVersion
)
166 data
= self
._get
(uri
)
167 if not data
: return data
168 data
= xml
.dom
.minidom
.parseString(data
)
169 data
= data
.getElementsByTagName("osm")[0].getElementsByTagName("node")[0]
170 return self
._DomParseNode
(data
)
172 def NodeCreate(self
, NodeData
):
173 """ Creates a node. Returns updated NodeData (without timestamp). """
174 return self
._do
("create", "node", NodeData
)
176 def NodeUpdate(self
, NodeData
):
177 """ Updates node with NodeData. Returns updated NodeData (without timestamp). """
178 return self
._do
("modify", "node", NodeData
)
180 def NodeDelete(self
, NodeData
):
181 """ Delete node with NodeData. Returns updated NodeData (without timestamp). """
182 return self
._do
("delete", "node", NodeData
)
184 def NodeHistory(self
, NodeId
):
185 """ Returns dict(NodeVerrsion: NodeData). """
186 uri
= "/api/0.6/node/"+str(NodeId
)+"/history"
187 data
= self
._get
(uri
)
188 data
= xml
.dom
.minidom
.parseString(data
)
190 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("node"):
191 data
= self
._DomParseNode
(data
)
192 result
[data
[u
"version"]] = data
195 def NodeWays(self
, NodeId
):
196 """ Returns [WayData, ... ] containing node #NodeId. """
197 uri
= "/api/0.6/node/%d/ways"%NodeId
198 data
= self
._get
(uri
)
199 data
= xml
.dom
.minidom
.parseString(data
)
201 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("way"):
202 data
= self
._DomParseRelation
(data
)
206 def NodeRelations(self
, NodeId
):
207 """ Returns [RelationData, ... ] containing node #NodeId. """
208 uri
= "/api/0.6/node/%d/relations"%NodeId
209 data
= self
._get
(uri
)
210 data
= xml
.dom
.minidom
.parseString(data
)
212 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("relation"):
213 data
= self
._DomParseRelation
(data
)
217 def NodesGet(self
, NodeIdList
):
218 """ Returns dict(NodeId: NodeData) for each node in NodeIdList """
219 uri
= "/api/0.6/nodes?nodes=" + ",".join([str(x
) for x
in NodeIdList
])
220 data
= self
._get
(uri
)
221 data
= xml
.dom
.minidom
.parseString(data
)
223 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("node"):
224 data
= self
._DomParseNode
(data
)
225 result
[data
[u
"id"]] = data
228 #######################################################################
230 #######################################################################
232 def WayGet(self
, WayId
, WayVersion
= -1):
233 """ Returns WayData for way #WayId. """
234 uri
= "/api/0.6/way/"+str(WayId
)
235 if WayVersion
<> -1: uri
+= "/"+str(WayVersion
)
236 data
= self
._get
(uri
)
237 if not data
: return data
238 data
= xml
.dom
.minidom
.parseString(data
)
239 data
= data
.getElementsByTagName("osm")[0].getElementsByTagName("way")[0]
240 return self
._DomParseWay
(data
)
242 def WayCreate(self
, WayData
):
243 """ Creates a way. Returns updated WayData (without timestamp). """
244 return self
._do
("create", "way", WayData
)
246 def WayUpdate(self
, WayData
):
247 """ Updates way with WayData. Returns updated WayData (without timestamp). """
248 return self
._do
("modify", "way", WayData
)
250 def WayDelete(self
, WayData
):
251 """ Delete way with WayData. Returns updated WayData (without timestamp). """
252 return self
._do
("delete", "way", WayData
)
254 def WayHistory(self
, WayId
):
255 """ Returns dict(WayVerrsion: WayData). """
256 uri
= "/api/0.6/way/"+str(WayId
)+"/history"
257 data
= self
._get
(uri
)
258 data
= xml
.dom
.minidom
.parseString(data
)
260 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("way"):
261 data
= self
._DomParseWay
(data
)
262 result
[data
[u
"version"]] = data
265 def WayRelations(self
, WayId
):
266 """ Returns [RelationData, ...] containing way #WayId. """
267 uri
= "/api/0.6/way/%d/relations"%WayId
268 data
= self
._get
(uri
)
269 data
= xml
.dom
.minidom
.parseString(data
)
271 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("relation"):
272 data
= self
._DomParseRelation
(data
)
276 def WayFull(self
, WayId
):
277 """ Return full data for way WayId as list of {type: node|way|relation, data: {}}. """
278 uri
= "/api/0.6/way/"+str(WayId
)+"/full"
279 data
= self
._get
(uri
)
280 return self
.ParseOsm(data
)
282 def WaysGet(self
, WayIdList
):
283 """ Returns dict(WayId: WayData) for each way in WayIdList """
284 uri
= "/api/0.6/ways?ways=" + ",".join([str(x
) for x
in WayIdList
])
285 data
= self
._get
(uri
)
286 data
= xml
.dom
.minidom
.parseString(data
)
288 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("way"):
289 data
= self
._DomParseWay
(data
)
290 result
[data
[u
"id"]] = data
293 #######################################################################
295 #######################################################################
297 def RelationGet(self
, RelationId
, RelationVersion
= -1):
298 """ Returns RelationData for relation #RelationId. """
299 uri
= "/api/0.6/relation/"+str(RelationId
)
300 if RelationVersion
<> -1: uri
+= "/"+str(RelationVersion
)
301 data
= self
._get
(uri
)
302 if not data
: return data
303 data
= xml
.dom
.minidom
.parseString(data
)
304 data
= data
.getElementsByTagName("osm")[0].getElementsByTagName("relation")[0]
305 return self
._DomParseRelation
(data
)
307 def RelationCreate(self
, RelationData
):
308 """ Creates a relation. Returns updated RelationData (without timestamp). """
309 return self
._do
("create", "relation", RelationData
)
311 def RelationUpdate(self
, RelationData
):
312 """ Updates relation with RelationData. Returns updated RelationData (without timestamp). """
313 return self
._do
("modify", "relation", RelationData
)
315 def RelationDelete(self
, RelationData
):
316 """ Delete relation with RelationData. Returns updated RelationData (without timestamp). """
317 return self
._do
("delete", "relation", RelationData
)
319 def RelationHistory(self
, RelationId
):
320 """ Returns dict(RelationVerrsion: RelationData). """
321 uri
= "/api/0.6/relation/"+str(RelationId
)+"/history"
322 data
= self
._get
(uri
)
323 data
= xml
.dom
.minidom
.parseString(data
)
325 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("relation"):
326 data
= self
._DomParseRelation
(data
)
327 result
[data
[u
"version"]] = data
330 def RelationRelations(self
, RelationId
):
331 """ Returns list of RelationData containing relation #RelationId. """
332 uri
= "/api/0.6/relation/%d/relations"%RelationId
333 data
= self
._get
(uri
)
334 data
= xml
.dom
.minidom
.parseString(data
)
336 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("relation"):
337 data
= self
._DomParseRelation
(data
)
341 def RelationFullRecur(self
, RelationId
):
342 """ Return full data for relation RelationId. Recurisve version relation of relations. """
349 temp
= self
.RelationFull(rid
)
351 if item
["type"] <> "relation":
353 if item
["data"]["id"] in done
:
355 todo
.append(item
["data"]["id"])
359 def RelationFull(self
, RelationId
):
360 """ Return full data for relation RelationId as list of {type: node|way|relation, data: {}}. """
361 uri
= "/api/0.6/relation/"+str(RelationId
)+"/full"
362 data
= self
._get
(uri
)
363 return self
.ParseOsm(data
)
365 def RelationsGet(self
, RelationIdList
):
366 """ Returns dict(RelationId: RelationData) for each relation in RelationIdList """
367 uri
= "/api/0.6/relations?relations=" + ",".join([str(x
) for x
in RelationIdList
])
368 data
= self
._get
(uri
)
369 data
= xml
.dom
.minidom
.parseString(data
)
371 for data
in data
.getElementsByTagName("osm")[0].getElementsByTagName("relation"):
372 data
= self
._DomParseRelation
(data
)
373 result
[data
[u
"id"]] = data
376 #######################################################################
378 #######################################################################
380 def ChangesetGet(self
, ChangesetId
):
381 """ Returns ChangesetData for changeset #ChangesetId. """
382 data
= self
._get
("/api/0.6/changeset/"+str(ChangesetId
))
383 data
= xml
.dom
.minidom
.parseString(data
)
384 data
= data
.getElementsByTagName("osm")[0].getElementsByTagName("changeset")[0]
385 return self
._DomParseChangeset
(data
)
387 def ChangesetUpdate(self
, ChangesetTags
= {}):
388 """ Updates current changeset with ChangesetTags. """
389 if self
._CurrentChangesetId
== -1:
390 raise Exception, "No changeset currently opened"
391 if u
"created_by" not in ChangesetTags
:
392 ChangesetTags
[u
"created_by"] = self
._created
_by
393 result
= self
._put
("/api/0.6/changeset/"+str(self
._CurrentChangesetId
), self
._XmlBuild
("changeset", {u
"tag": ChangesetTags
}))
394 return self
._CurrentChangesetId
396 def ChangesetCreate(self
, ChangesetTags
= {}):
397 """ Opens a changeset. Returns #ChangesetId. """
398 if self
._CurrentChangesetId
:
399 raise Exception, "Changeset alreadey opened"
400 if u
"created_by" not in ChangesetTags
:
401 ChangesetTags
[u
"created_by"] = self
._created
_by
402 result
= self
._put
("/api/0.6/changeset/create", self
._XmlBuild
("changeset", {u
"tag": ChangesetTags
}))
403 self
._CurrentChangesetId
= int(result
)
404 return self
._CurrentChangesetId
406 def ChangesetClose(self
):
407 """ Closes current changeset. Returns #ChangesetId. """
408 if not self
._CurrentChangesetId
:
409 raise Exception, "No changeset currently opened"
410 result
= self
._put
("/api/0.6/changeset/"+str(self
._CurrentChangesetId
)+"/close", u
"")
411 CurrentChangesetId
= self
._CurrentChangesetId
412 self
._CurrentChangesetId
= 0
413 return CurrentChangesetId
415 def ChangesetUpload(self
, ChangesData
):
416 """ Upload data. ChangesData is a list of dict {type: node|way|relation, action: create|delete|modify, data: {}}. Returns list with updated ids. """
418 data
+= u
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
419 data
+= u
"<osmChange version=\"0.6\" generator=\"" + self
._created
_by
+ "\">\n"
420 for change
in ChangesData
:
421 data
+= u
"<"+change
["action"]+">\n"
422 change
["data"]["changeset"] = self
._CurrentChangesetId
423 data
+= self
._XmlBuild
(change
["type"], change
["data"], False).decode("utf-8")
424 data
+= u
"</"+change
["action"]+">\n"
425 data
+= u
"</osmChange>"
426 data
= self
._http
("POST", "/api/0.6/changeset/"+str(self
._CurrentChangesetId
)+"/upload", True, data
.encode("utf-8"))
427 data
= xml
.dom
.minidom
.parseString(data
)
428 data
= data
.getElementsByTagName("diffResult")[0]
429 data
= [x
for x
in data
.childNodes
if x
.nodeType
== x
.ELEMENT_NODE
]
430 for i
in range(len(ChangesData
)):
431 if ChangesData
[i
]["action"] == "delete":
432 ChangesData
[i
]["data"].pop("version")
434 ChangesData
[i
]["data"]["version"] = int(data
[i
].getAttribute("new_id"))
437 def ChangesetDownload(self
, ChangesetId
):
438 """ Download data from a changeset. Returns list of dict {type: node|way|relation, action: create|delete|modify, data: {}}. """
439 uri
= "/api/0.6/changeset/"+str(ChangesetId
)+"/download"
440 data
= self
._get
(uri
)
441 return self
.ParseOsc(data
)
443 def ChangesetsGet(self
, min_lon
=None, min_lat
=None, max_lon
=None, max_lat
=None,
444 userid
=None, username
=None,
445 closed_after
=None, created_before
=None,
446 only_open
=False, only_closed
=False):
447 """ Returns dict(ChangsetId: ChangesetData) matching all criteria. """
449 uri
= "/api/0.6/changesets"
451 if min_lon
or min_lat
or max_lon
or max_lat
:
452 params
["bbox"] = ",".join([str(min_lon
),str(min_lat
),str(max_lon
),str(max_lat
)])
454 params
["user"] = userid
456 params
["display_name"] = username
457 if closed_after
and not created_before
:
458 params
["time"] = closed_after
461 closed_after
= "1970-01-01T00:00:00Z"
462 params
["time"] = closed_after
+ "," + created_before
469 uri
+= "?" + urllib
.urlencode(params
)
471 data
= self
._get
(uri
)
472 data
= xml
.dom
.minidom
.parseString(data
)
473 data
= data
.getElementsByTagName("osm")[0].getElementsByTagName("changeset")
475 for curChangeset
in data
:
476 tmpCS
= self
._DomParseChangeset
(curChangeset
)
477 result
[tmpCS
["id"]] = tmpCS
480 #######################################################################
482 #######################################################################
484 def Map(self
, min_lon
, min_lat
, max_lon
, max_lat
):
485 """ Download data in bounding box. Returns list of dict {type: node|way|relation, data: {}}. """
486 uri
= "/api/0.6/map?bbox=%f,%f,%f,%f"%(min_lon
, min_lat
, max_lon
, max_lat
)
487 data
= self
._get
(uri
)
488 return self
.ParseOsm(data
)
490 #######################################################################
492 #######################################################################
494 def ParseOsm(self
, data
):
495 """ Parse osm data. Returns list of dict {type: node|way|relation, data: {}}. """
496 data
= xml
.dom
.minidom
.parseString(data
)
497 data
= data
.getElementsByTagName("osm")[0]
499 for elem
in data
.childNodes
:
500 if elem
.nodeName
== u
"node":
501 result
.append({u
"type": elem
.nodeName
, u
"data": self
._DomParseNode
(elem
)})
502 elif elem
.nodeName
== u
"way":
503 result
.append({u
"type": elem
.nodeName
, u
"data": self
._DomParseWay
(elem
)})
504 elif elem
.nodeName
== u
"relation":
505 result
.append({u
"type": elem
.nodeName
, u
"data": self
._DomParseRelation
(elem
)})
508 def ParseOsc(self
, data
):
509 """ Parse osc data. Returns list of dict {type: node|way|relation, action: create|delete|modify, data: {}}. """
510 data
= xml
.dom
.minidom
.parseString(data
)
511 data
= data
.getElementsByTagName("osmChange")[0]
513 for action
in data
.childNodes
:
514 if action
.nodeName
== u
"#text": continue
515 for elem
in action
.childNodes
:
516 if elem
.nodeName
== u
"node":
517 result
.append({u
"action":action
.nodeName
, u
"type": elem
.nodeName
, u
"data": self
._DomParseNode
(elem
)})
518 elif elem
.nodeName
== u
"way":
519 result
.append({u
"action":action
.nodeName
, u
"type": elem
.nodeName
, u
"data": self
._DomParseWay
(elem
)})
520 elif elem
.nodeName
== u
"relation":
521 result
.append({u
"action":action
.nodeName
, u
"type": elem
.nodeName
, u
"data": self
._DomParseRelation
(elem
)})
524 #######################################################################
525 # Internal http function #
526 #######################################################################
528 def _do(self
, action
, OsmType
, OsmData
):
529 if self
._changesetauto
:
530 self
._changesetautodata
.append({"action":action
, "type":OsmType
, "data":OsmData
})
531 self
._changesetautoflush
()
534 return self
._do
_manu
(action
, OsmType
, OsmData
)
536 def _do_manu(self
, action
, OsmType
, OsmData
):
537 if not self
._CurrentChangesetId
:
538 raise Exception, "You need to open a changeset before uploading data"
539 if u
"timestamp" in OsmData
:
540 OsmData
.pop(u
"timestamp")
541 OsmData
[u
"changeset"] = self
._CurrentChangesetId
542 if action
== "create":
543 if OsmData
.get(u
"id", -1) > 0:
544 raise Exception, "This "+OsmType
+" already exists"
545 result
= self
._put
("/api/0.6/"+OsmType
+"/create", self
._XmlBuild
(OsmType
, OsmData
))
546 OsmData
[u
"id"] = int(result
.strip())
547 OsmData
[u
"version"] = 1
549 elif action
== "modify":
550 result
= self
._put
("/api/0.6/"+OsmType
+"/"+str(OsmData
[u
"id"]), self
._XmlBuild
(OsmType
, OsmData
))
551 OsmData
[u
"version"] = int(result
.strip())
553 elif action
=="delete":
554 result
= self
._delete
("/api/0.6/"+OsmType
+"/"+str(OsmData
[u
"id"]), self
._XmlBuild
(OsmType
, OsmData
))
555 OsmData
[u
"version"] = int(result
.strip())
556 OsmData
[u
"visible"] = False
560 return self
._changesetautoflush
(True)
562 def _changesetautoflush(self
, force
= False):
563 while (len(self
._changesetautodata
) >= self
._changesetautosize
) or (force
and self
._changesetautodata
):
564 if self
._changesetautocpt
== 0:
565 self
.ChangesetCreate(self
._changesetautotags
)
566 self
.ChangesetUpload(self
._changesetautodata
[:self
._changesetautosize
])
567 self
._changesetautodata
= self
._changesetautodata
[self
._changesetautosize
:]
568 self
._changesetautocpt
+= 1
569 if self
._changesetautocpt
== self
._changesetautomulti
:
570 self
.ChangesetClose()
571 self
._changesetautocpt
= 0
572 if self
._changesetautocpt
and force
:
573 self
.ChangesetClose()
574 self
._changesetautocpt
= 0
577 def _http_request(self
, cmd
, path
, auth
, send
):
581 path2
= path2
[:50]+"[...]"
582 print >>sys
.stderr
, "%s %s %s"%(time
.strftime("%Y-%m-%d %H:%M:%S"),cmd
,path2
)
583 self
._conn
.putrequest(cmd
, path
)
584 self
._conn
.putheader('User-Agent', self
._created
_by
)
586 self
._conn
.putheader('Authorization', 'Basic ' + base64
.encodestring(self
._username
+ ':' + self
._password
).strip())
588 self
._conn
.putheader('Content-Length', len(send
))
589 self
._conn
.endheaders()
591 self
._conn
.send(send
)
592 response
= self
._conn
.getresponse()
593 if response
.status
<> 200:
594 payload
= response
.read().strip()
595 if response
.status
== 410:
597 raise ApiError(response
.status
, response
.reason
, payload
)
599 print >>sys
.stderr
, "%s %s %s done"%(time
.strftime("%Y-%m-%d %H:%M:%S"),cmd
,path2
)
600 return response
.read()
602 def _http(self
, cmd
, path
, auth
, send
):
607 return self
._http
_request
(cmd
, path
, auth
, send
)
611 if i
<> 1: time
.sleep(5)
612 self
._conn
= httplib
.HTTPConnection(self
._api
, 80)
616 if i
<> 1: time
.sleep(5)
617 self
._conn
= httplib
.HTTPConnection(self
._api
, 80)
619 def _get(self
, path
):
620 return self
._http
('GET', path
, False, None)
622 def _put(self
, path
, data
):
623 return self
._http
('PUT', path
, True, data
)
625 def _delete(self
, path
, data
):
626 return self
._http
('DELETE', path
, True, data
)
628 #######################################################################
629 # Internal dom function #
630 #######################################################################
632 def _DomGetAttributes(self
, DomElement
):
633 """ Returns a formated dictionnary of attributes of a DomElement. """
635 for k
, v
in DomElement
.attributes
.items():
636 if k
== u
"uid" : v
= int(v
)
637 elif k
== u
"changeset" : v
= int(v
)
638 elif k
== u
"version" : v
= int(v
)
639 elif k
== u
"id" : v
= int(v
)
640 elif k
== u
"lat" : v
= float(v
)
641 elif k
== u
"lon" : v
= float(v
)
642 elif k
== u
"open" : v
= v
=="true"
643 elif k
== u
"visible" : v
= v
=="true"
644 elif k
== u
"ref" : v
= int(v
)
648 def _DomGetTag(self
, DomElement
):
649 """ Returns the dictionnary of tags of a DomElement. """
651 for t
in DomElement
.getElementsByTagName("tag"):
652 k
= t
.attributes
["k"].value
653 v
= t
.attributes
["v"].value
657 def _DomGetNd(self
, DomElement
):
658 """ Returns the list of nodes of a DomElement. """
660 for t
in DomElement
.getElementsByTagName("nd"):
661 result
.append(int(int(t
.attributes
["ref"].value
)))
664 def _DomGetMember(self
, DomElement
):
665 """ Returns a list of relation members. """
667 for m
in DomElement
.getElementsByTagName("member"):
668 result
.append(self
._DomGetAttributes
(m
))
671 def _DomParseNode(self
, DomElement
):
672 """ Returns NodeData for the node. """
673 result
= self
._DomGetAttributes
(DomElement
)
674 result
[u
"tag"] = self
._DomGetTag
(DomElement
)
677 def _DomParseWay(self
, DomElement
):
678 """ Returns WayData for the way. """
679 result
= self
._DomGetAttributes
(DomElement
)
680 result
[u
"tag"] = self
._DomGetTag
(DomElement
)
681 result
[u
"nd"] = self
._DomGetNd
(DomElement
)
684 def _DomParseRelation(self
, DomElement
):
685 """ Returns RelationData for the relation. """
686 result
= self
._DomGetAttributes
(DomElement
)
687 result
[u
"tag"] = self
._DomGetTag
(DomElement
)
688 result
[u
"member"] = self
._DomGetMember
(DomElement
)
691 def _DomParseChangeset(self
, DomElement
):
692 """ Returns ChangesetData for the changeset. """
693 result
= self
._DomGetAttributes
(DomElement
)
694 result
[u
"tag"] = self
._DomGetTag
(DomElement
)
697 #######################################################################
698 # Internal xml builder #
699 #######################################################################
701 def _XmlBuild(self
, ElementType
, ElementData
, WithHeaders
= True):
705 xml
+= u
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
706 xml
+= u
"<osm version=\"0.6\" generator=\"" + self
._created
_by
+ "\">\n"
708 # <element attr="val">
709 xml
+= u
" <" + ElementType
710 if u
"id" in ElementData
:
711 xml
+= u
" id=\"" + str(ElementData
[u
"id"]) + u
"\""
712 if u
"lat" in ElementData
:
713 xml
+= u
" lat=\"" + str(ElementData
[u
"lat"]) + u
"\""
714 if u
"lon" in ElementData
:
715 xml
+= u
" lon=\"" + str(ElementData
[u
"lon"]) + u
"\""
716 if u
"version" in ElementData
:
717 xml
+= u
" version=\"" + str(ElementData
[u
"version"]) + u
"\""
718 xml
+= u
" visible=\"" + str(ElementData
.get(u
"visible", True)).lower() + u
"\""
719 if ElementType
in [u
"node", u
"way", u
"relation"]:
720 xml
+= u
" changeset=\"" + str(self
._CurrentChangesetId
) + u
"\""
724 for k
, v
in ElementData
.get(u
"tag", {}).items():
725 xml
+= u
" <tag k=\""+self
._XmlEncode
(k
)+u
"\" v=\""+self
._XmlEncode
(v
)+u
"\"/>\n"
728 for member
in ElementData
.get(u
"member", []):
729 xml
+= u
" <member type=\""+member
[u
"type"]+"\" ref=\""+str(member
[u
"ref"])+u
"\" role=\""+self
._XmlEncode
(member
[u
"role"])+"\"/>\n"
732 for ref
in ElementData
.get(u
"nd", []):
733 xml
+= u
" <nd ref=\""+str(ref
)+u
"\"/>\n"
736 xml
+= u
" </" + ElementType
+ u
">\n"
741 return xml
.encode("utf8")
743 def _XmlEncode(self
, text
):
744 return text
.replace("&", "&").replace("\"", """).replace("<","<").replace(">",">")
746 ## End of main class ##
747 ###########################################################################