// searchExtern searches an extern id. func searchExtern(serv string, extern []string) string { seid := serv + ":" for _, e := range extern { sv, id, _ := jdh.ParseExtern(e) if sv == seid { return id } } return "" }
// Validate validates that a taxon is valid in the database, and set some // canonical values. It returns an error if the taxon is not valid. func (t *taxonomy) validate(tax *jdh.Taxon) error { tax.Id = strings.TrimSpace(tax.Id) tax.Name = strings.Join(strings.Fields(tax.Name), " ") if (len(tax.Id) == 0) || (len(tax.Name) == 0) { return errors.New("taxon without identification") } if _, ok := t.ids[tax.Id]; ok { return fmt.Errorf("taxon id %s already in use", tax.Id) } p := t.root if tax.Rank > jdh.Species { tax.Rank = jdh.Unranked } if len(tax.Parent) > 0 { var ok bool if p, ok = t.ids[tax.Parent]; !ok { return fmt.Errorf("taxon %s parent [%s] not in database", tax.Name, tax.Parent) } } if p == t.root { if !tax.IsValid { return fmt.Errorf("taxon %s is a synonym without a parent", tax.Name) } } else if !p.data.IsValid { return fmt.Errorf("taxon %s parent [%s] is a synonym", tax.Name, p.data.Name) } if !p.isDescValid(tax.Rank, tax.IsValid) { return fmt.Errorf("taxon %s rank incompatible with database hierarchy", tax.Name) } ext := tax.Extern tax.Extern = nil for _, e := range ext { serv, id, err := jdh.ParseExtern(e) if err != nil { continue } if len(id) == 0 { continue } add := true for _, ex := range tax.Extern { if strings.HasPrefix(ex, serv) { add = false break } } if !add { continue } if _, ok := t.ids[e]; !ok { tax.Extern = append(tax.Extern, e) } } return nil }
// Validate validates that a raster is valid in the database, and set some // canonical values. It returns an error if the raster is not valid. func (d *distros) validate(ras *jdh.Raster) error { ras.Id = strings.TrimSpace(ras.Id) ras.Taxon = strings.TrimSpace(ras.Taxon) if (len(ras.Id) == 0) || (len(ras.Taxon) == 0) { return errors.New("raster without identification") } if _, ok := d.ids[ras.Id]; ok { return fmt.Errorf("raster id %s already in use", ras.Id) } if !d.db.t.isInDB(ras.Taxon) { return fmt.Errorf("taxon %s [associated with raster %s] not in dabtase", ras.Taxon, ras.Id) } if ras.Cols == 0 { return fmt.Errorf("raster %s with an invalid number of cols: 0", ras.Id) } if ras.Raster == nil { return fmt.Errorf("raster %s without rasterized data", ras.Id) } if ras.Source > jdh.MachineModel { ras.Source = jdh.UnknownRaster } ras.Reference = strings.TrimSpace(ras.Reference) ext := ras.Extern ras.Extern = nil for _, e := range ext { serv, id, err := jdh.ParseExtern(e) if err != nil { continue } if len(id) == 0 { continue } add := true for _, ex := range ras.Extern { if strings.HasPrefix(ex, serv) { add = false break } } if !add { continue } if _, ok := d.ids[e]; !ok { ras.Extern = append(ras.Extern, e) } } return nil }
// Validates that a dataset is valid in the database. When posible canonical // values will be set. If the dataset is invalid it will return an error. func (d *datasets) validate(set *jdh.Dataset) error { set.Id = strings.TrimSpace(set.Id) set.Title = strings.Join(strings.Fields(set.Title), " ") if (len(set.Id) == 0) || (len(set.Title) == 0) { return errors.New("dataset without identification") } if _, ok := d.ids[set.Id]; ok { return fmt.Errorf("dataset id %s already in use", set.Id) } set.Citation = strings.Join(strings.Fields(set.Citation), " ") set.License = strings.Join(strings.Fields(set.License), " ") if u, err := url.Parse(set.Url); err != nil { set.Url = "" } else { set.Url = u.String() } ext := set.Extern set.Extern = nil for _, e := range ext { serv, id, err := jdh.ParseExtern(e) if err != nil { continue } if len(id) == 0 { continue } add := true for _, ex := range set.Extern { if strings.HasPrefix(ex, serv) { add = false break } } if !add { continue } if _, ok := d.ids[e]; !ok { set.Extern = append(set.Extern, e) } } return nil }
// AddExtern adds an extern id to an specimen. func (tr *trees) addExtern(ph *phylogeny, extern string) error { serv, id, err := jdh.ParseExtern(extern) if err != nil { return err } if len(id) == 0 { return nil } if or, ok := tr.ids[extern]; ok { return fmt.Errorf("extern id %s of %s alredy in use by %s", extern, ph.data.Id, or.data.Id) } // the service is already assigned, then overwrite for i, e := range ph.data.Extern { if strings.HasPrefix(e, serv) { delete(tr.ids, e) ph.data.Extern[i] = extern tr.ids[extern] = ph return nil } } ph.data.Extern = append(ph.data.Extern, extern) tr.ids[extern] = ph return nil }
// ValPhy validates that a tree is valid in the database, and set some // canonical values. It returns an error if the tree is not valid. func (tr *trees) valPhy(phy *jdh.Phylogeny) error { phy.Id = strings.TrimSpace(phy.Id) if len(phy.Id) == 0 { return errors.New("phylogeny without identification") } if _, ok := tr.ids[phy.Id]; ok { return fmt.Errorf("phylogeny id %s alredy in use", phy.Id) } phy.Name = strings.Join(strings.Fields(phy.Name), " ") phy.Root = "" ext := phy.Extern phy.Extern = nil for _, e := range ext { serv, id, err := jdh.ParseExtern(e) if err != nil { continue } if len(id) == 0 { continue } add := true for _, ex := range phy.Extern { if strings.HasPrefix(ex, serv) { add = false break } } if !add { continue } if _, ok := tr.ids[e]; !ok { phy.Extern = append(phy.Extern, e) } } return nil }
// AddExtern adds an extern id to an specimen. func (d *distros) addExtern(rd *raster, extern string) error { serv, id, err := jdh.ParseExtern(extern) if err != nil { return err } if len(id) == 0 { return nil } if or, ok := d.ids[extern]; ok { return fmt.Errorf("extern id %s of %s alredy in use by %s", extern, rd.data.Id, or.data.Id) } // the service is already assigned, then overwrite for i, e := range rd.data.Extern { if strings.HasPrefix(e, serv) { delete(d.ids, e) rd.data.Extern[i] = extern d.ids[extern] = rd return nil } } rd.data.Extern = append(rd.data.Extern, extern) d.ids[extern] = rd return nil }
// AddExtern adds an extern id to a taxon. func (t *taxonomy) addExtern(tx *taxon, extern string) error { serv, id, err := jdh.ParseExtern(extern) if err != nil { return err } if len(id) == 0 { return nil } if ot, ok := t.ids[extern]; ok { return fmt.Errorf("extern id %s of %s alredy in use by %s", extern, tx.data.Name, ot.data.Name) } // the service is already assigned, then overwrite for i, e := range tx.data.Extern { if strings.HasPrefix(e, serv) { delete(t.ids, e) tx.data.Extern[i] = extern t.ids[extern] = tx return nil } } tx.data.Extern = append(tx.data.Extern, extern) t.ids[extern] = tx return nil }
// AddExtern adds an extern id to a dataset. func (d *datasets) addExtern(sd *setData, extern string) error { serv, id, err := jdh.ParseExtern(extern) if err != nil { return err } if len(id) == 0 { return nil } if ot, ok := d.ids[extern]; ok { return fmt.Errorf("extern id %s of %s alredy in use by %s", extern, sd.data.Id, ot.data.Id) } // the service is already assigned, then overwrite for i, e := range sd.data.Extern { if strings.HasPrefix(e, serv) { delete(d.ids, e) sd.data.Extern[i] = extern d.ids[extern] = sd return nil } } sd.data.Extern = append(sd.data.Extern, extern) d.ids[extern] = sd return nil }
// AddExtern adds an extern id to an specimen. func (s *specimens) addExtern(sp *specimen, extern string) error { serv, id, err := jdh.ParseExtern(extern) if err != nil { return err } if len(id) == 0 { return nil } if or, ok := s.ids[extern]; ok { return fmt.Errorf("extern id %s of %s alredy in use by %s", extern, sp.data.Id, or.data.Id) } // the service is already assigned, then overwrite for i, e := range sp.data.Extern { if strings.HasPrefix(e, serv) { delete(s.ids, e) sp.data.Extern[i] = extern s.ids[extern] = sp return nil } } sp.data.Extern = append(sp.data.Extern, extern) s.ids[extern] = sp return nil }
// SetTree sets a value of a tree in the database. func (tr *trees) setTree(vals []jdh.KeyValue) error { id := "" for _, kv := range vals { if len(kv.Value) == 0 { continue } if kv.Key == jdh.KeyId { id = kv.Value[0] break } } if len(id) == 0 { return errors.New("tree without identification") } ph, ok := tr.ids[id] if !ok { return nil } phy := ph.data for _, kv := range vals { switch kv.Key { case jdh.TreName: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if phy.Name == v { continue } phy.Name = v case jdh.KeyComment: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if phy.Comment == v { continue } phy.Comment = v case jdh.KeyExtern: ok := false for _, v := range kv.Value { v = strings.TrimSpace(v) if len(v) == 0 { continue } serv, ext, err := jdh.ParseExtern(v) if err != nil { return err } if len(ext) == 0 { if !tr.delExtern(ph, serv) { continue } ok = true continue } if tr.addExtern(ph, v) != nil { continue } ok = true } if !ok { continue } default: continue } tr.changed = true } return nil }
// Set sets a value of a raster in the database. func (d *distros) set(vals []jdh.KeyValue) error { id := "" for _, kv := range vals { if len(kv.Value) == 0 { continue } if kv.Key == jdh.KeyId { id = kv.Value[0] break } } if len(id) == 0 { return errors.New("raster without identification") } rd, ok := d.ids[id] if !ok { return nil } ras := rd.data for _, kv := range vals { switch kv.Key { case jdh.RasPixel: if len(kv.Value) == 0 { continue } v := strings.TrimSpace(kv.Value[0]) if len(v) == 0 { continue } coor := strings.Split(v, ",") if len(coor) != 3 { return errors.New("invalid raster pixel reference: " + v) } x64, err := strconv.ParseInt(coor[0], 10, 0) if err != nil { return err } y64, err := strconv.ParseInt(coor[1], 10, 0) if err != nil { return err } p64, err := strconv.ParseInt(coor[2], 10, 0) if err != nil { return err } pt, px := image.Pt(int(x64), int(y64)), int(p64) if ras.Raster.At(pt) == px { continue } ras.Raster.Set(pt, px) case jdh.RDisSource: v := jdh.UnknownRaster if len(kv.Value) > 0 { v = jdh.GetRasterSource(strings.TrimSpace(kv.Value[0])) } if ras.Source == v { continue } case jdh.RDisTaxon: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if len(v) == 0 { continue } if ras.Taxon == v { continue } tax, ok := d.taxId[v] if !ok { if !d.db.t.isInDB(v) { continue } tax = &rasTaxon{ id: v, rsLs: list.New(), } tax.elem = d.taxLs.PushBack(tax) d.taxId[tax.id] = tax } oldtax := rd.taxon oldtax.rsLs.Remove(rd.elem) rd.elem = tax.rsLs.PushBack(rd) rd.taxon = tax rd.data.Taxon = tax.id if oldtax.rsLs.Len() == 0 { oldtax.rsLs = nil d.taxLs.Remove(oldtax.elem) oldtax.elem = nil delete(d.taxId, oldtax.id) } case jdh.KeyComment: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if ras.Comment == v { continue } ras.Comment = v case jdh.KeyExtern: ok := false for _, v := range kv.Value { v = strings.TrimSpace(v) if len(v) == 0 { continue } serv, ext, err := jdh.ParseExtern(v) if err != nil { return err } if len(ext) == 0 { if !d.delExtern(rd, serv) { continue } ok = true continue } if d.addExtern(rd, v) != nil { continue } ok = true } if !ok { continue } case jdh.KeyReference: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if ras.Reference == v { continue } ras.Reference = v default: continue } d.changed = true } return nil }
// Set sets a value of a taxon in the taxonomy. func (t *taxonomy) set(vals []jdh.KeyValue) error { id := "" for _, kv := range vals { if len(kv.Value) == 0 { continue } if kv.Key == jdh.KeyId { id = kv.Value[0] break } } if len(id) == 0 { return errors.New("taxon without identification") } tx, ok := t.ids[id] if !ok { return nil } tax := tx.data for _, kv := range vals { switch kv.Key { case jdh.KeyComment: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if tax.Comment == v { continue } tax.Comment = v case jdh.KeyExtern: ok := false for _, v := range kv.Value { v := strings.TrimSpace(v) if len(v) == 0 { continue } serv, ext, err := jdh.ParseExtern(v) if err != nil { continue } if len(ext) == 0 { if !t.delExtern(tx, serv) { continue } ok = true continue } if t.addExtern(tx, v) != nil { continue } ok = true } if !ok { continue } case jdh.TaxAuthority: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if tax.Authority == v { continue } tax.Authority = v case jdh.TaxName: nm := "" if len(kv.Value) > 0 { nm = strings.Join(strings.Fields(kv.Value[0]), " ") } if len(nm) == 0 { return fmt.Errorf("new name for %s undefined", tx.data.Name) } if tax.Name == nm { continue } // remove the old name nmLow := strings.ToLower(tax.Name) v := t.names.Lookup(nmLow).([]*taxon) v = delTaxFromList(v, tx) if len(v) > 0 { t.names.Set(nmLow, v) } else { t.names.Delete(nmLow) } tax.Name = nm // add the new name nmLow = strings.ToLower(tax.Name) vi := t.names.Lookup(nmLow) var txLs []*taxon if vi == nil { txLs = []*taxon{tx} } else { txLs = append(vi.([]*taxon), tx) } t.names.Set(nmLow, txLs) case jdh.TaxParent: p := t.root if len(kv.Value) > 0 { v := strings.TrimSpace(kv.Value[0]) if len(v) == 0 { continue } var ok bool p, ok = t.ids[v] if !ok { return fmt.Errorf("new parent [%s] for taxon %s not in database", kv.Value, tax.Name) } } if tx.parent == p { continue } if (!tax.IsValid) && (p == t.root) { return fmt.Errorf("taxon %s is a synonym, it requires a parent", tax.Name) } if (p != t.root) && (!p.data.IsValid) { return fmt.Errorf("new parent [%s] for taxon %s is a synonym", p.data.Name, tax.Name) } if !p.isDescValid(tax.Rank, tax.IsValid) { return fmt.Errorf("taxon %s rank incompatible with new parent [%s] hierarchy", tax.Name, p.data.Name) } tx.parent.childs = delTaxFromList(tx.parent.childs, tx) p.childs = append(p.childs, tx) tx.parent = p if p == t.root { tax.Parent = "" } else { tax.Parent = p.data.Id } case jdh.TaxRank: v := jdh.Unranked if len(kv.Value) > 0 { v = jdh.GetRank(strings.TrimSpace(kv.Value[0])) } if tax.Rank == v { continue } if !tx.parent.isDescValid(v, tax.IsValid) { return fmt.Errorf("new rank [%s] for taxon %s incompatible with taxonomy hierarchy", v, tax.Name) } tax.Rank = v case jdh.TaxSynonym: p := tx.parent if len(kv.Value) > 0 { v := strings.TrimSpace(kv.Value[0]) if len(v) == 0 { continue } var ok bool p, ok = t.ids[v] if !ok { return fmt.Errorf("new parent [%s] for taxon %s not in database", kv.Value, tax.Name) } } if (p == tx.parent) && (!tax.IsValid) { continue } if p == t.root { return fmt.Errorf("taxon %s can not be a synonym: no new parent defined", tax.Name) } if p != tx.parent { if !p.isDescValid(tax.Rank, false) { return fmt.Errorf("taxon %s rank incompatible with new parent [%s] hierarchy", tax.Name, p.data.Name) } tx.parent.childs = delTaxFromList(tx.parent.childs, tx) tx.parent = p tax.Parent = p.data.Id p.childs = append(p.childs, tx) } for _, d := range tx.childs { d.parent = p d.data.Parent = p.data.Id p.childs = append(p.childs, d) } tx.childs = nil tax.IsValid = false case jdh.TaxValid: if tax.IsValid { continue } tx.parent.childs = delTaxFromList(tx.parent.childs, tx) tx.parent = tx.parent.parent tx.data.Parent = tx.parent.data.Id tx.parent.childs = append(tx.parent.childs, tx) tax.IsValid = true default: continue } t.changed = true } return nil }
// Set sets one or more values of a dataset element. func (d *datasets) set(vals []jdh.KeyValue) error { id := "" for _, kv := range vals { if len(kv.Value) == 0 { continue } if kv.Key == jdh.KeyId { id = kv.Value[0] break } } if len(id) == 0 { return errors.New("dataset without identification") } sd, ok := d.ids[id] if !ok { return nil } set := sd.data for _, kv := range vals { switch kv.Key { case jdh.KeyComment: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if set.Comment == v { continue } set.Comment = v case jdh.KeyExtern: ok := false for _, v := range kv.Value { v = strings.TrimSpace(v) if len(v) == 0 { continue } serv, ext, err := jdh.ParseExtern(v) if err != nil { continue } if len(ext) == 0 { if !d.delExtern(sd, serv) { continue } ok = true continue } if d.addExtern(sd, v) != nil { continue } ok = true } if !ok { continue } case jdh.DataCitation: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if set.Citation == v { continue } set.Citation = v case jdh.DataLicense: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if set.License == v { continue } set.License = v case jdh.DataTitle: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if set.Title == v { continue } set.Title = v case jdh.DataUrl: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if len(v) == 0 { if len(set.Url) == 0 { continue } set.Url = "" break } u, err := url.Parse(v) if err != nil { continue } if set.Url == u.String() { continue } set.Url = u.String() } d.changed = true } return nil }
// Validate validates that an specimen is valid in the database, and set // some canonical values. It returns an error if the specimen is not valid. func (s *specimens) validate(spe *jdh.Specimen) error { spe.Id = strings.TrimSpace(spe.Id) spe.Taxon = strings.TrimSpace(spe.Taxon) if (len(spe.Id) == 0) || (len(spe.Taxon) == 0) { return errors.New("specimen without identification") } if _, ok := s.ids[spe.Id]; ok { return fmt.Errorf("specimen id %s already in use", spe.Id) } spe.Catalog = strings.TrimSpace(spe.Catalog) if len(spe.Catalog) > 0 { if _, ok := s.ids[spe.Catalog]; ok { return fmt.Errorf("specimen catalog code %s already in use", spe.Catalog) } } if !s.db.t.isInDB(spe.Taxon) { return fmt.Errorf("taxon %s [associated with specimen %s] not in database", spe.Taxon, spe.Id) } if !spe.Geography.IsValid() { spe.Geography = geography.Location{} } if !spe.Georef.IsValid() { spe.Georef = geography.InvalidGeoref() } else if (spe.Georef.Point.Lon == 0) || (spe.Georef.Point.Lon == 1) || (spe.Georef.Point.Lat == 0) || (spe.Georef.Point.Lat == 1) { spe.Georef = geography.InvalidGeoref() } if spe.Basis > jdh.Remote { spe.Basis = jdh.UnknownBasis } spe.Reference = strings.TrimSpace(spe.Reference) spe.Determiner = strings.Join(strings.Fields(spe.Determiner), " ") spe.Collector = strings.Join(strings.Fields(spe.Collector), " ") spe.Dataset = strings.TrimSpace(spe.Dataset) if len(spe.Dataset) > 0 { if !s.db.d.isInDB(spe.Dataset) { spe.Dataset = "" } } ext := spe.Extern spe.Extern = nil for _, e := range ext { serv, id, err := jdh.ParseExtern(e) if err != nil { continue } if len(id) == 0 { continue } add := true for _, ex := range spe.Extern { if strings.HasPrefix(ex, serv) { add = false break } } if !add { continue } if _, ok := s.ids[e]; !ok { spe.Extern = append(spe.Extern, e) } } return nil }
// Set sets a value of an specimen in the database. func (s *specimens) set(vals []jdh.KeyValue) error { id := "" for _, kv := range vals { if len(kv.Value) == 0 { continue } if kv.Key == jdh.KeyId { id = kv.Value[0] break } } if len(id) == 0 { return errors.New("specimen without identification") } sp, ok := s.ids[id] if !ok { return nil } spe := sp.data for _, kv := range vals { switch kv.Key { case jdh.SpeBasis: v := jdh.UnknownBasis if len(kv.Value) > 0 { v = jdh.GetBasisOfRecord(strings.TrimSpace(kv.Value[0])) } if spe.Basis == v { continue } spe.Basis = v case jdh.SpeCatalog: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Catalog == v { continue } if len(v) > 0 { if _, ok := s.ids[v]; ok { return fmt.Errorf("specimen catalog code %s already in use", kv.Value) } } if len(spe.Catalog) > 0 { delete(s.ids, spe.Catalog) } spe.Catalog = v if len(v) > 0 { s.ids[v] = sp } case jdh.SpeCollector: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Collector == v { continue } spe.Collector = v case jdh.SpeDataset: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Dataset == v { continue } if len(v) > 0 { if !s.db.d.isInDB(v) { continue } } spe.Dataset = v case jdh.SpeDate: if len(kv.Value) > 0 { v := strings.TrimSpace(kv.Value[0]) t, err := time.Parse(jdh.Iso8601, v) if err != nil { return err } if spe.Date.Equal(t) { continue } spe.Date = t break } if spe.Date.IsZero() { continue } spe.Date = time.Time{} case jdh.SpeDeterminer: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Determiner == v { continue } spe.Determiner = v case jdh.SpeLocality: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Locality == v { continue } spe.Locality = v case jdh.SpeTaxon: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if len(v) == 0 { continue } if spe.Taxon == v { continue } tax, ok := s.taxId[v] if !ok { if !s.db.t.isInDB(v) { continue } tax = &speTaxon{ id: v, specs: list.New(), } tax.elem = s.taxLs.PushBack(tax) s.taxId[tax.id] = tax } oldtax := sp.taxon oldtax.specs.Remove(sp.elem) sp.elem = tax.specs.PushBack(sp) sp.taxon = tax sp.data.Taxon = tax.id if oldtax.specs.Len() == 0 { oldtax.specs = nil s.taxLs.Remove(oldtax.elem) oldtax.elem = nil delete(s.taxId, oldtax.id) } case jdh.GeoCountry: v := geography.Country("") if len(kv.Value) > 0 { v = geography.GetCountry(strings.Join(strings.Fields(kv.Value[0]), " ")) } if spe.Geography.Country == v { continue } spe.Geography.Country = v case jdh.GeoCounty: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Geography.County == v { continue } spe.Geography.County = v case jdh.GeoLonLat: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if len(v) == 0 { if !spe.Georef.IsValid() { continue } spe.Georef = geography.InvalidGeoref() break } coor := strings.Split(v, ",") if len(coor) != 2 { return errors.New("invalid geographic coordinate values") } lon, err := strconv.ParseFloat(coor[0], 64) if err != nil { return err } lat, err := strconv.ParseFloat(coor[1], 64) if err != nil { return err } if (lon == 0) || (lon == 1) || (lat == 0) || (lat == 1) { return errors.New("invalid geographic coordinate values") } if (!geography.IsLon(lon)) || (!geography.IsLat(lat)) { return errors.New("invalid geographic coordinate values") } spe.Georef.Point = geography.Point{Lon: lon, Lat: lat} case jdh.GeoSource: if !spe.Georef.IsValid() { continue } v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Georef.Source == v { continue } spe.Georef.Source = v case jdh.GeoState: v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Geography.State == v { continue } spe.Geography.State = v case jdh.GeoUncertainty: if !spe.Georef.IsValid() { continue } v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } un64, err := strconv.ParseUint(v, 10, 0) if err != nil { return err } un := uint(un64) if un == spe.Georef.Uncertainty { continue } spe.Georef.Uncertainty = un case jdh.GeoValidation: if !spe.Georef.IsValid() { continue } v := "" if len(kv.Value) > 0 { v = strings.Join(strings.Fields(kv.Value[0]), " ") } if spe.Georef.Validation == v { continue } spe.Georef.Validation = v case jdh.KeyComment: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Comment == v { continue } spe.Comment = v case jdh.KeyExtern: ok := false for _, v := range kv.Value { v = strings.TrimSpace(v) if len(v) == 0 { continue } serv, ext, err := jdh.ParseExtern(v) if err != nil { return err } if len(ext) == 0 { if !s.delExtern(sp, serv) { continue } ok = true continue } if s.addExtern(sp, v) != nil { continue } ok = true } if !ok { continue } case jdh.KeyReference: v := "" if len(kv.Value) > 0 { v = strings.TrimSpace(kv.Value[0]) } if spe.Reference == v { continue } spe.Reference = v default: continue } s.changed = true } return nil }