function parse_osm_xml($uri) { global $messages; $r = new XMLReader(); if (!$r->open($uri, 'utf-8')) { $messages[] = _('Failed to open XML stream'); return; } $result = array(); $mode = false; $cur = array(); while ($r->read()) { if ($r->nodeType == XMLReader::ELEMENT) { if ($r->name == 'modify' || $r->name == 'create' || $r->name == 'delete') { $mode = $r->name; } elseif ($r->name == 'node' || $r->name == 'way' || $r->name == 'relation' || $r->name == 'changeset') { $id = $r->getAttribute('id'); if ($id === null) { $id = 0; } if (is_pint($id)) { $cur['type'] = $r->name; $cur['id'] = $id; $action = $mode ? $mode : $r->getAttribute('action'); if ($action) { $cur['action'] = $action; } // user, uid, visible, changeset, timestamp $version = $r->getAttribute('version'); $user = $r->getAttribute('user'); $uid = $r->getAttribute('uid'); $visible = $r->getAttribute('visible'); $changeset = $r->getAttribute('changeset'); $timestamp = $r->getAttribute('timestamp'); if (is_pint($version, true)) { $cur['version'] = $version; } if ($user !== null && strlen($user) > 0) { $cur['user'] = $user; } if (is_pint($uid, true)) { $cur['uid'] = $uid; } if (is_pint($changeset, true)) { $cur['changeset'] = $changeset; } if ($timestamp != null && strlen($timestamp) > 10) { $cur['timestamp'] = $timestamp; } // parse? if ($visible === 'false') { $cur['deleted'] = true; } $cur['tags'] = array(); if ($r->name == 'node') { $lat = $r->getAttribute('lat'); $lon = $r->getAttribute('lon'); if (is_numeric($lat) && is_numeric($lon)) { $cur['lat'] = $lat; $cur['lon'] = $lon; } } elseif ($r->name == 'way') { $cur['nodes'] = array(); } elseif ($r->name == 'relation') { $cur['members'] = array(); } } } elseif ($r->name == 'tag') { $key = $r->getAttribute('k'); $value = $r->getAttribute('v'); if ($key !== null && $value !== null) { $tkey = hard_trim($key); $tvalue = hard_trim($value); if (strlen($tkey) > 0 && strlen($tvalue) > 0) { $cur['tags'][$tkey] = $tvalue; } if (!isset($cur['action']) && ($key !== $tkey || $value !== $tvalue)) { $cur['action'] = 'modify'; } } } elseif ($r->name == 'nd') { $ref = $r->getAttribute('ref'); if (is_pint($ref)) { $cur['nodes'][] = $ref; } } elseif ($r->name == 'member') { $mtype = $r->getAttribute('type'); $mref = $r->getAttribute('ref'); $mrole = $r->getAttribute('role'); if ($mtype !== null && preg_match('/^(?:node|way|relation)$/', $mtype) && is_pint($mref)) { $member = array('type' => $mtype, 'id' => $mref); $member['role'] = $mrole === null ? '' : $mrole; $cur['members'][] = $member; } } } if ($r->nodeType == XMLReader::END_ELEMENT || $r->isEmptyElement) { if ($r->name == $mode) { $mode = false; } elseif (isset($cur['type']) && $r->name == $cur['type']) { if (isset($cur['version']) && $cur['version'] > 1) { // if $result contains older version, remove it for ($i = 0; $i < count($result); $i++) { if ($result[$i]['type'] == $cur['type'] && $result[$i]['id'] == $cur['id'] && (!isset($result['version']) || $result['version'] <= $cur['version'])) { array_splice($result, $i, 1); break; } } } $result[] = $cur; $cur = array(); } } if (count($result) == MAX_REQUEST_OBJECTS) { $messages[] = sprintf(_('Download is incomplete, maximum of %d objects has been reached'), MAX_REQUEST_OBJECTS); break; } } $r->close(); return renumber_created($result); }
function update_data($data) { global $basedata, $userdata, $messages, $added, $modified; // arrays for merging if (!isset($added) || !isset($modified)) { $added = array(); $modified = array(); } if (count($userdata)) { $data = renumber_created($data, $userdata); } // nb: this is already done in osmapi.php foreach ($data as $obj) { $objnv = strip_version($obj); if ($obj['type'] == 'changeset') { // check that created changeset metadata is not duplicated if ($obj['id'] > 0) { $found = false; foreach ($userdata as $obj) { if ($obj['type'] == 'changeset' && $obj['id'] <= 0) { $found = true; break; } } if ($found) { $messages[] = _('There can be only one changeset metadata') . '.'; continue; } } $userdata[] = $objnv; $added[] = $objnv; } elseif ($obj['id'] <= 0 || isset($obj['action']) && $obj['action'] == 'create') { // created objects go straight to userdata $userdata[] = $objnv; $added[] = $objnv; } else { // modify, delete or base if (!isset($obj['version'])) { $messages[] = sprintf(_('No version for object %s %s.'), $obj['type'], $obj['id']); continue; } if (isset($obj['action']) && strlen($obj['action']) > 0) { // for deleted and modified save only version $res = array('type' => $obj['type'], 'id' => $obj['id'], 'version' => $obj['version'], 'complete' => false); } else { $res = $obj; $res['complete'] = true; } // $res goes to basedata, $obj should be merged with userdata $pk = $res['type'] . $res['id']; $version_diff = $res['version'] - (isset($basedata[$pk]) ? $basedata[$pk]['version'] : 0); if (!isset($basedata[$pk]) || !$version_diff) { if (!isset($basedata[$pk]) || !$basedata[$pk]['complete']) { $basedata[$pk] = $res; } // userdata: if exists and modified, leave current version, otherwise replace $found = false; for ($i = 0; $i < count($userdata); $i++) { if ($userdata[$i]['type'] == $res['type'] && $userdata[$i]['id'] == $res['id']) { $found = true; if (!is_modified($userdata[$i])) { // should we replace it with the new version? idk. // $userdata[$i] = $objnv; // $modified[] = $objnv; } } } if (!$found) { $userdata[] = $objnv; $added[] = $objnv; } } elseif ($version_diff < 0) { // it's really old, skip it $messages[] = sprintf(_('Found older version of %s %s: %d instead of %d.'), $res['type'], $res['id'], $res['version'], $basedata[$pk]['version']); } else { $basedata[$pk] = $res; // userdata: if exists and modified, then conflict! $found = false; for ($i = 0; $i < count($userdata); $i++) { if ($userdata[$i]['type'] == $res['type'] && $userdata[$i]['id'] == $res['id']) { $found = true; if (is_modified($userdata[$i])) { $objnv['conflict'] = $userdata[$i]; $userdata[$i] = $objnv; $modified[] = $objnv; } } } if (!$found) { $userdata[] = $objnv; $added[] = $objnv; } } } } }