Skip to content

Commit 77c7a85

Browse files
committed
Add TryReadStartElement, removed one ReadStartElement overload
1 parent 6c413b4 commit 77c7a85

File tree

3 files changed

+101
-14
lines changed

3 files changed

+101
-14
lines changed

MinimalXmlReader.Benchmarks/MiniXmlReaderExample2Benchmarks.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public void MiniXmlReader()
2323

2424
r.SkipProcessingInstruction();
2525
r.SkipStartElement("root");
26-
r.ReadStartElement("person", out var _);
26+
r.TryReadStartElement("person");
2727
r.SkipStartElement("random");
2828
int.Parse(r.ReadContent());
2929
r.SkipEndElement("random");

MinimalXmlReader.Tests/MiniXmlReaderTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void IntegrationTest_Random()
7070

7171
Assert.False(r.SkipProcessingInstruction());
7272
Assert.True(r.SkipStartElement("root"));
73-
Assert.True(r.ReadStartElement("person", out var personAtts));
73+
Assert.True(r.TryReadStartElement("person", out var personAtts));
7474
Assert.Equal(expected: "Tierney", actual: personAtts["firstname"]);
7575
Assert.Equal(expected: "Shirberg", actual: personAtts["lastname"]);
7676
Assert.Equal(expected: "Port-au-Prince", actual: personAtts["city"]);

