-
Notifications
You must be signed in to change notification settings - Fork 19
/
place_node.go
195 lines (162 loc) 路 6.17 KB
/
place_node.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package gedcom
import "strings"
// PlaceNode represents a jurisdictional name to identify the place or location
// of an event.
//
// The original specification was derived from
// http://wiki-en.genealogy.net/GEDCOM/PLAC-Tag
type PlaceNode struct {
*SimpleNode
}
// NewPlaceNode creates a new PLAC node.
//
// The original specification was derived from
// http://wiki-en.genealogy.net/GEDCOM/PLAC-Tag
func NewPlaceNode(document *Document, value, pointer string, children []Node) *PlaceNode {
return &PlaceNode{
newSimpleNode(document, TagPlace, value, pointer, children),
}
}
// JurisdictionalName determines the best name to use to identify the
// jurisdiction entities.
//
// If Format() is not empty then this is the best jurisdictional name to use
// because it should be in the form of "Name,County,State,Country". Otherwise it
// will have to fallback to using the PlaceNode value.
//
// The PlaceNode value does not have to follow any standards but it's common for
// it to have the same value as the Format would have had.
//
// If the jurisdictional name is not exactly in the form of
// "Name,County,State,Country" (including more or less components) then it
// cannot be split. In this case the Name component is the entire name and the
// County, State and Country will be empty.
func (node *PlaceNode) JurisdictionalName() string {
name := Value(node.Format())
if name == "" {
name = Value(node)
}
return name
}
// Name is the first part of the JurisdictionalName().
//
// If the JurisdictionalName is not in the exact form of
// "Name,County,State,Country" then Name will return the entire jurisdictional
// name.
func (node *PlaceNode) Name() string {
name, _, _, _ := node.JurisdictionalEntities()
return name
}
// County is the second part of the JurisdictionalName().
//
// County will only return a non-empty response if the JurisdictionalName is
// exactly in the form of "Name,County,State,Country".
func (node *PlaceNode) County() string {
_, county, _, _ := node.JurisdictionalEntities()
return county
}
// State is the third part of the JurisdictionalName().
//
// State will only return a non-empty response if the JurisdictionalName is
// exactly in the form of "Name,County,State,Country".
func (node *PlaceNode) State() string {
_, _, state, _ := node.JurisdictionalEntities()
return state
}
// Country is the forth part of the JurisdictionalName().
//
// Country will only return a non-empty response if the JurisdictionalName is
// exactly in the form of "Name,County,State,Country" or the country can be
// identified from the list of Countries.
func (node *PlaceNode) Country() string {
_, _, _, country := node.JurisdictionalEntities()
if country != "" {
return country
}
// If the country is empty it is likely because the place is not formatted
// into four jurisdictional entities. In this case we will try to find the
// country by looking at the suffix of the place name.
nameWithoutPunctuation := strings.Trim(node.JurisdictionalName(), ",. ")
lowerCaseName := strings.ToLower(nameWithoutPunctuation)
for _, c := range Countries {
if strings.HasSuffix(lowerCaseName, strings.ToLower(c)) {
return c
}
}
return ""
}
// Format shows the jurisdictional entities that are named in a sequence from
// the lowest to the highest jurisdiction.
//
// The jurisdictions are separated by commas, and any jurisdiction's name that
// is missing is still accounted for by a comma.
//
// When a PLAC.FORM structure is included in the HEADER of a GEDCOM
// transmission, it implies that all place names follow this jurisdictional
// format and each jurisdiction is accounted for by a comma, whether the name is
// known or not.
//
// When the PLAC.FORM is subordinate to an event, it temporarily overrides the
// implications made by the PLAC.FORM structure stated in the HEADER. This usage
// is not common and, therefore, not encouraged. It should only be used when a
// system has over-structured its place-names.
//
// See JurisdictionalName() for a more reliable way to determine the Format.
func (node *PlaceNode) Format() *FormatNode {
n := First(NodesWithTag(node, TagFormat))
if IsNil(n) {
return nil
}
return n.(*FormatNode)
}
// PhoneticVariations of the place name are written in the same form as was the
// place name used in the superior PlaceNode value, but phonetically written
// using the method indicated by the subordinate Type.
//
// For example if hiragana was used to provide a reading of a name written in
// kanji, then the Type value would indicate kana.
//
// See PhoneticVariationTypeHangul and PhoneticVariationTypeKana.
func (node *PlaceNode) PhoneticVariations() []*PhoneticVariationNode {
t := (*PhoneticVariationNode)(nil)
return castNodesWithTag(node, TagPhonetic, t).([]*PhoneticVariationNode)
}
// RomanizedVariations of the place name are written in the same form prescribed
// for the place name used in the superior PlaceNode context.
//
// The method used to romanize the name is indicated by the Value of the
// subordinate Type().
//
// For example if romaji was used to provide a reading of a place name written
// in kanji, then the Type subordinate to the RomanizedVariationNode would
// indicate "romaji".
func (node *PlaceNode) RomanizedVariations() []*RomanizedVariationNode {
t := (*RomanizedVariationNode)(nil)
return castNodesWithTag(node, TagRomanized, t).([]*RomanizedVariationNode)
}
func (node *PlaceNode) Map() *MapNode {
n := First(NodesWithTag(node, TagMap))
if IsNil(n) {
return nil
}
return n.(*MapNode)
}
func (node *PlaceNode) Notes() []*NoteNode {
t := (*NoteNode)(nil)
return castNodesWithTag(node, TagNote, t).([]*NoteNode)
}
// JurisdictionalEntities returns the name, county, state and country.
//
// See JurisdictionalName() for a full explanation.
func (node *PlaceNode) JurisdictionalEntities() (string, string, string, string) {
jurisdictionalName := node.JurisdictionalName()
placeParts := strings.Split(jurisdictionalName, ",")
if len(placeParts) != 4 {
placeParts = []string{jurisdictionalName, "", "", ""}
}
name := strings.TrimSpace(placeParts[0])
county := strings.TrimSpace(placeParts[1])
state := strings.TrimSpace(placeParts[2])
country := strings.TrimSpace(placeParts[3])
return name, county, state, country
}