Last active
August 9, 2018 17:38
-
-
Save dnfield/e176f1d604b21a67265896390c4ca6ee to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// A push based XmlReader interface, intended to be similar to .NET's XmlReader. | |
class XmlTextReader { | |
/// Creates a new reader for `input`. | |
/// | |
/// Setting `ignoreWhitespace` to false will cause text nodes | |
XmlTextReader(String input, {this.ignoreWhitespace = true}) { | |
_result = Success(input, 0, null); | |
_depth = 0; | |
_eof = false; | |
} | |
/// If true, will ignore `XmlNodeType.TEXT` and when it is composed of whitespace. | |
bool ignoreWhitespace; | |
/// Parsing context. | |
Result _result; | |
/// The [XmlNodeType] of the current position of the reader. | |
XmlNodeType get nodeType => _nodeType; | |
XmlNodeType _nodeType; | |
/// The [XmlName] of the current node of the reader. | |
XmlName get name => _name; | |
XmlName _name; | |
/// The value of the current node of the reader. | |
/// | |
/// The value will have | |
String get value => _value; | |
String _value; | |
/// Will return true if `nodeType == XmlNodeType.ELEMENT` and the element is self closing, | |
/// e.g. `<element />`. | |
bool get isEmptyElement => _isEmptyElement; | |
bool _isEmptyElement; | |
/// The zero based depth of the reader. | |
int get depth => _depth; | |
int _depth; | |
/// True if the reader is positioned at the end of the buffer. | |
bool get eof => _eof; | |
bool _eof; | |
/// The `List<XmlAttribute>` of the current element (if `nodeType == XmlNodeType.ELEMENT`). | |
UnmodifiableListView<XmlAttribute> get attributes => | |
UnmodifiableListView<XmlAttribute>(_attributes); | |
List<XmlAttribute> _attributes; | |
/// Advances the reader to the next readable position. Returns true if more data remains, false if not. | |
bool read() { | |
if (_result.position > _result.buffer.length) { | |
_eof = true; | |
return false; | |
} | |
_result = _parseEvent(_result); | |
return (_result.isSuccess); | |
} | |
Result _parseEvent(Result context) { | |
_attributes = <XmlAttribute>[]; | |
_isEmptyElement = null; | |
_value = null; | |
_nodeType = null; | |
Result result = _characterData.parseOn(context); | |
if (result.isSuccess) { | |
_nodeType = XmlNodeType.TEXT; | |
_value = result.value.trim(); | |
if (_value == '') { | |
return _parseEvent(result); | |
} | |
return result; | |
} | |
result = _elementStart.parseOn(context); | |
if (result.isSuccess) { | |
_nodeType = XmlNodeType.ELEMENT; | |
_name = result.value[1]; | |
_depth++; | |
_attributes = List<XmlAttribute>.from(result.value[2]); | |
if (result.value[4] == XmlToken.closeEndElement) { | |
_depth--; | |
_isEmptyElement = true; | |
} else { | |
_isEmptyElement = false; | |
} | |
return result; | |
} | |
result = _elementEnd.parseOn(context); | |
if (result.isSuccess) { | |
_nodeType = XmlNodeType.ELEMENT; | |
_name = result.value[1]; | |
_depth--; | |
return result; | |
} | |
result = _comment.parseOn(context); | |
if (result.isSuccess) { | |
_nodeType = XmlNodeType.COMMENT; | |
_value = result.value[1]; | |
return result; | |
} | |
// Parse CDATA as character data: | |
result = _cdata.parseOn(context); | |
if (result.isSuccess) { | |
_nodeType = XmlNodeType.CDATA; | |
_value = result.value[1]; | |
return result; | |
} | |
// Parse processing instruction: | |
result = _processing.parseOn(context); | |
if (result.isSuccess) { | |
_nodeType = XmlNodeType.PROCESSING; | |
_value = result.value[2]; | |
return result; | |
} | |
// Parse docytpes: | |
result = _doctype.parseOn(context); | |
if (result.isSuccess) { | |
_nodeType = XmlNodeType.DOCUMENT_TYPE; | |
_value = result.value[2]; | |
return result; | |
} | |
if (context.position == context.buffer.length) { | |
_eof = true; | |
return context.failure('EOF'); | |
} | |
// Skip to the next character when there is a problem: | |
return context.success(null, context.position + 1); | |
} | |
@override | |
String toString() => eof | |
? 'XmlTextReader{EOF}' | |
: 'XmlTextReader{$depth $nodeType $name $value $attributes}'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment