-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxml.fs
94 lines (73 loc) · 2.83 KB
/
xml.fs
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
namespace Solar
module Tuple =
let map (f : 'a -> 'b) (g : 'c -> 'd) : 'a * 'c -> 'b * 'd = function
| (a, b) -> (f a, g b)
let map3 (f : 'a -> 'b) (g : 'c -> 'd) (h : 'e -> 'f) :
'a * 'c * 'e -> 'b * 'd * 'f = function
| (a, b, c) -> (f a, g b, h c)
let mapId (f : 'a -> 'b) : 'a * 'a -> 'b * 'b = map f f
let map3Id (f : 'a -> 'b) : 'a * 'a * 'a -> 'b * 'b * 'b = map3 f f f
module Xml =
open System
open System.IO
open System.Xml
open System.Drawing
open System.Globalization
let private parseNumber (s : string) =
Double.Parse (s, CultureInfo.InvariantCulture)
let private safeSelect (s : string) (n : XmlNode) =
let raw = n.SelectSingleNode s
if isNull raw then
raise <| ArgumentException (sprintf "Tag ‘%s’ is missing." s)
raw
let private safeSelectAttribute (s : string) (n : XmlNode) =
let raw = n.Attributes.[s]
if isNull raw then
raise <| ArgumentException (sprintf "Attribute ‘%s’ is missing." s)
raw.Value
let private parseVector (v : XmlNode) : Vector =
let (x, y, z) =
Tuple.map3Id (fun s -> parseNumber <| safeSelectAttribute s v)
("x", "y", "z")
{ x = x; y = y; z = z }
let private parsePlanet (v : XmlNode) : Body =
let getVector s =
safeSelect s v
|> parseVector
let id = safeSelectAttribute "id" v
let speed = getVector "Speed"
let acc = getVector "Acc"
let pos = getVector "Pos"
let sgp = parseNumber (safeSelect "SGP" v).InnerText
let render = safeSelect "render" v
let visibleRadius =
safeSelectAttribute "radius" render
|> parseNumber
let visibleColor =
safeSelectAttribute "color" render
|> ColorTranslator.FromHtml
{ speed = speed;
acc = acc;
pos = pos;
// This is standard gravitational parameter
// https://en.wikipedia.org/wiki/Standard_gravitational_parameter
μ = sgp;
id = id;
visibleRadius = visibleRadius;
visibleColor = visibleColor }
let private parsePlanets (v : XmlDocument) : Body list =
let planets = v.SelectNodes "//Objects/Planet"
let stars = v.SelectNodes "//Objects/Star"
if isNull planets then
raise <| ArgumentException ("Tag ‘Planets’ is missing.")
Seq.cast<XmlNode> planets
|> Seq.append (Seq.cast<XmlNode> stars)
|> Seq.map parsePlanet
|> List.ofSeq
let public parseFile (fileName : string) : Body list =
let text =
use sr = new StreamReader (fileName) in
sr.ReadToEnd ()
let doc = XmlDocument ()
doc.LoadXml text
parsePlanets doc