-
Notifications
You must be signed in to change notification settings - Fork 215
/
Program.cs
112 lines (93 loc) · 3.29 KB
/
Program.cs
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sprache;
using System.IO;
namespace XmlExample
{
public class Document
{
public Node Root;
public override string ToString()
{
return Root.ToString();
}
}
public class Item { }
public class Content : Item
{
public string Text;
public override string ToString()
{
return Text;
}
}
public class Node : Item
{
public string Name;
public IEnumerable<Item> Children;
public override string ToString()
{
if (Children != null)
return string.Format("<{0}>", Name) +
Children.Aggregate("", (s, c) => s + c) +
string.Format("</{0}>", Name);
return string.Format("<{0}/>", Name);
}
}
public static class XmlParser
{
static CommentParser Comment = new CommentParser("<!--", "-->", "\r\n");
static readonly Parser<string> Identifier =
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.XOr(Parse.Char('-')).XOr(Parse.Char('_')).Many()
select new string(first.Concat(rest).ToArray());
static Parser<T> Tag<T>(Parser<T> content)
{
return from lt in Parse.Char('<')
from t in content
from gt in Parse.Char('>').Token()
select t;
}
static readonly Parser<string> BeginTag = Tag(Identifier);
static Parser<string> EndTag(string name)
{
return Tag(from slash in Parse.Char('/')
from id in Identifier
where id == name
select id).Named("closing tag for " + name);
}
static readonly Parser<Content> Content =
from chars in Parse.CharExcept('<').Many()
select new Content { Text = new string(chars.ToArray()) };
static readonly Parser<Node> FullNode =
from tag in BeginTag
from nodes in Parse.Ref(() => Item).Many()
from end in EndTag(tag)
select new Node { Name = tag, Children = nodes };
static readonly Parser<Node> ShortNode = Tag(from id in Identifier
from slash in Parse.Char('/')
select new Node { Name = id });
static readonly Parser<Node> Node = ShortNode.Or(FullNode);
static readonly Parser<Item> Item =
from leading in Comment.MultiLineComment.Many()
from item in Node.Select(n => (Item)n).XOr(Content)
from trailing in Comment.MultiLineComment.Many()
select item;
public static readonly Parser<Document> Document =
from leading in Parse.WhiteSpace.Many()
from doc in Node.Select(n => new Document { Root = n }).End()
select doc;
}
class Program
{
static void Main()
{
string input = File.ReadAllText("TestFile.xml", Encoding.UTF8);
var parsed = XmlParser.Document.Parse(input);
Console.WriteLine(parsed);
Console.ReadKey(true);
}
}
}