@@ -6,7 +6,8 @@ import fs from 'fs-extra';
66import Zip from 'adm-zip' ;
77import { defaultHandler as upload } from '../upload' ;
88import { DOMParser , Document } from '@xmldom/xmldom' ;
9- import toGeoJson from '../utilities/togeojson' ;
9+ import kml from '../utilities/transformKML'
10+ import { Xslt , XmlParser } from 'xslt-processor' ;
1011
1112interface SecurityConfig {
1213 authentication : {
@@ -17,7 +18,7 @@ interface LayerRequest extends Request {
1718 layer : {
1819 type : string ;
1920 } ;
20- kml ?: Document ;
21+ features ?: any [ ] ;
2122 file ?: Express . Multer . File ;
2223}
2324
@@ -29,76 +30,116 @@ interface ImportResponse {
2930 } > ;
3031}
3132
32- function importRoutes ( app : Express , security : SecurityConfig ) : void {
33- const passport = security . authentication . passport ;
33+ const getMimeType = ( filename : string ) : string => {
34+ const ext = filename . toLowerCase ( ) . split ( '.' ) . pop ( ) || '' ;
35+ const mimeTypes : { [ key : string ] : string } = {
36+ 'png' : 'image/png' ,
37+ 'jpg' : 'image/jpeg' ,
38+ 'jpeg' : 'image/jpeg' ,
39+ 'gif' : 'image/gif' ,
40+ 'bmp' : 'image/bmp'
41+ } ;
42+ return mimeTypes [ ext ] || 'application/octet-stream' ;
43+ }
3444
35- function validate ( req : Request , res : Response , next : NextFunction ) : void | Response {
36- const layRequest = req as LayerRequest ;
37- if ( layRequest . layer . type !== 'Feature' ) {
38- return res . status ( 400 ) . send ( 'Cannot import data, layer type is not "Static".' ) ;
39- }
45+ const validate = async ( req : Request , res : Response , next : NextFunction ) : Promise < void | Response > => {
46+ const layRequest = req as LayerRequest ;
47+ if ( layRequest . layer . type !== 'Feature' ) {
48+ return res . status ( 400 ) . send ( 'Cannot import data, layer type is not "Static".' ) ;
49+ }
4050
41- if ( ! layRequest . file ) {
42- return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
43- }
51+ if ( ! layRequest . file ) {
52+ return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
53+ }
54+
55+ const fileExtension : string = layRequest . file . originalname . toLowerCase ( ) . split ( '.' ) . pop ( ) || '' ;
4456
45- const fileExtension : string = layRequest . file . originalname . toLowerCase ( ) . split ( '.' ) . pop ( ) || '' ;
57+ if ( ! [ 'kml' , 'kmz' ] . includes ( fileExtension ) ) {
58+ return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
59+ }
4660
47- if ( fileExtension === 'kmz' ) {
48- try {
49- const zip = new Zip ( layRequest . file . path ) ;
50- const zipEntries = zip . getEntries ( ) ;
51- const kmlEntry = zipEntries . find ( entry => entry . entryName . toLowerCase ( ) . endsWith ( '.kml' ) ) ;
61+ const parser = new DOMParser ( ) ;
62+ let geoJson : any ;
5263
53- if ( ! kmlEntry ) {
54- return res . status ( 400 ) . send ( 'No KML file found inside.' ) ;
55- }
64+ if ( fileExtension === 'kmz' ) {
65+ try {
66+ const zip = new Zip ( layRequest . file . path ) ;
67+ const zipEntries = zip . getEntries ( ) ;
68+ const kmlEntry = zipEntries . find ( entry => entry . entryName . toLowerCase ( ) . endsWith ( '.kml' ) ) ;
69+ // const xslEntry = zipEntries.find(entry => entry.entryName.toLowerCase().endsWith('.xsl') || entry.entryName.toLowerCase().endsWith('.xslt'));
5670
57- const kmlData : string = kmlEntry . getData ( ) . toString ( 'utf8' ) ;
58- processKmlData ( kmlData , layRequest , res , next ) ;
59- } catch ( err ) {
60- return res . status ( 400 ) . send ( 'Unable to extract contents from KMZ file.' ) ;
71+ if ( ! kmlEntry ) {
72+ return res . status ( 400 ) . send ( 'No KML file found inside.' ) ;
6173 }
62- } else if ( fileExtension === 'kml' ) {
63- fs . readFile ( layRequest . file . path , 'utf8' , function ( err : Error | null , data : string ) {
64- if ( err ) return next ( err ) ;
65- processKmlData ( data , layRequest , res , next ) ;
74+
75+ const images : { [ key : string ] : string } = { } ;
76+ zipEntries . forEach ( entry => {
77+ const entryName = entry . entryName ;
78+ if ( ! entry . isDirectory && / \. ( p n g | j p g | j p e g | g i f | b m p ) $ / i. test ( entryName ) ) {
79+ const buffer = entry . getData ( ) ;
80+ const base64 = buffer . toString ( 'base64' ) ;
81+ const mimeType = getMimeType ( entryName ) ;
82+ images [ entryName ] = `data:${ mimeType } ;base64,${ base64 } ` ;
83+ }
6684 } ) ;
67- } else {
68- return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
69- }
70- }
7185
72- function processKmlData ( data : string , req : LayerRequest , res : Response , next : NextFunction ) : void | Response {
73- const parser = new DOMParser ( ) ;
74- const kml : Document = parser . parseFromString ( data , "application/xml" ) ;
75- const parseError = kml . getElementsByTagName ( "parsererror" ) ;
86+ const kmlString = kmlEntry . getData ( ) . toString ( 'utf8' ) ;
87+
88+ // if (xslEntry) {
89+ // const xslString = xslEntry.getData().toString('utf8');
90+
91+ // const xslt = new Xslt({ cData: true, escape: false });
92+ // const xmlParser = new XmlParser();
93+
94+ // const outXmlString = await xslt.xsltProcess(
95+ // xmlParser.xmlParse(kmlString),
96+ // xmlParser.xmlParse(xslString)
97+ // );
98+ // console.log('outXmlString', outXmlString);
99+ // const transformedDocument = parser.parseFromString(outXmlString, 'text/xml');
100+ // geoJson = toGeoJson.kml(transformedDocument);
101+ // }
102+
103+ const kmlDocument = parser . parseFromString ( kmlString , 'text/xml' ) ;
104+ geoJson = kml ( kmlDocument as any , images ) ;
105+
106+ } catch ( err ) {
107+ return res . status ( 400 ) . send ( 'Unable to extract contents from KMZ file.' + err ) ;
108+ }
109+ } else {
110+ const fileData = fs . readFileSync ( layRequest . file . path , 'utf8' ) ;
111+ const kmlDocument : Document = parser . parseFromString ( fileData , 'application/xml' ) ;
112+ const parseError = kmlDocument . getElementsByTagName ( "parsererror" ) ;
76113
77114 if ( parseError . length > 0 ) {
78115 console . error ( "KML Parsing Error:" , parseError [ 0 ] . textContent ) ;
79116 } else {
80117 console . log ( "Parsed KML successfully" ) ;
81118 }
82119
83- if ( ! kml || kml . documentElement ?. nodeName !== 'kml' ) {
120+ if ( ! kmlDocument || kmlDocument . documentElement ?. nodeName !== 'kml' ) {
84121 return res . status ( 400 ) . send ( 'Invalid file, please upload a KML or KMZ file.' ) ;
85122 }
86123
87- req . kml = kml ;
88- return next ( ) ;
124+ geoJson = kml ( kmlDocument as any ) ;
89125 }
90126
127+ layRequest . features = geoJson ;
128+ return next ( ) ;
129+ }
130+
131+ function importRoutes ( app : Express , security : SecurityConfig ) : void {
132+ const passport = security . authentication . passport ;
133+
91134 app . post (
92135 '/api/layers/:layerId/kml' ,
93136 passport . authenticate ( 'bearer' ) ,
94137 access . authorize ( 'CREATE_LAYER' as AnyPermission ) ,
95138 upload . single ( 'file' ) ,
96139 validate ,
97- function ( req : Request , res : Response , next : NextFunction ) : void {
140+ ( req : Request , res : Response , next : NextFunction ) => {
98141 const layerRequest = req as LayerRequest ;
99- console . log ( 'Importing KML file:' , layerRequest . file ?. originalname ) ;
100- const features = toGeoJson . kml ( layerRequest . kml ! ) ;
101- new api . Feature ( layerRequest . layer ) . createFeatures ( features )
142+ new api . Feature ( layerRequest . layer ) . createFeatures ( layerRequest . features )
102143 . then ( ( newFeatures : any [ ] ) => {
103144 const response : ImportResponse = {
104145 files : [ {
0 commit comments