Skip to content

Instantly share code, notes, and snippets.

@dmd
Created March 5, 2022 15:36
Show Gist options
  • Save dmd/823add215b1af43c5663b7bc52d02f11 to your computer and use it in GitHub Desktop.
Save dmd/823add215b1af43c5663b7bc52d02f11 to your computer and use it in GitHub Desktop.
# Photos - XML metadata to printable
1. Read the XML file
2. Drop fields, reformat GPS
Transform:
```
out :: reformat(in) =
begin
let clat = in.RDF.Description.Composite_GPSLatitude; // 40 deg 40' 27.16" N
let clon = in.RDF.Description.Composite_GPSLongitude; // 73 deg 55' 50.80" W
let clatDMSF = re_split(clat, '\\D+')[0:4];
let clonDMSF = re_split(clon, '\\D+')[0:4];
let lat_deg = (float)(decimal(''))clatDMSF[0];
let lat_min = (float)(decimal(''))clatDMSF[1];
let lat_sec = (float)(decimal(''))clatDMSF[2];
let lat_fra = (float)(decimal(''))clatDMSF[3];
let lon_deg = (float)(decimal(''))clonDMSF[0];
let lon_min = (float)(decimal(''))clonDMSF[1];
let lon_sec = (float)(decimal(''))clonDMSF[2];
let lon_fra = (float)(decimal(''))clatDMSF[3];
let lat_sign = if (is_defined(re_get_match(clat, '[swSW]'))) -1 else 1;
let lon_sign = if (is_defined(re_get_match(clon, '[swSW]'))) -1 else 1;
let lat = lat_sign * (lat_deg + lat_min / 60 + lat_sec / 3600 + lat_fra / 36000);
let lon = lon_sign * (lon_deg + lon_min / 60 + lon_sec / 3600 + lon_fra / 36000);
out.FileName :: in.RDF.Description.FileName;
out.DateTimeOriginal :: first_defined(in.RDF.Description.DateTimeOriginal,in.RDF.Description.DateTimeCreated);
out.Description :: first_defined(in.RDF.Description.Description,in.RDF.Description.ImageDescription, '');
out.Title:: if (is_null(in.RDF.Description.Title) or in.RDF.Description.Title == 'Untitled' ) '' else in.RDF.Description.Title;
out.Keywords:: vector_sort_dedup_first(in.RDF.Description.Keywords.Bag.li);
out.ImageSize :: in.RDF.Description.ImageSize;
out.GPSPosition :: in.RDF.Description.GPSPosition;
out.GPSLatitudeDecimal :: first_defined(lat, '0');
out.GPSLongitudeDecimal :: first_defined(lon, '0');
end;
```
Output DML:
```
record
string('') FileName;
datetime('YYYY:MM:DD HH24:MI:SS') DateTimeOriginal;
utf8 string('') Description = NULL;
utf8 string('') Title = NULL;
utf8 string('')[int] Keywords = NULL;
string('') ImageSize;
string('') GPSPosition = NULL;
decimal('') GPSLatitudeDecimal;
decimal('') GPSLongitudeDecimal;
end;
```
3. Enrich location
```
constant string('') GOOGLE_GEO_API_KEY parameter; // AIzaSyDtYAOwrl8hpVm43H3lcJpMRn6gJL8L6Fg
constant string('') GOOGLE_GEO_URL parameter; // https://maps.googleapis.com/maps/api/geocode/xml
request :: prepare_request(in) =
begin
request.request_url :: GOOGLE_GEO_URL;
request.request_url_params :: [vector [record name "latlng" value string_concat(in.GPSLatitudeDecimal, ',', in.GPSLongitudeDecimal)], [record name "key" value GOOGLE_GEO_API_KEY]];
end;
out :: create_output(in, responses) =
begin
out.FileName :: in.FileName;
out.response_body::reinterpret(responses.response_body);
end;
```
4. Parse the geoxml
DML:
```
type xml_doc_t = utf8 record
decimal('') seq_num;
string('')[big endian integer(4)] formatted_address;
string('',charset="x-ab-internal") XML_fields() = 'seq_num=seqnum(),=GeocodeResponse/%e/status,=GeocodeResponse/%e/result{1-n}/%e/type{1-n},formatted_address=GeocodeResponse/%e/result{1-n}/%e/formatted_address/text(),=GeocodeResponse/%e/result{1-n}/%e/address_component{1-n},=GeocodeResponse/%e/result{1-n}/%e/geometry,=GeocodeResponse/%e/result{1-n}/%e/place_id';
string('',charset="x-ab-internal") XML_generated_by_version() = '3.2.6.0';
string('',charset="x-ab-internal") XML_generated_at_compatibility() = '';
end;
metadata type = record
string('') FileName;
string('') DateTimeOriginal;
utf8 string('') Description = NULL;
utf8 string('') Title = NULL;
utf8 string('')[big endian integer(4)] Keywords = NULL;
string('') ImageSize;
string('') GPSPosition = NULL;
decimal('') GPSLatitudeDecimal;
decimal('') GPSLongitudeDecimal;
xml_doc_t geo;
end;
```
5. Reformat for text output
Transform:
```
out :: reformat(in) =
begin
out.* :: in.*;
out.GPSCoords :: (string(''))in.GPSLatitudeDecimal + ',' + (string(''))in.GPSLongitudeDecimal;
out.Place :: string_join(in.geo.formatted_address[0:3], '\n');
out.Keywords :: string_join(in.Keywords, ', ');
out.FileName :: string_replace(in.FileName,'.jpg','');
end;
```
Final output DML:
```
record
string(6) lab_start_rec = '===== ';
string(' ') FileName;
string('\n') lab_start_rec_e = '=====';
string(6) lab_date = 'Date: ';
string('\n') DateTimeOriginal;
string(7) lab_title = 'Title: ';
utf8 string('\n') Title = NULL;
string(10) lab_desc = 'Desc\n----\n';
utf8 string('\n\n') Description = NULL;
string(10) lab_keywords = 'Keywords: ';
utf8 string('\n') Keywords = NULL;
string(6) lab_size = 'Size: ';
string('\n') ImageSize;
string(5) lab_gps = 'GPS: ';
string('\n') GPSCoords;
string(14) lab_place = 'Places\n------\n';
utf8 string('\n\n\n') Place;
//string(2) end_rec = '\n\n';
end;
```
Done!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment