@@ -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>
@@ -197,8 +273,11 @@ public bool SkipEndElement()
197273 {
198274 _ = SkipSpaces ( ) ;
199275
276+ var safePosition = position ;
277+
200278 if ( ! SkipChar ( '<' ) || ! SkipChar ( '/' ) )
201279 {
280+ position = safePosition ;
202281 return false ;
203282 }
204283
@@ -236,6 +315,7 @@ public bool SkipEndElement()
236315 /// Reads content of an element.
237316 /// </summary>
238317 /// <returns>The content of the element.</returns>
318+ /// <exception cref="Exception">Something unexpected has failed.</exception>
239319 public ReadOnlySpan < char > ReadContent ( )
240320 {
241321 SkipSpaces ( ) ;
@@ -251,6 +331,7 @@ public ReadOnlySpan<char> ReadContent()
251331 /// Reads content of an element as a string.
252332 /// </summary>
253333 /// <returns>The content of the element as a string.</returns>
334+ /// <exception cref="Exception">Something unexpected has failed.</exception>
254335 public string ReadContentAsString ( )
255336 {
256337 return ReadContent ( ) . ToString ( ) ;
@@ -260,6 +341,7 @@ public string ReadContentAsString()
260341 /// Reads content of an element as a boolean.
261342 /// </summary>
262343 /// <returns>The content of the element as a boolean.</returns>
344+ /// <exception cref="Exception">Something unexpected has failed.</exception>
263345 public bool ReadContentAsBoolean ( )
264346 {
265347 var content = ReadContent ( ) ;
@@ -272,6 +354,7 @@ public bool ReadContentAsBoolean()
272354 } ;
273355 }
274356
357+ /// <exception cref="Exception">Something unexpected has failed.</exception>
275358 private bool ValidateElementName ( ReadOnlySpan < char > name )
276359 {
277360 for ( var i = 0 ; i < name . Length ; i ++ )
@@ -296,6 +379,7 @@ private bool ValidateElementName(ReadOnlySpan<char> name)
296379 return true ;
297380 }
298381
382+ /// <exception cref="Exception">Something unexpected has failed.</exception>
299383 private Dictionary < string , string > ReadAttributes ( bool expectsProcessingInstruction = false )
300384 {
301385 SkipSpaces ( ) ;
@@ -334,13 +418,15 @@ private Dictionary<string, string> ReadAttributes(bool expectsProcessingInstruct
334418 return attributes ;
335419 }
336420
337- private ReadOnlySpan < char > BeginReadStartElement ( )
421+ /// <exception cref="Exception">Something unexpected has failed.</exception>
422+ private bool TryBeginReadStartElement ( out ReadOnlySpan < char > name )
338423 {
339424 SkipSpaces ( ) ;
340425
341426 if ( ! SkipChar ( '<' ) )
342427 {
343- throw new Exception ( "Not a start element" ) ;
428+ name = default ;
429+ return false ;
344430 }
345431
346432 var start = position ;
@@ -357,10 +443,10 @@ private ReadOnlySpan<char> BeginReadStartElement()
357443 Advance ( ) ;
358444 }
359445
360- var name = xml [ start ..position ] ;
446+ name = xml [ start ..position ] ;
361447
362448 Debug . WriteLine ( $ "BeginReadStartElement({ name } )") ;
363- return name ;
449+ return true ;
364450 }
365451
366452 private bool SkipChar ( char c )
@@ -376,6 +462,7 @@ private bool SkipChar(char c)
376462 return true ;
377463 }
378464
465+ /// <exception cref="Exception">Something unexpected has failed.</exception>
379466 private void SkipUntilChar ( char c , bool includeSpaces = false )
380467 {
381468 do
@@ -406,6 +493,7 @@ private bool SkipSpaces()
406493 return skipped ;
407494 }
408495
496+ /// <exception cref="Exception">Something unexpected has failed.</exception>
409497 private void SkipAttributes ( bool expectsProcessingInstruction = false )
410498 {
411499 SkipSpaces ( ) ;
@@ -438,6 +526,7 @@ private void SkipAttributes(bool expectsProcessingInstruction = false)
438526 }
439527 }
440528
529+ /// <exception cref="Exception">Something unexpected has failed.</exception>
441530 private ReadOnlySpan < char > ReadUntilChar ( char expectedChar , bool includeSpaces = false )
442531 {
443532 var start = position ;
@@ -462,6 +551,7 @@ private ReadOnlySpan<char> ReadUntilChar(char expectedChar, bool includeSpaces =
462551 return xml [ start ..position ] ;
463552 }
464553
554+ /// <exception cref="Exception">Something unexpected has failed.</exception>
465555 private void Advance ( )
466556 {
467557 if ( position == xml . Length - 1 )
0 commit comments