-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhit.go
More file actions
128 lines (105 loc) · 3.28 KB
/
hit.go
File metadata and controls
128 lines (105 loc) · 3.28 KB
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
package result
import (
"encoding/json"
"encoding/xml"
"sort"
"strings"
"github.com/pkg/errors"
)
// Hit represents a single Hit
type Hit struct {
ID string `json:"id,omitempty"` // the (possibly internal) id of this hit
URL string `json:"url,omitempty"` // the url of the document returned
XPath string `json:"xpath"` // the xpath of the query term to the formulae referred to by this id
Element *HarvestElement `json:"source,omitempty"` // the raw harvest element (if any)
Score float64 `json:"score,omitempty"` // score of this hit
Snippets []string `json:"snippets,omitempty"` // extracts of this hit (if any)
Math []*MathFormula `json:"math_ids"` // math found within this hit
}
// UnmarshalJSON unmarshals a json hit
func (hit *Hit) UnmarshalJSON(bytes []byte) error {
type marshalHit Hit // to prevent infinite recursion
h := struct {
XHTML string `json:"xhtml,omitempty"` // xml version of a harvest element (if any)
*marshalHit
}{
marshalHit: (*marshalHit)(hit),
}
// unmarshal the helper
if err := json.Unmarshal(bytes, &h); err != nil {
err = errors.Wrap(err, "json.Unmarshal failed")
return err
}
// if no harvest element was returned
// we do not need to unmarshal it
if strings.TrimSpace(h.XHTML) == "" {
return nil
}
// else unmarshal the xml as an element
err := xml.Unmarshal([]byte("<data>"+h.XHTML+"</data>"), &h.Element)
if err != nil {
err = errors.Wrap(err, "xml.Unmarshal failed")
return err
}
err = hit.PopulateMathSource()
err = errors.Wrap(err, "hit.PopulateMathSource failed")
return err
}
// PopulateMath populates the 'Math' property of this hit using the 'math' property of the result
func (hit *Hit) PopulateMath() error {
// if we already have some math, return an error
if len(hit.Math) > 0 {
return errors.New("[Hit.PopulateMath] Math already populated")
}
for _, mwsid := range hit.Element.MWSNumbers {
// load the path data
path, ok := hit.Element.MWSPaths[mwsid]
if !ok {
return errors.Errorf("[Hit.PopulateMath] Result %q missing path info for %d", hit.ID, mwsid)
}
// sort the keys in alphabetical order
keys := make([]string, len(path))
count := 0
for key := range path {
keys[count] = key
count++
}
sort.Strings(keys)
// and iterate over it
for _, key := range keys {
res := &MathFormula{XPath: path[key].XPath}
res.SetURL(key)
hit.Math = append(hit.Math, res)
}
}
// ensure that math is not a nil-slice
if hit.Math == nil {
hit.Math = []*MathFormula{}
}
err := hit.PopulateMathSource()
err = errors.Wrap(err, "hit.PopulateMathSource failed")
return err
}
// PopulateMathSource populates the maths sources for all mathFormulae within this hit
func (hit *Hit) PopulateMathSource() error {
for _, math := range hit.Math {
key := math.LocalID
source, ok := hit.Element.MathSource[key]
if !ok {
return errors.Errorf("[Hit.PopulateMathSource] Missing source info for %s", key)
}
math.Source = source
}
return nil
}
// PopulateSubsitutions populates the subsitutions field of all found math formulae
// in this hit
func (hit *Hit) PopulateSubsitutions(res *Result) error {
for _, math := range hit.Math {
if err := math.PopulateSubsitutions(hit, res); err != nil {
err = errors.Wrap(err, "math.PopulateSubsitutions failed")
return err
}
}
return nil
}