MinimalXmlReader/MiniXmlReader.cs

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public MiniXmlReader(ReadOnlySpan<char> xml)
2424
/// Skips a processing instruction.
2525
/// </summary>
2626
/// <returns>True if a processing instruction was skipped; otherwise, false.</returns>
27+
/// <exception cref="Exception">Something unexpected has failed.</exception>
2728
public bool SkipProcessingInstruction()
2829
{
2930
_ = SkipSpaces();
@@ -50,6 +51,7 @@ public bool SkipProcessingInstruction()
5051
/// Skips a start element.
5152
/// </summary>
5253
/// <param name="name">The name of the element to skip.</param>
54+
/// <exception cref="Exception">Something unexpected has failed.</exception>
5355
public bool SkipStartElement(ReadOnlySpan<char> name)
5456
{
5557
_ = SkipSpaces();
@@ -108,9 +110,13 @@ public bool SkipStartElement()
108110
/// </summary>
109111
/// <param name="attributes">The attributes of the element.</param>
110112
/// <returns>The name of the element.</returns>
113+
/// <exception cref="Exception">Not a start element or something unexpected has failed.</exception>
111114
public ReadOnlySpan<char> ReadStartElement(out Dictionary<string, string> attributes)
112115
{
113-
var name = BeginReadStartElement();
116+
if (!TryBeginReadStartElement(out var name))
117+
{
118+
throw new Exception("Not a start element");
119+
}
114120

115121
attributes = ReadAttributes();
116122

@@ -121,37 +127,84 @@ public ReadOnlySpan<char> ReadStartElement(out Dictionary<string, string> attrib
121127
/// Reads a start element.
122128
/// </summary>
123129
/// <returns>The name of the element.</returns>
130+
/// <exception cref="Exception">Not a start element or something unexpected has failed.</exception>
124131
public ReadOnlySpan<char> ReadStartElement()
125132
{
126-
var name = BeginReadStartElement();
133+
if (!TryBeginReadStartElement(out var name))
134+
{
135+
throw new Exception("Not a start element");
136+
}
127137

128138
SkipAttributes();
129139

130140
return name;
131141
}
132142

133143
/// <summary>
134-
/// Reads a start element.
144+
/// Tries reading a start element.
135145
/// </summary>
136-
/// <param name="name">The name of the element to read.</param>
146+
/// <param name="name">The name of the element to match.</param>
137147
/// <param name="attributes">The attributes of the element.</param>
138148
/// <returns>True if a start element was read; otherwise, false.</returns>
139149
/// <exception cref="Exception">Something unexpected has failed.</exception>
140-
public bool ReadStartElement(ReadOnlySpan<char> name, [NotNullWhen(true)] out Dictionary<string, string>? attributes)
150+
public bool TryReadStartElement(ReadOnlySpan<char> name, [NotNullWhen(true)] out Dictionary<string, string>? attributes)
141151
{
142152
SkipSpaces();
143153

144154
var safePosition = position;
145155

146-
if (!SkipChar('<'))
156+
if (!SkipChar('<') || !ValidateElementName(name))
147157
{
148-
throw new Exception("Not a start element");
158+
position = safePosition;
159+
attributes = null;
160+
return false;
149161
}
150162

151-
if (!ValidateElementName(name))
163+
attributes = ReadAttributes();
164+
165+
return true;
166+
}
167+
168+
/// <summary>
169+
/// Tries reading a start element.
170+
/// </summary>
171+
/// <param name="name">The name of the element to match.</param>
172+
/// <returns>True if a start element was read; otherwise, false.</returns>
173+
/// <exception cref="Exception">Something unexpected has failed.</exception>
174+
public bool TryReadStartElement(ReadOnlySpan<char> name)
175+
{
176+
SkipSpaces();
177+
178+
var safePosition = position;
179+
180+
if (!SkipChar('<') || !ValidateElementName(name))
152181
{
153182
position = safePosition;
183+
return false;
184+
}
185+
186+
SkipAttributes();
187+
188+
return true;
189+
}
190+
191+
/// <summary>
192+
/// Tries reading a start element.
193+
/// </summary>
194+
/// <param name="name">The returned name of the element.</param>
195+
/// <param name="attributes">The attributes of the element.</param>
196+
/// <returns>True if a start element was read; otherwise, false.</returns>
197+
/// <exception cref="Exception">Something unexpected has failed.</exception>
198+
public bool TryReadStartElement(out ReadOnlySpan<char> name, [NotNullWhen(true)] out Dictionary<string, string>? attributes)
199+
{
200+
SkipSpaces();
201+
202+
var safePosition = position;
203+
204+
if (!TryBeginReadStartElement(out name))
205+
{
154206
attributes = null;
207+
position = safePosition;
155208
return false;
156209
}
157210

@@ -160,6 +213,29 @@ public bool ReadStartElement(ReadOnlySpan<char> name, [NotNullWhen(true)] out Di
160213
return true;
161214
}
162215

216+
/// <summary>
217+
/// Tries reading a start element.
218+
/// </summary>
219+
/// <param name="name">The returned name of the element.</param>
220+
/// <returns>True if a start element was read; otherwise, false.</returns>
221+
/// <exception cref="Exception">Something unexpected has failed.</exception>
222+
public bool TryReadStartElement(out ReadOnlySpan<char> name)
223+
{
224+
SkipSpaces();
225+
226+
var safePosition = position;
227+
228+
if (!TryBeginReadStartElement(out name))
229+
{
230+
position = safePosition;
231+
return false;
232+
}
233+
234+
SkipAttributes();
235+
236+
return true;
237+
}
238+
163239
/// <summary>
164240
/// Skips an end element.
165241
/// </summary>
@@ -239,6 +315,7 @@ public bool SkipEndElement()
239315
/// Reads content of an element.
240316
/// </summary>
241317
/// <returns>The content of the element.</returns>
318+
/// <exception cref="Exception">Something unexpected has failed.</exception>
242319
public ReadOnlySpan<char> ReadContent()
243320
{
244321
SkipSpaces();
@@ -254,6 +331,7 @@ public ReadOnlySpan<char> ReadContent()
254331
/// Reads content of an element as a string.
255332
/// </summary>
256333
/// <returns>The content of the element as a string.</returns>
334+
/// <exception cref="Exception">Something unexpected has failed.</exception>
257335
public string ReadContentAsString()
258336
{
259337
return ReadContent().ToString();
@@ -263,6 +341,7 @@ public string ReadContentAsString()
263341
/// Reads content of an element as a boolean.
264342
/// </summary>
265343
/// <returns>The content of the element as a boolean.</returns>
344+
/// <exception cref="Exception">Something unexpected has failed.</exception>
266345
public bool ReadContentAsBoolean()
267346
{
268347
var content = ReadContent();
@@ -275,6 +354,7 @@ public bool ReadContentAsBoolean()
275354
};
276355
}
277356

357+
/// <exception cref="Exception">Something unexpected has failed.</exception>
278358
private bool ValidateElementName(ReadOnlySpan<char> name)
279359
{
280360
for (var i = 0; i < name.Length; i++)
@@ -299,6 +379,7 @@ private bool ValidateElementName(ReadOnlySpan<char> name)
299379
return true;
300380
}
301381

382+
/// <exception cref="Exception">Something unexpected has failed.</exception>
302383
private Dictionary<string, string> ReadAttributes(bool expectsProcessingInstruction = false)
303384
{
304385
SkipSpaces();
@@ -337,13 +418,15 @@ private Dictionary<string, string> ReadAttributes(bool expectsProcessingInstruct
337418
return attributes;
338419
}
339420

340-
private ReadOnlySpan<char> BeginReadStartElement()
421+
/// <exception cref="Exception">Something unexpected has failed.</exception>
422+
private bool TryBeginReadStartElement(out ReadOnlySpan<char> name)
341423
{
342424
SkipSpaces();
343425

344426
if (!SkipChar('<'))
345427
{
346-
throw new Exception("Not a start element");
428+
name = default;
429+
return false;
347430
}
348431

349432
var start = position;
@@ -360,10 +443,10 @@ private ReadOnlySpan<char> BeginReadStartElement()
360443
Advance();
361444
}
362445

363-
var name = xml[start..position];
446+
name = xml[start..position];
364447

365448
Debug.WriteLine($"BeginReadStartElement({name})");
366-
return name;
449+
return true;
367450
}
368451

369452
private bool SkipChar(char c)
@@ -379,6 +462,7 @@ private bool SkipChar(char c)
379462
return true;
380463
}
381464

465+
/// <exception cref="Exception">Something unexpected has failed.</exception>
382466
private void SkipUntilChar(char c, bool includeSpaces = false)
383467
{
384468
do
@@ -409,6 +493,7 @@ private bool SkipSpaces()
409493
return skipped;
410494
}
411495

496+
/// <exception cref="Exception">Something unexpected has failed.</exception>
412497
private void SkipAttributes(bool expectsProcessingInstruction = false)
413498
{
414499
SkipSpaces();
@@ -441,6 +526,7 @@ private void SkipAttributes(bool expectsProcessingInstruction = false)
441526
}
442527
}
443528

529+
/// <exception cref="Exception">Something unexpected has failed.</exception>
444530
private ReadOnlySpan<char> ReadUntilChar(char expectedChar, bool includeSpaces = false)
445531
{
446532
var start = position;
@@ -465,6 +551,7 @@ private ReadOnlySpan<char> ReadUntilChar(char expectedChar, bool includeSpaces =
465551
return xml[start..position];
466552
}
467553

554+
/// <exception cref="Exception">Something unexpected has failed.</exception>
468555
private void Advance()
469556
{
470557
if (position == xml.Length - 1)

0 commit comments

Comments
 (0)