Ejemplo n.º 1
0
// returns a copy of a taxon
func (tx *taxon) copy() *jdh.Taxon {
	tax := &jdh.Taxon{
		Id:   strings.TrimSpace(tx.id),
		Name: strings.Join(strings.Fields(tx.name), " "),
		Rank: jdh.GetRank(strings.TrimSpace(tx.rank)),
	}
	return tax
}
Ejemplo n.º 2
0
func spInRun(c *cmdapp.Command, args []string) {
	openLocal(c)
	pId := ""
	if len(ancFlag) > 0 {
		p := taxon(c, localDB, ancFlag)
		if !p.IsValid {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("taxon "+p.Name+" a synonym, can ot be a parent"))
			os.Exit(1)
		}
		pId = p.Id
	}
	var set *jdh.Dataset
	if len(dsetFlag) > 0 {
		set = dataset(c, localDB, dsetFlag)
	} else {
		set = &jdh.Dataset{}
	}
	rank := jdh.Unranked
	if len(rankFlag) > 0 {
		rank = jdh.GetRank(rankFlag)
	}
	format := "txt"
	if len(formatFlag) > 0 {
		format = formatFlag
	}
	if len(args) > 0 {
		switch format {
		case "txt":
			for _, fname := range args {
				spInTxt(c, fname, pId, rank, set)
			}
		case "ndm":
			for _, fname := range args {
				spInNdm(c, fname, pId, rank, set)
			}
		default:
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("format "+format+" unknown"))
			os.Exit(1)
		}
	} else {
		switch format {
		case "txt":
			spInTxt(c, "", pId, rank, set)
		case "ndm":
			spInNdm(c, "", pId, rank, set)
		default:
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("format "+format+" unknown"))
			os.Exit(1)
		}
	}
	localDB.Exec(jdh.Commit, "", nil)
}
Ejemplo n.º 3
0
// TrInPickTax returns the id of a given taxon name. If there are more taxons
// fullfilling the name, then it will print a list of the potential
// names and finish the program.
func trInPickTax(name, parent string) (string, error) {
	vals := new(jdh.Values)
	vals.Add(jdh.TaxName, name)
	if len(parent) != 0 {
		vals.Add(jdh.TaxParent, parent)
	}
	rank := jdh.Unranked
	if len(rankFlag) > 0 {
		rank = jdh.GetRank(rankFlag)
		if rank != jdh.Unranked {
			vals.Add(jdh.TaxRank, rankFlag)
		}
	}
	l, err := localDB.List(jdh.Taxonomy, vals)
	if err != nil {
		return "", err
	}
	var tax *jdh.Taxon
	mult := ""
	for {
		ot := &jdh.Taxon{}
		if err := l.Scan(ot); err != nil {
			if err == io.EOF {
				break
			}
			return "", err
		}
		if tax == nil {
			tax = ot
			continue
		}
		if len(mult) == 0 {
			mult = fmt.Sprintf("ambiguos taxon name\n")
			mult += fmt.Sprintf("%s\t%s\n", tax.Id, tax.Name)
		}
		mult += fmt.Sprintf("%s\t%s\n", ot.Id, ot.Name)
	}
	if len(mult) > 0 {
		return "", errors.New(mult)
	}
	if tax == nil {
		tax = &jdh.Taxon{
			Name:    name,
			IsValid: true,
			Parent:  parent,
			Rank:    rank,
		}
		return localDB.Exec(jdh.Add, jdh.Taxonomy, tax)
	}
	return tax.Id, nil
}
Ejemplo n.º 4
0
func raMkRun(c *cmdapp.Command, args []string) {
	openLocal(c)
	var spDB jdh.DB
	if len(extDBFlag) > 0 {
		openExt(c, extDBFlag, "")
		spDB = extDB
	} else {
		spDB = localDB
	}
	var tax *jdh.Taxon
	if len(taxonFlag) > 0 {
		tax = taxon(c, localDB, taxonFlag)
		if len(tax.Id) == 0 {
			return
		}
	} else if len(args) > 0 {
		if len(args) > 2 {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("too many arguments"))
			os.Exit(1)
		}
		pName := ""
		if len(args) > 1 {
			pName = args[1]
		}
		tax = pickTaxName(c, localDB, args[0], pName)
		if len(tax.Id) == 0 {
			return
		}
	} else {
		tax = &jdh.Taxon{}
	}
	rank := jdh.Kingdom
	if len(rankFlag) > 0 {
		rank = jdh.GetRank(rankFlag)
		if rank == jdh.Unranked {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("invalid rank"))
			os.Exit(1)
		}
	}
	if (sizeFlag <= 0) || (sizeFlag >= 360) {
		fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("invalid size option"))
		os.Exit(1)
	}
	cols := uint(360 / sizeFlag)
	if int(float64(cols)*sizeFlag) < 360 {
		cols++
	}
	size := 360 / float64(cols)
	raMkFetch(c, spDB, tax, jdh.Kingdom, rank, size)
	localDB.Exec(jdh.Commit, "", nil)
}
Ejemplo n.º 5
0
func txInRun(c *cmdapp.Command, args []string) {
	openLocal(c)
	pId := ""
	if len(ancFlag) > 0 {
		p := taxon(c, localDB, ancFlag)
		if !p.IsValid {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("taxon "+p.Name+" a synonym, can ot be a parent"))
			os.Exit(1)
		}
		pId = p.Id
	}
	valid := true
	if synonymFlag {
		if len(pId) == 0 {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("synonym without defined parent"))
			os.Exit(2)
		}
		valid = false
	}
	rank := jdh.Unranked
	if len(rankFlag) > 0 {
		rank = jdh.GetRank(rankFlag)
	}
	format := "txt"
	if len(formatFlag) > 0 {
		format = formatFlag
	}
	if len(args) > 0 {
		switch format {
		case "txt":
			for _, fn := range args {
				txInTxt(c, fn, pId, rank, valid)
			}
		default:
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("format "+format+" unknown"))
			os.Exit(1)
		}
	} else {
		switch format {
		case "txt":
			txInTxt(c, "", pId, rank, valid)
		default:
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("format "+format+" unknown"))
			os.Exit(1)
		}
	}
	localDB.Exec(jdh.Commit, "", nil)
}
Ejemplo n.º 6
0
// returns a copy of species
func (sp *species) copy() *jdh.Taxon {
	if sp.Key == 0 {
		return &jdh.Taxon{}
	}
	rank := jdh.GetRank(strings.TrimSpace(sp.Rank))
	tax := &jdh.Taxon{
		Id:        strconv.FormatInt(sp.Key, 10),
		Name:      strings.Join(strings.Fields(sp.CanonicalName), " "),
		Authority: strings.Join(strings.Fields(sp.Authorship), " "),
		Rank:      rank,
		IsValid:   !sp.Synonym,
		Comment:   strings.Join(strings.Fields(sp.AccordingTo), " "),
	}
	if sp.Synonym {
		tax.Parent = strconv.FormatInt(sp.AcceptedKey, 10)
	} else if sp.ParentKey > 0 {
		tax.Parent = strconv.FormatInt(sp.ParentKey, 10)
	}
	return tax
}
Ejemplo n.º 7
0
func spPopRun(c *cmdapp.Command, args []string) {
	if len(extDBFlag) == 0 {
		fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("expectiong '--extdb' option"))
		c.Usage()
	}
	openLocal(c)
	openExt(c, extDBFlag, "")
	var tax *jdh.Taxon
	if len(taxonFlag) > 0 {
		tax = taxon(c, localDB, taxonFlag)
		if len(tax.Id) == 0 {
			return
		}
	} else if len(args) > 0 {
		if len(args) > 2 {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("too many arguments"))
			os.Exit(1)
		}
		pName := ""
		if len(args) > 1 {
			pName = args[1]
		}
		tax = pickTaxName(c, localDB, args[0], pName)
		if len(tax.Id) == 0 {
			return
		}
	} else {
		tax = &jdh.Taxon{}
	}
	rank := jdh.Kingdom
	if len(rankFlag) > 0 {
		rank = jdh.GetRank(rankFlag)
		if rank == jdh.Unranked {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("invalid rank"))
			os.Exit(1)
		}
	}
	spPopFetch(c, tax, jdh.Kingdom, rank)
	localDB.Exec(jdh.Commit, "", nil)
}
Ejemplo n.º 8
0
// searchTaxon searchs for taxon name in gbif.
func (db *DB) searchTaxon(l *listScanner, name string, kvs []jdh.KeyValue) {
	nm := strings.Join(strings.Fields(name), " ")
	if i := strings.Index(nm, "*"); i > 0 {
		l.setErr(errors.New("current gbif api does not support partial lookups"))
		return
	}
	var pId int64
	var pName string
	var rank jdh.Rank
	for _, kv := range kvs {
		if len(kv.Value) == 0 {
			continue
		}
		switch kv.Key {
		case jdh.TaxParent:
			pId, _ = strconv.ParseInt(kv.Value[0], 10, 64)
		case jdh.TaxRank:
			rank = jdh.GetRank(kv.Value[0])
		case jdh.TaxParentName:
			pName = strings.ToLower(strings.Join(strings.Fields(kv.Value[0]), " "))
		}
	}
	vals := url.Values{}
	vals.Add("name", nm)
	for off := int64(0); ; {
		if off > 0 {
			vals.Set("offset", strconv.FormatInt(off, 10))
		}
		request := wsHead + "species?" + vals.Encode()
		an := new(spAnswer)
		if err := db.listRequest(request, an); err != nil {
			l.setErr(err)
			return
		}
		for _, sp := range an.Results {
			if sp.Key != sp.NubKey {
				continue
			}
			if pId != 0 {
				if !sp.isDesc(pId) {
					continue
				}
			}
			if rank != jdh.Unranked {
				if rank != jdh.GetRank(strings.TrimSpace(sp.Rank)) {
					continue
				}
			}
			if len(pName) > 0 {
				if !sp.hasParentName(pName) {
					continue
				}
			}
			select {
			case l.c <- sp.copy():
			case <-l.end:
				return
			}
		}
		if an.EndOfRecords {
			break
		}
		off += an.Limit
	}
	select {
	case l.c <- nil:
	case <-l.end:
	}
}
Ejemplo n.º 9
0
func readTaxon(id string) (*taxon, error) {
	if (len(id) == 0) || (id == "0") {
		return nil, errors.New("taxon without identification")
	}
	request := emblHead + "Taxon:" + id + "&display=xml"
	answer, err := http.Get(request)
	if err != nil {
		return nil, err
	}
	defer answer.Body.Close()
	dec := xml.NewDecoder(answer.Body)
	tx := &taxon{
		tax: &jdh.Taxon{},
	}
	for tk, err := dec.Token(); err != io.EOF; tk, err = dec.Token() {
		if err != nil {
			return nil, err
		}
		switch t := tk.(type) {
		case xml.StartElement:
			switch t.Name.Local {
			case "taxon":
				for _, at := range t.Attr {
					switch at.Name.Local {
					case "scientificName":
						tx.tax.Name = at.Value
						tx.tax.IsValid = true
					case "taxId":
						tx.tax.Id = at.Value
					case "parentTaxId":
						tx.tax.Parent = at.Value
					case "rank":
						tx.tax.Rank = jdh.GetRank(at.Value)
					}
				}
			case "lineage":
				if err = readTaxonLineage(dec, tx); err != nil {
					return nil, err
				}
			case "children":
				skip(dec, t.Name.Local)
			case "synonym":
				nm := ""
				isSyn := false
				for _, at := range t.Attr {
					switch at.Name.Local {
					case "type":
						if at.Value == "synonym" {
							isSyn = true
						}
					case "name":
						nm = at.Value
					}
				}
				if isSyn {
					tx.syn = append(tx.syn, nm)
				}
			}
		}
	}
	return tx, nil
}
Ejemplo n.º 10
0
// SearchTaxon search for a taxon name in iNaturalist.
func (db *DB) searchTaxon(l *listScanner, name string, kvs []jdh.KeyValue) {
	nm := strings.Join(strings.Fields(name), " ")
	i := strings.Index(nm, "*")
	prefix := ""
	if i == 0 {
		l.setErr(errors.New("taxon without identification"))
		return
	}
	if i > 0 {
		prefix = nm[:i]
		nm = nm[:i]
	}
	pId := ""
	var rank jdh.Rank
	pName := ""
	for _, kv := range kvs {
		if len(kv.Value) == 0 {
			continue
		}
		switch kv.Key {
		case jdh.TaxParent:
			pId = kv.Value[0]
		case jdh.TaxRank:
			rank = jdh.GetRank(kv.Value[0])
		case jdh.TaxParentName:
			pName = strings.Join(strings.Fields(kv.Value[0]), " ")
		}
	}
	vals := url.Values{}
	vals.Add("q", name)
	vals.Add("utf8", "✓")
	for next := 1; ; next++ {
		if next > 1 {
			vals.Set("page", strconv.FormatInt(int64(next), 10))
		}
		ls, nx, err := db.txSearch(inatHead + "taxa/search?" + vals.Encode())
		if err != nil {
			l.setErr(err)
			return
		}
		for _, tx := range ls {
			tax := tx.copy()
			if len(prefix) > 0 {
				if strings.HasPrefix(tax.Name, prefix) {
					if len(pId) > 0 {
						pl, err := db.txList(tx.id)
						if err != nil {
							l.setErr(err)
							return
						}
						isP := false
						for _, pt := range pl {
							if pt.id == tx.id {
								break
							}
							if pt.id == pId {
								isP = true
								break
							}
						}
						if !isP {
							continue
						}
					}
					if len(pName) > 0 {
						pl, err := db.txList(tx.id)
						if err != nil {
							l.setErr(err)
							return
						}
						isP := false
						for _, pt := range pl {
							if pt.id == tx.id {
								break
							}
							if strings.Join(strings.Fields(pt.name), " ") == pName {
								isP = true
								break
							}
						}
						if !isP {
							continue
						}
					}
					if rank != jdh.Unranked {
						if rank != tax.Rank {
							continue
						}
					}
					select {
					case l.c <- tax:
					case <-l.end:
						return
					}
				}
				continue
			}
			if tax.Name == nm {
				if len(pId) > 0 {
					pl, err := db.txList(tx.id)
					if err != nil {
						l.setErr(err)
						return
					}
					isP := false
					for _, pt := range pl {
						if pt.id == tx.id {
							break
						}
						if pt.id == pId {
							isP = true
							break
						}
					}
					if !isP {
						continue
					}
				}
				if len(pName) > 0 {
					pl, err := db.txList(tx.id)
					if err != nil {
						l.setErr(err)
						return
					}
					isP := false
					for _, pt := range pl {
						if pt.id == tx.id {
							break
						}
						if strings.Join(strings.Fields(pt.name), " ") == pName {
							isP = true
							break
						}
					}
					if !isP {
						continue
					}
				}
				if rank != jdh.Unranked {
					if rank != tax.Rank {
						continue
					}
				}
				select {
				case l.c <- tax:
				case <-l.end:
					return
				}
			}
		}
		if !nx {
			break
		}
	}
	select {
	case l.c <- nil:
	case <-l.end:
	}
}
Ejemplo n.º 11
0
// SearchTaxon search for a taxon name in ncbi.
func (db *DB) searchTaxon(l *listScanner, name string, kvs []jdh.KeyValue) {
	nm := strings.Join(strings.Fields(name), " ")
	i := strings.Index(nm, "*")
	prefix := ""
	if i == 0 {
		l.setErr(errors.New("taxon without identification"))
		return
	}
	if i > 0 {
		prefix = nm[:i]
		nm = nm[:i]
	}
	pId := ""
	var rank jdh.Rank
	pName := ""
	for _, kv := range kvs {
		if len(kv.Value) == 0 {
			continue
		}
		switch kv.Key {
		case jdh.TaxParent:
			pId = kv.Value[0]
		case jdh.TaxRank:
			rank = jdh.GetRank(kv.Value[0])
		case jdh.TaxParentName:
			pName = strings.Join(strings.Fields(kv.Value[0]), " ")
		}
	}
	vals := url.Values{}
	vals.Add("db", "taxonomy")
	vals.Add("term", nm)
	for next := 0; ; {
		if next > 0 {
			vals.Set("RetStart", strconv.FormatInt(int64(next), 10))
		}
		request := ncbiHead + "esearch.fcgi?" + vals.Encode()
		nl, nx, err := db.search(request)
		if err != nil {
			l.setErr(err)
			return
		}
		for _, id := range nl {
			tx, err := readTaxon(id)
			if err != nil {
				l.setErr(err)
				return
			}
			if len(prefix) > 0 {
				if strings.HasPrefix(tx.tax.Name, prefix) {
					if len(pId) > 0 {
						isP := false
						for _, p := range tx.par {
							if pId == p {
								isP = true
								break
							}
						}
						if !isP {
							continue
						}
					}
					if rank != jdh.Unranked {
						if rank != tx.tax.Rank {
							continue
						}
					}
					if len(pName) > 0 {
						isP := false
						for _, p := range tx.lin {
							if pName == p {
								isP = true
								break
							}
						}
						if !isP {
							continue
						}
					}
					select {
					case l.c <- tx.tax:
					case <-l.end:
						return
					}
					continue
				}
				for i, s := range tx.syn {
					if strings.HasPrefix(s, prefix) {
						if len(pId) > 0 {
							isP := false
							for _, p := range tx.par {
								if pId == p {
									isP = true
									break
								}
							}
							if !isP {
								continue
							}
						}
						if rank != jdh.Unranked {
							if rank != tx.tax.Rank {
								continue
							}
						}
						if len(pName) > 0 {
							isP := false
							for _, p := range tx.lin {
								if pName == p {
									isP = true
									break
								}
							}
							if !isP {
								continue
							}
						}
						st := &jdh.Taxon{
							Id:      tx.tax.Id + "." + strconv.FormatInt(int64(i)+1, 10),
							Name:    s,
							IsValid: false,
							Parent:  tx.tax.Id,
							Rank:    tx.tax.Rank,
						}
						select {
						case l.c <- st:
						case <-l.end:
							return
						}
						break
					}
				}
				continue
			}
			if tx.tax.Name == nm {
				if len(pId) > 0 {
					isP := false
					for _, p := range tx.par {
						if pId == p {
							isP = true
							break
						}
					}
					if !isP {
						continue
					}
				}
				if rank != jdh.Unranked {
					if rank != tx.tax.Rank {
						continue
					}
				}
				if len(pName) > 0 {
					isP := false
					for _, p := range tx.lin {
						if pName == p {
							isP = true
							break
						}
					}
					if !isP {
						continue
					}
				}
				select {
				case l.c <- tx.tax:
				case <-l.end:
					return
				}
				continue
			}
			for i, s := range tx.syn {
				if s == nm {
					if len(pId) > 0 {
						isP := false
						for _, p := range tx.par {
							if pId == p {
								isP = true
								break
							}
						}
						if !isP {
							continue
						}
					}
					if rank != jdh.Unranked {
						if rank != tx.tax.Rank {
							continue
						}
					}
					st := &jdh.Taxon{
						Id:      tx.tax.Id + "." + strconv.FormatInt(int64(i)+1, 10),
						Name:    s,
						IsValid: false,
						Parent:  tx.tax.Id,
						Rank:    tx.tax.Rank,
					}
					select {
					case l.c <- st:
					case <-l.end:
						return
					}
					break
				}
			}
		}
		if nx == 0 {
			break
		}
		next = nx
	}
	select {
	case l.c <- nil:
	case <-l.end:
	}
}
Ejemplo n.º 12
0
func txLsRun(c *cmdapp.Command, args []string) {
	var db jdh.DB
	if len(extDBFlag) != 0 {
		openExt(c, extDBFlag, "")
		db = extDB
	} else {
		openLocal(c)
		db = localDB
	}
	var tax *jdh.Taxon
	if len(idFlag) > 0 {
		tax = taxon(c, db, idFlag)
		if len(tax.Id) == 0 {
			return
		}
	} else if len(args) > 0 {
		if len(args) > 2 {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("too many arguments"))
			os.Exit(1)
		}
		pName := ""
		if len(args) > 1 {
			pName = args[1]
		}
		tax = pickTaxName(c, db, args[0], pName)
		if len(tax.Id) == 0 {
			return
		}
	}
	if ancsFlag {
		if tax == nil {
			os.Exit(0)
		}
		vals := new(jdh.Values)
		vals.Add(jdh.TaxParents, tax.Id)
		l, err := db.List(jdh.Taxonomy, vals)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr(err))
			os.Exit(1)
		}
		txLsProc(c, l)
		return
	}
	if len(rankFlag) > 0 {
		rank := jdh.GetRank(rankFlag)
		if (rank == jdh.Unranked) && (strings.ToLower(rankFlag) != rank.String()) {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("unknown rank"))
			os.Exit(1)
		}
		txLsRank(c, db, tax, rank)
		return
	}
	if synonymFlag {
		if tax == nil {
			os.Exit(0)
		}
		l := getTaxDesc(c, db, tax.Id, false)
		txLsProc(c, l)
		return
	}
	id := ""
	if tax != nil {
		id = tax.Id
	}
	l := getTaxDesc(c, db, id, true)
	txLsProc(c, l)
}
Ejemplo n.º 13
0
func txSyncRun(c *cmdapp.Command, args []string) {
	if len(extDBFlag) == 0 {
		fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("expectiong '--extdb' option"))
		c.Usage()
	}
	openLocal(c)
	openExt(c, extDBFlag, "")
	var tax *jdh.Taxon
	if len(idFlag) > 0 {
		tax = taxon(c, localDB, idFlag)
		if len(tax.Id) == 0 {
			return
		}
	} else if len(args) > 0 {
		if len(args) > 2 {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("too many arguments"))
			os.Exit(1)
		}
		pName := ""
		if len(args) > 1 {
			pName = args[1]
		}
		tax = pickTaxName(c, localDB, args[0], pName)
		if len(tax.Id) == 0 {
			return
		}
	} else {
		tax = &jdh.Taxon{}
	}
	noFlag := true
	if matchFlag {
		txSyncMatch(c, tax)
		localDB.Exec(jdh.Commit, "", nil)
		noFlag = false
	}
	if updateFlag || validFlag {
		txSyncUpdate(c, tax)
		localDB.Exec(jdh.Commit, "", nil)
		noFlag = false
	}
	if len(rankFlag) > 0 {
		rank := jdh.GetRank(rankFlag)
		if rank == jdh.Unranked {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("invalid rank"))
			os.Exit(1)
		}
		txSyncRank(c, tax, rank)
		localDB.Exec(jdh.Commit, "", nil)
		noFlag = false
	}
	if len(popFlag) > 0 {
		rank := jdh.GetRank(popFlag)
		if rank == jdh.Unranked {
			fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("invalid rank"))
			os.Exit(1)
		}
		prev := tax.Rank
		if prev == jdh.Unranked {
			prev = jdh.Kingdom
		}
		txSyncPop(c, tax, prev, rank)
		localDB.Exec(jdh.Commit, "", nil)
		noFlag = false
	}
	if noFlag {
		fmt.Fprintf(os.Stderr, "%s\n", c.ErrStr("undefined action"))
		c.Usage()
	}
}
Ejemplo n.º 14
0
// 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
}
Ejemplo n.º 15
0
// List returns a list of taxons.
func (t *taxonomy) list(vals []jdh.KeyValue) (*list.List, error) {
	l := list.New()
	nameList := false
	noVal := true
	// creates the list
	for _, kv := range vals {
		switch kv.Key {
		case jdh.TaxChildren:
			tx := t.root
			if len(kv.Value) > 0 {
				v := strings.TrimSpace(kv.Value[0])
				if len(v) > 0 {
					var ok bool
					if tx, ok = t.ids[v]; !ok {
						return nil, fmt.Errorf("taxon %s not in database", kv.Value)
					}
				}
			}
			for _, d := range tx.childs {
				if d.data.IsValid {
					l.PushBack(d.data)
				}
			}
			noVal = false
		case jdh.TaxSynonyms:
			if len(kv.Value) == 0 {
				return l, nil
			}
			tx := t.root
			v := strings.TrimSpace(kv.Value[0])
			if len(v) == 0 {
				return l, nil
			}
			var ok bool
			if tx, ok = t.ids[v]; !ok {
				return nil, fmt.Errorf("taxon %s not in database", kv.Value)
			}
			for _, d := range tx.childs {
				if !d.data.IsValid {
					l.PushBack(d.data)
				}
			}
			noVal = false
		case jdh.TaxParents:
			if len(kv.Value) == 0 {
				return l, nil
			}
			v := strings.TrimSpace(kv.Value[0])
			if len(v) == 0 {
				return l, nil
			}
			tx, ok := t.ids[v]
			if !ok {
				return nil, fmt.Errorf("taxon %s not in database", kv.Value)
			}
			for p := tx.parent; p != t.root; p = p.parent {
				l.PushBack(p.data)
			}
			noVal = false
		case jdh.TaxName:
			if len(kv.Value) == 0 {
				return nil, errors.New("taxon without identification")
			}
			nm := strings.ToLower(strings.Join(strings.Fields(kv.Value[0]), " "))
			if len(nm) == 0 {
				return nil, errors.New("taxon without identification")
			}
			i := strings.Index(nm, "*")
			if i == 0 {
				return nil, errors.New("taxon without identification")
			}
			var ls *list.List
			if i > 0 {
				prefix := nm[:i]
				ls = t.names.Prefix(prefix)
			} else {
				ls = list.New()
				if v := t.names.Lookup(nm); v != nil {
					ls.PushBack(v)
				}
			}
			for e := ls.Front(); e != nil; e = e.Next() {
				tl := e.Value.([]*taxon)
				for _, tx := range tl {
					l.PushBack(tx.data)
				}
			}
			noVal = false
			nameList = true
		}
		if !noVal {
			break
		}
	}
	if noVal {
		return nil, errors.New("taxon without identification")
	}
	if !nameList {
		return l, nil
	}

	// filters of the list.
	for _, kv := range vals {
		if l.Len() == 0 {
			break
		}
		if len(kv.Value) == 0 {
			continue
		}
		switch kv.Key {
		case jdh.TaxParent:
			pId := strings.TrimSpace(kv.Value[0])
			if len(pId) == 0 {
				continue
			}
			for e := l.Front(); e != nil; {
				nx := e.Next()
				tax := e.Value.(*jdh.Taxon)
				if !t.isDesc(tax.Id, pId) {
					l.Remove(e)
				}
				e = nx
			}
		case jdh.TaxParentName:
			p := strings.Join(strings.Fields(kv.Value[0]), " ")
			if len(p) == 0 {
				continue
			}
			for e := l.Front(); e != nil; {
				nx := e.Next()
				tax := e.Value.(*jdh.Taxon)
				if !t.hasParentName(tax.Id, p) {
					l.Remove(e)
				}
				e = nx
			}
		case jdh.TaxRank:
			rank := jdh.GetRank(strings.TrimSpace(kv.Value[0]))
			for e := l.Front(); e != nil; {
				nx := e.Next()
				tax := e.Value.(*jdh.Taxon)
				if tax.Rank != rank {
					l.Remove(e)
				}
				e = nx
			}
		}
	}
	return l, nil
}