Project

General

Profile

« Previous | Next » 

Revision 135

map: Implemented DB input support for querying a single table

View differences:

scripts/test/map
7 7

  
8 8
shopt -s nullglob
9 9

  
10
test -n "$n" || n=2
11
let n++ # account for header row
10
test -n "$n" || export n=2
12 11

  
13 12
. ../util/env_password in_password
14 13

  
......
17 16
../../mappings/extract_plot_map
18 17
../../mappings/join_all_vegbank
19 18

  
20
function importCsv()
19
function trace()
21 20
{
22
    (set -x; head -"$n" "$in")
21
    (
22
        echo -n "$PS4"
23
        for arg in "$@"; do printf "%q " "$arg"; done
24
        echo "${_in+<$_in}" "${_out+>$_out}"
25
    ) >&2
23 26
}
24 27

  
25
function importDb()
28
function fromCsv()
26 29
{
27
    echo "$PS4. \"$in\"" >&2
28
    . "$in"
30
    (_in="$in"; trace)
31
    "$1" <"$in" || exit
29 32
}
30 33

  
31
function exportXml()
34
function fromDb()
32 35
{
36
    trace . "$in"
37
    (. "$in"; "$1") || exit
38
}
39

  
40
function toXml()
41
{
33 42
    out="$stem.$out_fmt.xml"
34 43
    (set -x; ../map "../../mappings/$src-$out_fmt.$table.csv" >"output/$out"\
35 44
    && diff "accepted_output/$out" "output/$out")
36 45
}
37 46

  
38
function exportDb()
47
function toDb()
39 48
{
40 49
    (set -x; ../map2vegbank "../../mappings/$src-VegBank.$table.csv")
41 50
}
......
48 57
    
49 58
    # Test exporting to XML
50 59
    for out_fmt in VegX VegBank; do
51
        if test "$ext" == "csv"; then importCsv|exportXml
52
        elif test "$ext" == "sh"; then (importDb; exportXml)
60
        if test "$ext" == "csv"; then fromCsv toXml
61
        elif test "$ext" == "sh"; then fromDb toXml
53 62
        fi
54 63
    done
55 64
    
56 65
    # Test exporting to VegBank db
57
    if test "$ext" == "csv"; then importCsv|exportDb
58
    elif test "$ext" == "sh"; then (importDb; exportDb)
66
    if test "$ext" == "csv"; then fromCsv toDb
67
    elif test "$ext" == "sh"; then fromDb toDb
59 68
    fi
60 69
done
scripts/lib/util.py
1 1
# Useful functions and classes
2 2

  
3
def module(value): return type(value).__module__.split('.')
4

  
5
def root_module(value): return module(value)[0]
6

  
7
def first(iter_): return iter_.next()
8

  
3 9
def skip(iter_, func):
4 10
    # Advance iter while func is True
5 11
    try:
scripts/lib/sql.py
7 7
import ex
8 8
import util
9 9

  
10
def _add_cursor_info(e, cur): ex.add_msg(e, 'query: '+cur.query)
10
def get_cur_query(cur):
11
    if hasattr(cur, 'query'): return cur.query
12
    elif hasattr(cur, '_last_executed'): return cur._last_executed
13
    else: return None
11 14

  
15
def _add_cursor_info(e, cur): ex.add_msg(e, 'query: '+get_cur_query(cur))
16

  
12 17
class NameException(Exception): pass
13 18

  
14 19
class DbException(ex.ExceptionWithCause):
......
41 46

  
42 47
def col(cur, idx): return cur.description[idx][0]
43 48

  
44
def row(cur): return iter(lambda: cur.fetchone(), None).next()
49
def rows(cur): return iter(lambda: cur.fetchone(), None)
45 50

  
51
def row(cur): return rows(cur).next()
52

  
46 53
def value(cur): return row(cur)[0]
47 54

  
48 55
def with_savepoint(db, func):
......
57 64
        return return_val
58 65

  
59 66
def select(db, table, fields, conds, limit=None):
60
    assert type(limit) == int
67
    assert limit == None or type(limit) == int
61 68
    check_name(table)
62 69
    map(check_name, fields)
63 70
    map(check_name, conds.keys())
......
84 91
    else: query += ' DEFAULT VALUES'
85 92
    return run_query(db, query, row.values())
86 93

  
87
def last_insert_id(db): return value(run_query(db, 'SELECT lastval()'))
94
def last_insert_id(db):
95
    module = util.root_module(db)
96
    if module == 'psycopg2': return value(run_query(db, 'SELECT lastval()'))
97
    elif module == 'MySQLdb': return db.insert_id()
98
    else: return None
88 99

  
89 100
def try_insert(db, table, row):
90 101
    try: return with_savepoint(db, lambda: insert(db, table, row))
scripts/lib/xml_dom.py
19 19

  
20 20
def set_id(node, id_): node.setAttribute('id', id_)
21 21

  
22
def is_empty(node): return node.firstChild == None
23

  
22 24
class NodeElemIter:
23 25
    def __init__(self, node): self.child = node.firstChild
24 26
    
......
99 101
        self.iter_.next()
100 102
        return entry
101 103

  
104
def set_child(node, name, value):
105
    '''Note: does not remove any existing child of the same name'''
106
    child = node.ownerDocument.createElement(name)
107
    set_value(node.ownerDocument, child, value)
108
    node.appendChild(child)
109

  
102 110
def replace(old_node, new_node):
103 111
    old_node.parentNode.replaceChild(new_node, old_node) # note order reversed
104 112

  
105 113
def replace_with_text(doc, node, str_): replace(node, doc.createTextNode(str_))
106 114

  
107 115
def by_tag_name(node, name, last_only=False):
108
    # last_only optimization returns last (most recently inserted) matching node
116
    '''last_only optimization returns last matching node'''
109 117
    children = []
110 118
    for child in NodeElemReverseIter(node):
111 119
        if child.tagName == name:
......
117 125
    return xml.dom.minidom.getDOMImplementation().createDocument(None, root,
118 126
        None)
119 127

  
128
def writexml(writer, node): node.writexml(writer, addindent='    ', newl='\n')
129

  
120 130
# xml.dom.minidom modifications
121 131

  
122 132
def _write_data(writer, data): writer.write(escape(data))
scripts/lib/xpath.py
142 142
    if last_only == None: last_only = create
143 143
    
144 144
    if create and not is_positive(xpath): return None
145
    doc = parent.ownerDocument
145 146
    for elem_idx, elem in enumerate(xpath):
146 147
        # Find possible matches
147 148
        children = []
......
216 217
    if value != None: set_value(xpath, value)
217 218
    get(doc, xpath, True)
218 219

  
219
def path2xml(xpath):
220
    doc = xml_dom.create_doc()
221
    get(doc, xpath, True)
222
    return doc.documentElement
220
def path2xml(xpath, first_branch=True):
221
    root = xml_dom.create_doc().documentElement
222
    get(root.ownerDocument, xpath, True)
223
    if first_branch: root = root.firstChild
224
    return root
223 225

  
224 226
def str2xml(xpath): return path2xml(parse(xpath))
scripts/lib/db_xml.py
37 37
    if pkeys == None: pkeys = {}
38 38
    def pkey(table): return sql.pkey(db, pkeys, table)
39 39
    
40
    table = name_of(node)
41
    pkey_ = pkey(table)
42
    
43
    fields = []
44
    conds = {}
40 45
    for child in xml_dom.NodeElemIter(node):
41
        assert xml_dom.is_text(child)
46
        child_name = name_of(child)
47
        if xml_dom.is_empty(child): fields.append(child_name)
48
        elif xml_dom.is_text(child): conds[child_name] = xml_dom.value(child)
49
        else: raise Exception('Joins not supported yet')
50
    id_ = xml_dom.get_id(node)
51
    if id_ != '': conds[pkey(table)] = id_ # replace any existing pkey value
52
    if fields == []: fields.append(pkey_)
42 53
    
43
    return []
54
    return sql.select(db, table, fields, conds)
44 55

  
45 56
def put(db, node, store_ids=False, row_ct_ref=None, pkeys=None, parent_id=None):
46 57
    # store_ids enables searching the tree for missing fields
scripts/lib/opts.py
4 4

  
5 5
def env_flag(name): return name in os.environ and os.environ[name] != ''
6 6

  
7
def get_env_var(name, default, env_names_ref=None):
8
    if env_names_ref != None: env_names_ref.append(name)
9
    return os.getenv(name, default)
10

  
7 11
def get_env_vars(names, prefix=None, env_names_ref=None):
8 12
    vars_ = {}
9 13
    for name in names:
scripts/map
3 3
# For outputting an XML file to a PostgreSQL database, use the general format of
4 4
# http://vegbank.org/vegdocs/xml/vegbank_example_ver1.0.2.xml
5 5

  
6
import os
7 6
import os.path
8 7
import sys
9 8
import xml.dom.minidom
......
25 24
    def usage_err():
26 25
        raise SystemExit('Usage: '+opts.env_usage(env_names, True)
27 26
            +' [commit=1] '+sys.argv[0]+' [map_path] [<input] [>output]')
27
    limit = int(opts.get_env_var('n', sys.maxint, env_names))
28
    commit = opts.env_flag('commit')
28 29
    
29 30
    # Get db config from env vars
30 31
    db_config_names = ['engine', 'host', 'user', 'password', 'database']
......
39 40
    map_path = None
40 41
    try: _prog_name, map_path = sys.argv
