В данном случае меня интересовали: геометрия (lat, lon), имя (name), высота (ele), дата/время (cmt), символ(sym). Содержание <desc> дублирует <cmt>, с точки зрения MapSource: <cmt> - время, <desc> - комментарий к точке, <extensions> влияет только на отображение точки в MapSource. Символ <sym> записывается как string, лучше вынести в отдельную таблицу.
Я это называю - "собирать бисер". В SFA нет функций для редактирования геометрии (в PostGIS и Oracle Spatila - есть). По хорошему надо использовать WKB - но как сделать это на SQL - я не знаю. Поэтому использую WKT и колдую с текстом (longText, по началу использовал text - как то не хватило...). У MySQL есть пара неприятных моментов связанных с геометрией: при попытке создать в хранимке определённую геометрию (например LINESTRING) - MySQL меняет функцию на создание просто геометрии (и внезапно получаем MULTIPOINT, хотя может это косяк моей версии), поэтому я использовал geomfromtext и в строке явно указывал тип геометрии. При объявлении "Declare p1, p2 point;" p1, p2 - это указатели, а значит при set p1=p2 мы получаем два указателя на один объект. Что бы скопировать точку приходится городить такое : Set p1 = geomfromtext(concat('Point(', X(CrP), ' ', Y(CrP), ')'));
Для разработки модуля импорта данных, я выбрал VBA, по двум причинам: наиболее удобный IDE из доступных у меня на рабочей машине; наличие опыта и наработок. Перед началом работы, необходимо подключить Microsoft XML v6.0 (работа с XML) и Microsoft ActiveX Data Objects 2.8 Library (подключение БД). Также я использовал WinAPI, а именно GetOpenFileNameA из comdlg32.dll.
Изначально, было решено, разделить чтение и запись, что бы передать данные используются структуры: wpt_rec и trk_rec. В начале разработки, в отладочных целях, данные записывались на Лист в Excel'е - данный код приведён в листингах, но закомментирован. Некрасиво получилось то, что фильтрация исходных данных происходить в разных местах: для точек - при чтении XML'я (If cWPT.cmt <> "" Then 'У "ненужных" точек cWPT.cmt=""), для треков в начале записи в БД (If nTRK.s(0).p(0).time <> "" Then). Так же разделено преобразование даты/время, но здесь это оправданно - как было сказано выше, в точках и трэках время записано по разному.
'Переменные для записи данных на ЛистDimgIAsInteger,gJAsIntegerDimcRangeAsRangePublicTypewpt_rec'waypointslatAsDoublelonAsDoublenameAsStringeleAsDoublecmtAsString'select str_to_date('15-AUG-12 9:38:50', '%d-%M-%Y %H:%i:%s')symAsIntegerEndTypePublicTypetrk_pt_rec'Track PointlatAsDoublelonAsDoubleeleAsDoubletimeAsStringEndTypePublicTypetrk_seg'Track Segmentp()Astrk_pt_recEndTypePublicTypetrk_rec'tracklogsnameAsStrings()Astrk_segEndTypePublicSubOpenGPX(crFileAsString)'Обрабока gpxDimiAsIntegerDimObjDocAsMSXML2.DOMDocument60DimnNodeAsIXMLDOMNode'SetObjDoc=NewMSXML2.DOMDocument60ObjDoc.LoadcrFile'ОткрываемObjDoc.setProperty"SelectionNamespaces","xmlns=""http://www.topografix.com/GPX/1/1"""Fori=0ToObjDoc.DocumentElement.ChildNodes.Length-1'получаем узел и назначаем метод обработки, в зависемости от типаSetnNode=ObjDoc.DocumentElement.ChildNodes.Item(i)IfnNode.BaseName="wpt"ThenWork_wpt1nNodeIfnNode.BaseName="trk"ThenWork_trk1nNodeNextiEndSubPublicSubtest1()'Открываем gpx'ыDimiAsIntegerDimarr'StartWorksheet 'Получаем ЛистStart1'Подключаемся к БДarr=Split(OpenFile(0),Chr(0))'Проверяем количество файловIfUBound(arr)=1ThenOpenGPX(arr(0))ElseFori=1ToUBound(arr)-1OpenGPX(arr(0)&"\"&arr(i))NextiEndIf'MsgBox "Good"EndSubPublicSubWork_wpt1(nWPTAsIXMLDOMNode)'Обработка waypointsDimiAsInteger,symidAsIntegerDimcWPTAswpt_recDimnNodeAsIXMLDOMNode'nwptcWPT.lat=nWPT.Attributes.Item(0).TextcWPT.lon=nWPT.Attributes.Item(1).Text'cRange.Cells(gI, 3).Value = nwpt.ChildNodes.Item(1).TextFori=0TonWPT.ChildNodes.Length-1SetnNode=nWPT.ChildNodes.Item(i)SelectCasenNode.BaseName'Обрабатываем потомковCase"name":cWPT.name=nNode.TextCase"ele":cWPT.ele=nNode.TextCase"cmt":cWPT.cmt=nNode.TextCase"sym":cWPT.sym=GetSymId(nNode.Text)'cRange.Cells(gI, 6).Value = symid'cRange.Cells(gI, 7).Value = nNode.TextEndSelectNextiIfcWPT.cmt<>""Then'У "ненужных" точек cWPT.cmt=""'cRange.Cells(gI, 1).Value = cWPT.lat'cRange.Cells(gI, 2).Value = cWPT.lon'cRange.Cells(gI, 3).Value = cWPT.name'cRange.Cells(gI, 4).Value = cWPT.ele'cRange.Cells(gI, 5).Value = cWPT.cmt'cRange.Cells(gI, 6).Value = cWPT.sym'cRange.Cells(gI, 8).Value = SearchWPT(cWPT)InsWPTcWPT'Отправляем waypoints в БДEndIf'gI = gI + 1EndSubPublicSubStartWorksheet()' Получаем ЛистDiml1AsWorksheetSetWorksheet=Worksheets.Item("Лист1")SetcRange=Worksheet.CellsgI=1:gJ=1'cRange.Cells(1, 1).Value = "good"EndSubPublicFunctionWork_trkseg1(nTRKsegAsIXMLDOMNode)Astrk_seg'Обработка Track SegmentDimi,J,npAsIntegerDimWorkStrAsString'Dim cP As trk_pt_recDimnNodeAsIXMLDOMNodeDimnNode2AsIXMLDOMNode'nTRKnp=0Fori=0TonTRKseg.ChildNodes.Length-1SetnNode=nTRKseg.ChildNodes.Item(i)SelectCasenNode.BaseName'Обрабатываем потомковCase"trkpt"ReDimPreserveWork_trkseg1.p(np)Work_trkseg1.p(np).lat=nNode.Attributes.Item(0).TextWork_trkseg1.p(np).lon=nNode.Attributes.Item(1).TextForJ=0TonNode.ChildNodes.Length-1SetnNode2=nNode.ChildNodes.Item(J)SelectCasenNode2.BaseName'Обрабатываем потомковCase"ele":Work_trkseg1.p(np).ele=nNode2.TextCase"time"'Форматируем времяWorkStr=nNode2.TextWorkStr=Replace(WorkStr,"T"," ")WorkStr=Replace(WorkStr,"Z","")Work_trkseg1.p(np).time=WorkStrEndSelectNextJ'Work_trkseg1.p(np) = cPnp=np+1EndSelectNextiEndFunctionPublicSubWork_trk1(nTRKAsIXMLDOMNode)'Обработка tracklogsDimi,trksegAsIntegerDimcTRKAstrk_recDimnNodeAsIXMLDOMNode'nTRKtrkseg=0Fori=0TonTRK.ChildNodes.Length-1SetnNode=nTRK.ChildNodes.Item(i)SelectCasenNode.BaseName'Обрабатываем потомковCase"name":cTRK.name=nNode.TextCase"trkseg"ReDimPreservecTRK.s(trkseg)cTRK.s(trkseg)=Work_trkseg1(nNode)trkseg=trkseg+1EndSelectNexti'WrTrk cTRKInsTRKcTRK'Отправляем tracklogs в БДEndSubPublicSubWrTrk(cTRKAstrk_rec)'Обработка Track для записи на ЛистDimi,JAsIntegerFori=0ToUBound(cTRK.s)ForJ=0ToUBound(cTRK.s(i).p)'cRange.Cells(gI, 1).Value = cTRK.name'cRange.Cells(gI, 2).Value = I + 1'cRange.Cells(gI, 3).Value = cTRK.s(I).p(J).lat'cRange.Cells(gI, 4).Value = cTRK.s(I).p(J).lon'cRange.Cells(gI, 5).Value = cTRK.s(I).p(J).ele'cRange.Cells(gI, 6).Value = cTRK.s(I).p(J).timegI=gI+1NextJNexti'InsTRK cTRKEndSub
Загрузка в БД
DimMyConnectAsADODB.ConnectionPublicFunctionConnectToMySQL()AsADODB.Connection'Подключаемся к БДSetConnectToMySQL=NewADODB.ConnectionConnectToMySQL.ConnectionString="Driver={MySQL ODBC 5.1 Driver};Server=localhost;Database=gpx_DB;User=guest;Password=guest;Option=3;"ConnectToMySQL.OpenEndFunctionPublicSubStart1()'Подключаемся к БДSetMyConnect=ConnectToMySQLEndSub'"SELECT id FROM `gpx_db`.`symtbl` where `desc`="PublicFunctionGetSymId(SymDescAsString)AsInteger' Обрабатываем <sym>, получаем ключ из symtblDimStrSQLAsStringDimMyRSAsADODB.Recordset'SetMyRS=NewADODB.RecordsetSetMyRS.ActiveConnection=MyConnectMyRS.Source="SELECT id FROM `gpx_db`.`symtbl` where `desc`="""&SymDesc&""";"MyRS.OpenIfMyRS.BOFAndMyRS.EOFThenInsSymDesc(SymDesc)GetSymId=GetSymId(SymDesc)ElseGetSymId=MyRS.fields(0).ValueEndIfEndFunction'insert into `gpx_db`.`symtbl` values (null,'Restaurant')PublicSubInsSymDesc(SymDescAsString)'Добавляем новое значение <sym>MyConnect.Execute"insert into `gpx_db`.`symtbl` values (null,"""&SymDesc&""");"EndSub'SELECT * FROM wpt w where p=geomfromtext('POINT(60.5513457 59.5433567)') and cmt=str_to_date('15-AUG-12 9:38:50', '%d-%M-%Y %H:%i:%s');PublicFunctionSearchWPT(nWPTAswpt_rec)AsInteger'Ищем waypoints в БДDimStrSQLAsStringDimMyRSAsADODB.Recordset'SetMyRS=NewADODB.RecordsetSetMyRS.ActiveConnection=MyConnectMyRS.Source="SELECT id FROM wpt w where p=geomfromtext(""POINT("&nWPT.lon&" "&nWPT.lat&")"") and cmt="&_
"str_to_date("""&nWPT.cmt&""", ""%d-%M-%Y %H:%i:%s"");"MyRS.OpenIfMyRS.BOFAndMyRS.EOFThenSearchWPT=0ElseSearchWPT=MyRS.fields(0).ValueEndIfEndFunction'select str_to_date('15-AUG-12 9:38:50', '%d-%M-%Y %H:%i:%s')PublicSubInsWPT(nWPTAswpt_rec)'Добавляем waypoints в БДIfSearchWPT(nWPT)=0Then'Проверяем наличие'geomfromtext('Point(0 0)')MyConnect.Execute"insert into `gpx_db`.`wpt` values (null,geomfromtext(""Point("&nWPT.lon&" "&nWPT.lat&")""), """&nWPT.name&_
""", "&nWPT.ele&", str_to_date("""&nWPT.cmt&""", '%d-%M-%Y %H:%i:%s'), "&nWPT.sym&");"EndIfEndSub'SELECT id FROM trk t where name='ACTIVE LOG' and dt='2012-08-15 09:51:32';PublicFunctionSearchTRK(nTRKAstrk_rec)AsInteger'Ищем tracklogs в БДDimStrSQLAsStringDimMyRSAsADODB.Recordset'SetMyRS=NewADODB.RecordsetSetMyRS.ActiveConnection=MyConnectMyRS.Source="SELECT id FROM trk where name="""&nTRK.name&""" and dt=CONVERT_TZ(str_to_date("""&nTRK.s(0).p(0).time&_
""", '%Y-%m-%d %H:%i:%s'),'+00:00','+6:00');"'MyRS.Source = "select SearchTrk(" & nTRK.s(0).p(0).lon & ", " & nTRK.s(0).p(0).lat & ", CONVERT_TZ(str_to_date(""" & nTRK.s(0).p(0).time & _' """, '%Y-%m-%d %H:%i:%s'),'+00:00','+6:00'))"MyRS.OpenIfMyRS.BOFAndMyRS.EOFThenSearchTRK=0ElseSearchTRK=MyRS.fields(0).ValueEndIfEndFunctionPublicFunctionInsTRK(nTRKAstrk_rec)AsInteger'Добавляем tracklogs в БДDimresAsInteger'IfnTRK.s(0).p(0).time<>""Thenres=SearchTRK(nTRK)Ifres=0ThenMyConnect.Execute"insert into `gpx_db`.`trk` values (null, """&nTRK.name&""", 0, null, CONVERT_TZ(str_to_date("""&_
nTRK.s(0).p(0).time&""", '%Y-%m-%d %H:%i:%s'),'+00:00','+6:00'));"res=SearchTRK(nTRK)InsTRKptsnTRK,resMyConnect.Execute"call CreateTrkLine("&res&");"EndIfInsTRK=resEndIfEndFunctionPublicSubInsTRKpts(nTRKAstrk_rec,TRK_idAsInteger)'Добавляем Track Point в БДDimi,JAsInteger'Fori=0ToUBound(nTRK.s)ForJ=0ToUBound(nTRK.s(i).p)MyConnect.Execute"insert into `gpx_db`.`trkpt` values (null, "&TRK_id&", "&i+1&_
", geomfromtext(""Point("&nTRK.s(i).p(J).lon&" "&nTRK.s(i).p(J).lat&")""), "&_
"CONVERT_TZ(str_to_date("""&nTRK.s(i).p(J).time&""", '%Y-%m-%d %H:%i:%s'),'+00:00','+6:00'), "&_
nTRK.s(i).p(J).ele&");"NextJNextiEndSub