Skip to content

Commit 625df26

Browse files
authored
Update README.md
1 parent e81daa5 commit 625df26

File tree

1 file changed

+177
-2
lines changed

1 file changed

+177
-2
lines changed

README.md

Lines changed: 177 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,185 @@ Install the latest version of Parsley.Net nuget package with command below.
3232
```
3333
NuGet\Install-Package Parsley.Net
3434
```
35+
### ii. Implementation: Using Parsley.Net
36+
#### Step 1. Initialise and use Parser class.
37+
`Parser` is an implementation of `IParser` interface that provides methods for
38+
- parsing content of a file by specifying the file path
39+
- parsing an array of delimiter separated strings
3540

36-
### ii. Developer Guide
41+
Please see below.
42+
```
43+
public interface IParser
44+
{
45+
public T[] Parse<T>(string filepath) where T : IFileLine, new();
46+
public T[] Parse<T>(string[] lines) where T : IFileLine, new();
47+
}
48+
```
49+
To initialise `Parser` class you could do it manually or use dependency injection as shown below. The parser class has parameterised constructor that takes the delimiter character to initialise the instance. Default character is ',' (comma) to initialise the parser for a CSV file parsing.
50+
51+
Example of Manual Instantiation is
52+
```
53+
var parser = new Parser('|');
54+
```
55+
Example of IoC is
56+
```
57+
var services = new ServiceCollection();
58+
59+
services.AddTransient(typeof(IParser), c => new Parser(','));
60+
// or use extension method
61+
services.UseParsley('|');
62+
63+
serviceProvider = services.BuildServiceProvider();
64+
var parser = serviceProvider.GetService<IParser>();
65+
```
66+
#### Step 2. Define the `IFileLine` implementation to parse a file record into a strongly typed line class.
67+
Consider the file below. To parse a row into a C# class, you need to implement `IFileLine` interface. By doing this you create a strongly typed line representation for each row in the file.
68+
```
69+
|Mr|Jack Marias|Male|London|
70+
|Dr|Bony Stringer|Male|New Jersey|
71+
|Mrs|Mary Ward|Female||
72+
|Mr|Robert Webb|||
73+
```
74+
Let us create an employee class which will hold data for each row shown in the file above. The properties in the line class should match to the column index and data type of the fields of the row.
75+
76+
We use the column attribute to specify the column index and can optionally specify a default value for the associated column should it be be empty. As a rule of thumb, the number of properties with column attributes should match the number of columns in the row else the parser will throw an exception.
3777

38-
Please read [Developer Guide](https://github.com/CodeShayk/Parsley.Net/blob/master/Parsley.md) for details on how to implement Parsley.Net in your project.
78+
IFileLine interface provides
79+
- `Index` property that holds the index of the parsed line relative to the whole file,
80+
- `Errors` property which is an array representing any column parsing failures.
81+
82+
Please see below.
83+
```
84+
public interface IFileLine
85+
{
86+
public int Index { get; set; }
87+
public IList<string> Errors { get; set; }
88+
}
89+
```
90+
91+
Example. `Employee` class
92+
```
93+
public class Employee : IFileLine
94+
{
95+
// Custom column properties
96+
97+
[Column(0)]
98+
public string Title { get; set; }
99+
[Column(1)]
100+
public string Name { get; set; }
101+
[Column(2)]
102+
public EnumGender Sex { get; set; }
103+
[Column(3, "London")]
104+
public string Location { get; set; }
105+
106+
// IFileLine Members
107+
public int Index { get; set; }
108+
public IList<string> Errors { get; set; }
109+
}
110+
```
111+
Once you have created the line class it is as simple as calling one of the parser.Parse() methods below
112+
113+
i. By providing the path of the file to parse method.
114+
```
115+
var records = new Parser('|').Parse<Employee>("c://employees.txt");
116+
```
117+
ii. By providing the list of delimiter separated string values to parse method.
118+
```
119+
var lines = new[]
120+
{
121+
"|Mr|Jack Marias|Male|London|",
122+
"|Dr|Bony Stringer|Male|New Jersey|",
123+
};
124+
125+
var records = new Parser('|').Parse<Employee>(lines);
126+
```
127+
#### Step 3. Advanced Parsing of data using nested types in the FileLine class.
128+
You could implement advance parsing of data by implementing `TypeConverter` class. Suppose we have to change the Name string property in Employee class above to a `NameType` property shown below.
129+
```
130+
public class Employee : IFileLine
131+
{
132+
[Column(0)]
133+
public string Title { get; set; }
134+
[Column(1)]
135+
public NameType Name { get; set; }
136+
[Column(2)]
137+
public EnumGender Sex { get; set; }
138+
[Column(3, "London")]
139+
public string Location { get; set; }
140+
141+
// IFileLine Members
142+
public int Index { get; set; }
143+
public IList<string> Errors { get; set; }
144+
}
145+
146+
public class NameType
147+
{
148+
public string FirstName { get; set; }
149+
public string Surname { get; set; }
150+
}
151+
```
152+
153+
In order to parse the string name value from delimiter separated record in the file correctly to NameType instance, you need to implement custom `TypeConverter` converter.
154+
155+
Example - `NameConverter`
156+
```
157+
public class NameConverter : TypeConverter
158+
{
159+
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
160+
{
161+
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
162+
}
163+
164+
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
165+
{
166+
string stringValue;
167+
object result;
168+
169+
result = null;
170+
stringValue = value as string;
171+
172+
if (!string.IsNullOrEmpty(stringValue))
173+
{
174+
result = NameType.Parse(stringValue);
175+
}
176+
177+
return result ?? base.ConvertFrom(context, culture, value);
178+
}
179+
}
180+
```
181+
After implementing the custom TypeConverter, you need to decorate the NameType class with ` [TypeConverter(typeof(NameConverter))]` attribute.
182+
183+
```
184+
[TypeConverter(typeof(NameConverter))]
185+
public class NameType
186+
{
187+
public string FirstName { get; set; }
188+
public string Surname { get; set; }
189+
190+
public static NameType Parse(string input)
191+
{
192+
var values = input.Split(' ');
193+
194+
if (values.Length == 1)
195+
return new NameType { FirstName = values[0] };
196+
197+
if (values.Length == 2)
198+
return new NameType { FirstName = values[0], Surname = values[1] };
199+
200+
if (values.Length > 2)
201+
{
202+
var forenames = string.Empty;
203+
for (var i = 0; i < values.Length - 1; i++)
204+
forenames += string.Concat(values[i]) + " ";
205+
206+
return new NameType { FirstName = forenames.Trim(), Surname = values[values.Length - 1] };
207+
}
208+
209+
return new NameType { FirstName = input };
210+
}
211+
}
212+
```
213+
Now parsing the file should hydrate data correctly to the Employee FileLine class and its nested name type.
39214

40215
## Support
41216

0 commit comments

Comments
 (0)