41 42
    except ValueError:
42
        if in_is_db or not out_is_db: usage_err()
43
    commit = opts.env_flag('commit')
43
        if in_is_db: usage_err()
44 44
    
45 45
    # Load map header
46 46
    in_is_xpaths = True
......
84 84
            
85 85
            import db_xml
86 86
            
87
            src_root = xpath.str2xml(src_root)
88
            mappings = [(in_, xpath.path2xml(out)) for in_, out in mappings]
87
            src_root = xpath.parse(src_root)
88
            src_root_xml = xpath.path2xml(src_root)
89
            mappings = [(xpath.path2xml(in_), out) for in_, out in mappings]
89 90
            
90 91
            in_db = sql.connect(in_db_config)
91 92
            in_pkeys = {}
92
            for row_id in db_xml.get(in_db, src_root, in_pkeys):
93
            for row_idx, row in enumerate(sql.rows(db_xml.get(in_db,
94
                src_root_xml, in_pkeys))):
95
                if not row_idx < limit: break
96
                row_id, = row
97
                row_id = str(row_id)
98
                
93 99
                def put_col(path, value):
94 100
                    xpath.put_obj(doc1, path, row_id, has_types, value)
95 101
                for value, out in metadata: put_col(out, value)
96 102
                for in_, out in mappings:
97
                    put_col(out, db_xml.get(in_db, in_, in_pkeys))
98
                    xpath.put_obj(doc1, out, row_id, has_types, )
103
                    root = xpath.get(in_.ownerDocument, src_root)
104
                    xml_dom.replace(root, root.cloneNode(False))
105
                    xml_dom.set_id(root, row_id)
106
                    
107
                    cur = db_xml.get(in_db, in_, in_pkeys)
108
                    try: value = sql.value(cur)
109
                    except StopIteration: continue
110
                    put_col(out, str(value))
99 111
            in_db.close()
100 112
        elif in_is_xml: raise SystemExit('XML input not supported yet')
101 113
        else: # input is CSV
......
103 115
            reader = csv.reader(sys.stdin)
104 116
            cols = reader.next()
105 117
            for row_idx, row in enumerate(reader):
118
                if not row_idx < limit: break
106 119
                row_id = str(row_idx)
120
                
107 121
                def put_col(path, value):
108 122
                    xpath.put_obj(doc1, path, row_id, has_types, value)
109 123
                for value, out in metadata: put_col(out, value)
......
127 141
        finally:
128 142
            out_db.rollback()
129 143
            out_db.close()
130
    else: doc1.writexml(sys.stdout, addindent='    ', newl='\n') # output is XML
144
    else: xml_dom.writexml(sys.stdout, doc1) # output is XML
131 145

  
132 146
try: main()
133 147
except SyntaxException, ex: raise SystemExit(str(ex))
mappings/SALVIAS_db-VegX.organisms.csv
1 1
"SALVIAS:/plotObservations","VegX:/*s/individualOrganismObservation","Comments"
2
"/OBSERVATION_ID","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept/voucher","Brad: Neither is correct; this is just an internal ID for table plotObservations. However, it has the important property of uniquely identifying an ""observation"", which is an individual tree, in the case of an individual observation, or a records of a species with an associated count of individuals or measurement of percent cover, in the case of aggregate observations. Not sure where to store this. Main point is that it is not part of the original data, but an auto_increment added later."
3
"/PLOT_ID",,"Brad: Not sure why this is repeated? This field and plotCode, as the same as above."
4
"/plot_code","/*ID->/*s/plotObservation/*UniqueIdentifierID->/*s/plot/relatedSpatialItem/relatedItem[relationshipType=parentPlot]/relatedItemID->/*s/plot/plotUniqueIdentifier","Brad: Same as plotCode, above"
2
"/PlotObsID","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept/voucher","Brad: Neither is correct; this is just an internal ID for table plotObservations. However, it has the important property of uniquely identifying an ""observation"", which is an individual tree, in the case of an individual observation, or a records of a species with an associated count of individuals or measurement of percent cover, in the case of aggregate observations. Not sure where to store this. Main point is that it is not part of the original data, but an auto_increment added later."
3
"/PlotID",,"Brad: Not sure why this is repeated? This field and plotCode, as the same as above."
4
"/PlotCode","/*ID->/*s/plotObservation/*UniqueIdentifierID->/*s/plot/plotUniqueIdentifier","Brad: Same as plotCode, above"
5 5
"/census_no","/simpleUserdefined[name=censusNo]/value","Brad: Assigned by SALVIAS. 1 for first plot, then 2, 3, etc. I can't recall if we even have repeat censuses in SALVIAS. Probably not."
6 6
"/census_date","/*ID->/*s/plotObservation/obsStartDate/_date/year",
7
"/subplot","/*ID->/*s/plotObservation/*UniqueIdentifierID->/*s/plot/plotUniqueIdentifier",
8
"/individual_code","/simpleUserdefined[name=individualCode]/value","Brad: Code, if any, used by the data provider to indicate an individual tree. Scope is unknown, although typically this value is unique only within plot, or sometimes only within subplot."
7
"/OrigRecordID",,
8
"/Line",,
9
"/Ind","/simpleUserdefined[name=individualCode]/value","Brad: Code, if any, used by the data provider to indicate an individual tree. Scope is unknown, although typically this value is unique only within plot, or sometimes only within subplot."
9 10
"/ind_id",,"Brad: OMIT"
10 11
"/tag1","/*ID->/*s/individualOrganism/identificationLabel","Brad: Another type of code, typically a number, used by the original data provider to indicate an individual tree. These are numbers on physical tags attached to the tree. Tag2 Is the same thing, only used if the first tag was lost. Obviously not a good system as it's possible a tree tag could be lost and changed more than once."
11 12
"/tag2","/*ID->/*s/individualOrganism/identificationLabel","Brad: See commend for tag1. Your mapping for tag2 looks correct. Probably both values would go here, only nested, with one superceding the other."
12 13
"/x_position","/simpleUserdefined[name=xPosition]/value","Brad: Correct for VegBank. I'm not so sure for VegX. Let's ask Nick about this. These are important, fundamental values of many tree plots, and should be accommodated within VegX."
13 14
"/y_position","/simpleUserdefined[name=yPosition]/value","Brad: See comment above for x_position"
14
"/voucher_string",,"Brad: OMIT. This is the verbatim text, which includes both collectors name and collection number. I would use coll_number, below."
15
"/dist",,
16
"/perp_dist",,
17
"/SourceVoucher",,"Brad: OMIT. This is the verbatim text, which includes both collectors name and collection number. I would use coll_number, below."
15 18
"/coll_number","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept/authorCode","Brad: Incorrect. Map instead as for voucher_string"
16 19
"/collector_code",,"Brad: OMIT"
20
"/coll_inits",,
17 21
"/coll_lastname","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=collector]/partyWithRole/*ID->/parties/party/individualName/surName","Brad: Correct for VegBank. This is the collector of a separate specimen which vouchers this tree or species. I worry that vouchers are not properly accommodated in VegX. Again, we need to check with Nick."
18 22
"/coll_firstname","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=collector]/partyWithRole/*ID->/parties/party/individualName/givenName","Brad: See comment above"
19
"/det_type","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=collector]/groupType","Brad: A SALVIAS value referring to the relationship between the voucher specimen and the observation. Affect how the identification of the specimen(latin name) is transferred to the observation. 'direct'=voucher specimen was collected from this same tree; they are one and the same individual. 'indirect'=voucher specimen was collected for a different individual, but the original data provider confirmed that this is the same species. 'default'=basically same as 'indirect'. 'uncollected'=no voucher specimen, data provider  asserted that this was the name but was unable to collect. The main different is that with 'direct', 'indirect', and 'default', the scientific name can be updated automatically based on the name attached to the specimen voucher (assuming you have a link to that data, presumably from a herbarium database. Whereas, if det_type='uncollected', the name can never change because there is no specimen."
23
"/DetType","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=collector]/groupType","Brad: A SALVIAS value referring to the relationship between the voucher specimen and the observation. Affect how the identification of the specimen(latin name) is transferred to the observation. 'direct'=voucher specimen was collected from this same tree; they are one and the same individual. 'indirect'=voucher specimen was collected for a different individual, but the original data provider confirmed that this is the same species. 'default'=basically same as 'indirect'. 'uncollected'=no voucher specimen, data provider  asserted that this was the name but was unable to collect. The main different is that with 'direct', 'indirect', and 'default', the scientific name can be updated automatically based on the name attached to the specimen voucher (assuming you have a link to that data, presumably from a herbarium database. Whereas, if det_type='uncollected', the name can never change because there is no specimen."
24
"/det_by",,
20 25
"/fam_status",,"Brad: OMIT. This will be determined later by using TNRS."
21 26
"/gen_status",,"Brad: OMIT. This will be determined later by using TNRS."
22
"/species_status",,"Brad: OMIT. Except, note that if species_status=3, this indicate that name is a morphospecies and not a standard latin name. Not exactly sure how to use this in BIEN, but could be useful during the name-scrubbing process with TNRS."
23
"/family","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=fam])/Name",
24
"/genus","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=gen])/Name",
25
"/specific_epithet","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=sp])/Name",
26
"/specific_authority","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=sp])/AccordingTo/Simple","Brad: Incorrect. This is the author of the scientificName. The should be a place for this in the taxonomic name elements of VegB and VegX. Let's discuss."
27
"/name_status",,"Brad: OMIT. Except, note that if species_status=3, this indicate that name is a morphospecies and not a standard latin name. Not exactly sure how to use this in BIEN, but could be useful during the name-scrubbing process with TNRS."
28
"/SpAuthStatus",,
29
"/Family","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=fam])/Name",
30
"/Genus","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=gen])/Name",
31
"/GenAuth",,
32
"/Species","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=sp])/Name",
33
"/auth","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=sp])/AccordingTo/Simple","Brad: Incorrect. This is the author of the scientificName. The should be a place for this in the taxonomic name elements of VegB and VegX. Let's discuss."
27 34
"/infra_rank_1","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=TaxonomicRankBelowSubspeciesEnum])/Rank",
28 35
"/infra_ep_1","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=TaxonomicRankBelowSubspeciesEnum])/Name",
29
"/cf_aff","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/note","Brad: Not sure where this goes. Indicator of identification uncertainty. 'cf.'=similar to the species listed, 'aff.'=related to the species list, but not the same. You'll need to check with Bob and with Nick where these go in VegX and VegBank."
30
"/comments",,"Brad: OMIT"
31
"/habit","/simpleUserdefined[name=habit]/value","Brad: Incorrect for VegBank, correct for VegX. This is growth form (tree, shrub, herb, etc.). It is an observation of a trait."
32
"/no_of_individuals","/simpleUserdefined[name=count]/value","Brad: Incorrect for VegX. This is a count of number of indiiduals for an *aggregate* observation. For VegBank, I'm not sure. Not exactly the same as stemCount. An individual tree could have 3 stems but would still only count as 1. We need to check with Bob on this."
36
"/infra_auth_1",,
37
"/common_name",,
38
"/morphoname",,
39
"/species_code",,
40
"/Habit","/simpleUserdefined[name=habit]/value","Brad: Incorrect for VegBank, correct for VegX. This is growth form (tree, shrub, herb, etc.). It is an observation of a trait."
41
"/height_class",,
42
"/height_m","/height","Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob"
43
"/height_m_commercial",,
44
"/ht_first_branch_m","/simpleUserdefined[name=htFirstBranchM]/value","Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob"
45
"/NoInd","/simpleUserdefined[name=count]/value","Brad: Incorrect for VegX. This is a count of number of indiiduals for an *aggregate* observation. For VegBank, I'm not sure. Not exactly the same as stemCount. An individual tree could have 3 stems but would still only count as 1. We need to check with Bob on this."
33 46
"/cover_percent","/simpleUserdefined[name=coverPercent]/value",
34 47
"/intercept_cm","/simpleUserdefined[name=interceptCm]/value","Brad: Incorrect for VegBank This is an aggregate observation. Used in line-intercept methodology only, describes the point along centerline at which an individual intercepts the center line of the plot. Used to determin relative abundance."
35
"/height_m","/height","Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob"
36
"/ht_first_branch_m","/simpleUserdefined[name=htFirstBranchM]/value","Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob"
37
"/stem_tag1","/*ID->/*s/individualOrganism/identificationLabel","Brad: Same as tag1 & tag2, but applied to individual stems. I'm still not clear how to distinguish between methods which tag only individuals trees, and those which tag individual stems."
38
"/stem_tag2","/*ID->/*s/individualOrganism/identificationLabel","Brad: see above"
39
"/stem_dbh","/diameterBaseDistance[baseDistance=1.37]/diameter",
40
"/basal_diam","/diameterBaseDistance[baseDistance=0]/diameter",
41
"/stem_height_m","/simpleUserdefined[name=stemHeightM]/value","Brad: Same as for height, but applies to individuals stems, not trees. Rare."
42
"/stem_height_first_branch_m","/simpleUserdefined[name=stemHeightFirstBranchM]/value","Brad: Should also be userDefined for VegBank. Same as for ht_first_branch_m, but applies to individuals stems, not trees. Rare."
43
"/stem_canopy_form","/simpleUserdefined[name=stemCanopyForm]/value","Brad: Should also be userDefined for VegBank. "
44
"/stem_canopy_position","/simpleUserdefined[name=stemCanopyPosition]/value","Brad: Should also be userDefined for VegBank. "
45
"/stem_liana_infestation","/simpleUserdefined[name=stemLianaInfestation]/value","Brad: Should also be userDefined for VegBank. "
46
"/notes","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept/note/text",
47
"/orig_family","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=identifier]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=fam])/Name","Brad: OMIT"
48
"/orig_species","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=identifier]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=sp])/Name","Brad: OMIT"
48
"/cfaff","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=computer]/note","Brad: Not sure where this goes. Indicator of identification uncertainty. 'cf.'=similar to the species listed, 'aff.'=related to the species list, but not the same. You'll need to check with Bob and with Nick where these go in VegX and VegBank."
49
"/other_annotations",,
50
"/morphocf",,
51
"/IsMorpho",,
52
"/OrigFamily","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=identifier]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=fam])/Name","Brad: OMIT"
53
"/OrigGenus",,
54
"/OrigSpecies","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept->/*s/taxonDetermination[*ID,partyWithRole/role=identifier]/*s/taxonRelationshipAssertion(/assertion/*ID->/*s/taxonConcept[Rank/@code=sp])/Name","Brad: OMIT"
55
"/OrigAuth",,
56
"/phenology",,
57
"/canopy_position","/simpleUserdefined[name=canopyPosition]/value","Brad: Should also be userDefined for VegBank. "
58
"/canopy_form","/simpleUserdefined[name=canopyForm]/value","Brad: Should also be userDefined for VegBank. "
59
"/liana_infestation","/simpleUserdefined[name=lianaInfestation]/value","Brad: Should also be userDefined for VegBank. "
60
"/Notes","/*ID->/*s/individualOrganism/*sID->/*s/taxonNameUsageConcept/note/text",
61
"/temp_dbh","/diameterBaseDistance[baseDistance=1.37]/diameter",
62
"/temp_liandbh",,
63
"/tmp_del",,
mappings/SALVIAS_db-VegBank.organisms.csv
1 1
SALVIAS:/plotObservations,VegBank:/taxonObservation,Comments
2
/OBSERVATION_ID,"/{taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]:[interpretationType=Author,originalInterpretation=true,currentInterpretation=false,interpretationDate=epoch,*_ID/plantConcept:[*_ID/reference],*_ID/party]/museumAccessionNumber,*_ID/observation/*_ID/plot:[confidentialityStatus=0]/authorPlotCode/_alt/3}","Brad: Neither is correct; this is just an internal ID for table plotObservations. However, it has the important property of uniquely identifying an ""observation"", which is an individual tree, in the case of an individual observation, or a records of a species with an associated count of individuals or measurement of percent cover, in the case of aggregate observations. Not sure where to store this. Main point is that it is not part of the original data, but an auto_increment added later."
3
/plot_code,/*_ID/observation/*_ID/plot/PARENT_ID/plot:[confidentialityStatus=0]/authorPlotCode/_alt/1,"Brad: Same as plotCode, above"
2
/PlotObsID,"/{taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]:[interpretationType=Author,originalInterpretation=true,currentInterpretation=false,interpretationDate=epoch,*_ID/plantConcept:[*_ID/reference],*_ID/party]/museumAccessionNumber,*_ID/observation/*_ID/plot:[confidentialityStatus=0]/authorPlotCode/_alt/3}","Brad: Neither is correct; this is just an internal ID for table plotObservations. However, it has the important property of uniquely identifying an ""observation"", which is an individual tree, in the case of an individual observation, or a records of a species with an associated count of individuals or measurement of percent cover, in the case of aggregate observations. Not sure where to store this. Main point is that it is not part of the original data, but an auto_increment added later."
3
/PlotCode,"/*_ID/observation/{*_ID/plot:[confidentialityStatus=0]/authorPlotCode/_alt/2,authorObsCode}","Brad: Same as plotCode, above"
4 4
/census_no,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=censusNo]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Assigned by SALVIAS. 1 for first plot, then 2, 3, etc. I can't recall if we even have repeat censuses in SALVIAS. Probably not."
5 5
/census_date,/*_ID/observation/obsStartDate/_date/year,
6
/subplot,"/*_ID/observation/{*_ID/plot:[confidentialityStatus=0]/authorPlotCode/_alt/2,authorObsCode}",
7
/individual_code,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=individualCode]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Code, if any, used by the data provider to indicate an individual tree. Scope is unknown, although typically this value is unique only within plot, or sometimes only within subplot."
6
/Ind,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=individualCode]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Code, if any, used by the data provider to indicate an individual tree. Scope is unknown, although typically this value is unique only within plot, or sometimes only within subplot."
8 7
/tag1,/taxonImportance/stemCount/stemLocation/stemCode,"Brad: Another type of code, typically a number, used by the original data provider to indicate an individual tree. These are numbers on physical tags attached to the tree. Tag2 Is the same thing, only used if the first tag was lost. Obviously not a good system as it's possible a tree tag could be lost and changed more than once."
9 8
/tag2,/taxonImportance/stemCount/stemLocation/stemCode,"Brad: See commend for tag1. Your mapping for tag2 looks correct. Probably both values would go here, only nested, with one superceding the other."
10 9
/x_position,/taxonImportance/stemCount/stemLocation/stemXPosition,"Brad: Correct for VegBank. I'm not so sure for VegX. Let's ask Nick about this. These are important, fundamental values of many tree plots, and should be accommodated within VegX."
......
12 11
/coll_number,/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/collectionNumber,Brad: Incorrect. Map instead as for voucher_string
13 12
/coll_lastname,/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/collector_ID/party/surName,"Brad: Correct for VegBank. This is the collector of a separate specimen which vouchers this tree or species. I worry that vouchers are not properly accommodated in VegX. Again, we need to check with Nick."
14 13
/coll_firstname,/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/collector_ID/party/givenName,Brad: See comment above
15
/det_type,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=determinationType]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: A SALVIAS value referring to the relationship between the voucher specimen and the observation. Affect how the identification of the specimen(latin name) is transferred to the observation. 'direct'=voucher specimen was collected from this same tree; they are one and the same individual. 'indirect'=voucher specimen was collected for a different individual, but the original data provider confirmed that this is the same species. 'default'=basically same as 'indirect'. 'uncollected'=no voucher specimen, data provider  asserted that this was the name but was unable to collect. The main different is that with 'direct', 'indirect', and 'default', the scientific name can be updated automatically based on the name attached to the specimen voucher (assuming you have a link to that data, presumably from a herbarium database. Whereas, if det_type='uncollected', the name can never change because there is no specimen."
16
/family,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Family]:[interpretationType=""Computer (automated)"",originalInterpretation=false,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",
17
/genus,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Genus]:[interpretationType=""Computer (automated)"",originalInterpretation=false,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",
18
/specific_epithet,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Species]:[interpretationType=""Computer (automated)"",originalInterpretation=false,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",
19
/specific_authority,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Species]/*_ID/plantConcept/*_ID/plantName/reference_ID/reference/shortName",Brad: Incorrect. This is the author of the scientificName. The should be a place for this in the taxonomic name elements of VegB and VegX. Let's discuss.
14
/DetType,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=determinationType]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: A SALVIAS value referring to the relationship between the voucher specimen and the observation. Affect how the identification of the specimen(latin name) is transferred to the observation. 'direct'=voucher specimen was collected from this same tree; they are one and the same individual. 'indirect'=voucher specimen was collected for a different individual, but the original data provider confirmed that this is the same species. 'default'=basically same as 'indirect'. 'uncollected'=no voucher specimen, data provider  asserted that this was the name but was unable to collect. The main different is that with 'direct', 'indirect', and 'default', the scientific name can be updated automatically based on the name attached to the specimen voucher (assuming you have a link to that data, presumably from a herbarium database. Whereas, if det_type='uncollected', the name can never change because there is no specimen."
15
/Family,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Family]:[interpretationType=""Computer (automated)"",originalInterpretation=false,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",
16
/Genus,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Genus]:[interpretationType=""Computer (automated)"",originalInterpretation=false,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",
17
/Species,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Species]:[interpretationType=""Computer (automated)"",originalInterpretation=false,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",
18
/auth,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Species]/*_ID/plantConcept/*_ID/plantName/reference_ID/reference/shortName",Brad: Incorrect. This is the author of the scientificName. The should be a place for this in the taxonomic name elements of VegB and VegX. Let's discuss.
20 19
/infra_rank_1,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Subspecies]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName/_name/first",
21 20
/infra_ep_1,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=computer,*_ID/plantConcept/plantStatus/plantLevel=Subspecies]:[interpretationType=""Computer (automated)"",originalInterpretation=false,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName/_name/last",
22
/cf_aff,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=cfAff]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Not sure where this goes. Indicator of identification uncertainty. 'cf.'=similar to the species listed, 'aff.'=related to the species list, but not the same. You'll need to check with Bob and with Nick where these go in VegX and VegBank."
23
/habit,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=habit]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Incorrect for VegBank, correct for VegX. This is growth form (tree, shrub, herb, etc.). It is an observation of a trait."
24
/no_of_individuals,/taxonImportance/*/stemCount,"Brad: Incorrect for VegX. This is a count of number of indiiduals for an *aggregate* observation. For VegBank, I'm not sure. Not exactly the same as stemCount. An individual tree could have 3 stems but would still only count as 1. We need to check with Bob on this."
21
/Habit,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=habit]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Incorrect for VegBank, correct for VegX. This is growth form (tree, shrub, herb, etc.). It is an observation of a trait."
22
/height_m,/taxonImportance/stemCount/stemHeight,Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob
23
/ht_first_branch_m,"/taxonImportance/stemCount/stemLocation/definedValue[*_ID/userDefined[tableName=stemLocation,userDefinedName=heightFirstBranchM]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue",Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob
24
/NoInd,/taxonImportance/*/stemCount,"Brad: Incorrect for VegX. This is a count of number of indiiduals for an *aggregate* observation. For VegBank, I'm not sure. Not exactly the same as stemCount. An individual tree could have 3 stems but would still only count as 1. We need to check with Bob on this."
25 25
/cover_percent,/taxonImportance/cover,
26 26
/intercept_cm,"/taxonImportance/definedValue[*_ID/userDefined[tableName=taxonImportance,userDefinedName=interceptCm]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Incorrect for VegBank This is an aggregate observation. Used in line-intercept methodology only, describes the point along centerline at which an individual intercepts the center line of the plot. Used to determin relative abundance."
27
/height_m,/taxonImportance/stemCount/stemHeight,Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob
28
/ht_first_branch_m,"/taxonImportance/stemCount/stemLocation/definedValue[*_ID/userDefined[tableName=stemLocation,userDefinedName=heightFirstBranchM]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue",Brad: Incorrect for VegBank. This is a measurement applied to a single tree. Check with Bob
29
/stem_tag1,/taxonImportance/stemCount/stemLocation/stemCode,"Brad: Same as tag1 & tag2, but applied to individual stems. I'm still not clear how to distinguish between methods which tag only individuals trees, and those which tag individual stems."
30
/stem_tag2,/taxonImportance/stemCount/stemLocation/stemCode,Brad: see above
31
/stem_dbh,/taxonImportance/stemCount/stemDiameter,
32
/basal_diam,"/taxonImportance/stemCount/stemLocation/definedValue[*_ID/userDefined[tableName=stemLocation,userDefinedName=stemBasalDiameter]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue",
33
/stem_height_m,/taxonImportance/stemCount/stemHeight,"Brad: Same as for height, but applies to individuals stems, not trees. Rare."
34
/stem_height_first_branch_m,"/taxonImportance/stemCount/stemLocation/definedValue[*_ID/userDefined[tableName=stemLocation,userDefinedName=stemHeightFirstBranchM]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Should also be userDefined for VegBank. Same as for ht_first_branch_m, but applies to individuals stems, not trees. Rare."
35
/stem_canopy_form,"/taxonImportance/stemCount/stemLocation/definedValue[*_ID/userDefined[tableName=stemLocation,userDefinedName=stemCanopyForm]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue",Brad: Should also be userDefined for VegBank. 
36
/stem_canopy_position,"/taxonImportance/stemCount/stemLocation/definedValue[*_ID/userDefined[tableName=stemLocation,userDefinedName=stemCanopyPosition]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue",Brad: Should also be userDefined for VegBank. 
37
/stem_liana_infestation,"/taxonImportance/stemCount/stemLocation/definedValue[*_ID/userDefined[tableName=stemLocation,userDefinedName=stemLianaInfestation]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue",Brad: Should also be userDefined for VegBank. 
38
/notes,/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/notes,
39
/orig_family,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=identifier,*_ID/plantConcept/plantStatus/plantLevel=Family]:[interpretationType=Author,originalInterpretation=true,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",Brad: OMIT
40
/orig_species,"/taxonImportance/stemCount/stemLocation/{taxonInterpretation[ROLE_ID/aux_Role/roleCode=identifier,*_ID/plantConcept/plantStatus/plantLevel=Species]:[interpretationType=Author,originalInterpretation=true,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName,taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/*_ID/plantConcept/*_ID/*/plantName/_alt/2}",Brad: OMIT
27
/cfaff,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/definedValue[*_ID/userDefined[tableName=taxonInterpretation,userDefinedName=cfAff]:[userDefinedType=varchar]]:[@fkey=tableRecord_ID]/definedValue","Brad: Not sure where this goes. Indicator of identification uncertainty. 'cf.'=similar to the species listed, 'aff.'=related to the species list, but not the same. You'll need to check with Bob and with Nick where these go in VegX and VegBank."
28
/OrigFamily,"/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=identifier,*_ID/plantConcept/plantStatus/plantLevel=Family]:[interpretationType=Author,originalInterpretation=true,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName",Brad: OMIT
29
/OrigSpecies,"/taxonImportance/stemCount/stemLocation/{taxonInterpretation[ROLE_ID/aux_Role/roleCode=identifier,*_ID/plantConcept/plantStatus/plantLevel=Species]:[interpretationType=Author,originalInterpretation=true,currentInterpretation=true,interpretationDate=epoch,*_ID/party]/*_ID/plantConcept:[plantStatus:[plantConceptStatus=accepted,startDate=epoch,*_ID/party],*_ID/reference]/*_ID/*/plantName,taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/*_ID/plantConcept/*_ID/*/plantName/_alt/2}",Brad: OMIT
30
/Notes,/taxonImportance/stemCount/stemLocation/taxonInterpretation[ROLE_ID/aux_Role/roleCode=collector]/notes,
31
/temp_dbh,/taxonImportance/stemCount/stemDiameter,

Also available in: Unified diff