Customized XML Reader Creation
Custom XML Readers allow an application to extend either the XmlReader, or XmlTextReader, or define its own custom readers.
Sample of Extending the XmlTextReader
The following is an example showing how to extend the XmlTextReader to create a reader that converts attributes to elements. The overridden Read provides the logic to track the current node type, and if an attribute, exposes this as an element node type using the XmlNodeType.Name and XmlNodeType.Value properties.
Option Explicit Option Strict Imports System Imports System.IO Imports System.Text Imports System.Xml Imports System.Xml.XPath Public Class AttrToElementReader Inherits XmlTextReader Private _ReadAttributes As Boolean = False Private _ReadAttributeValue As Boolean = False Private _AttributeName As String = String.Empty Private _NodeType As XmlNodeType = XmlNodeType.None Public Sub New(fileName As String) MyBase.New(fileName) MyBase.WhitespaceHandling = WhitespaceHandling.None ' Intentionally Empty End Sub Public Overrides Function Read() As Boolean If Not _ReadAttributes Then Dim baseRead As Boolean = MyBase.Read() _ReadAttributes = baseRead And XmlNodeType.Element = MyBase.NodeType And 0 < MyBase.AttributeCount Return baseRead End If 'Read attribues; If _ReadAttributeValue Then _ReadAttributeValue = MyBase.ReadAttributeValue() If Not _ReadAttributeValue Then ' End of attribute. ' End element. _NodeType = XmlNodeType.EndElement Else _NodeType = XmlNodeType.None End If Return True End If _ReadAttributes = MyBase.MoveToNextAttribute() If _ReadAttributes Then _ReadAttributeValue = True _NodeType = XmlNodeType.Element _AttributeName = MyBase.Name Return True Else _ReadAttributeValue = False _NodeType = XmlNodeType.None _AttributeName = String.Empty Return Read() End If End Function Public Overrides ReadOnly Property NodeType() As XmlNodeType Get If XmlNodeType.None = _NodeType Then Return MyBase.NodeType End If Return _NodeType End Get End Property Public Overrides ReadOnly Property Value() As String Get If XmlNodeType.None = _NodeType Then Return MyBase.Value End If Return String.Empty End Get End Property Public Overrides ReadOnly Property Name() As String Get If XmlNodeType.None = _NodeType Then Return MyBase.Name End If Return _AttributeName End Get End Property End Class 'AttrToElementReader [C#]using System; using System.IO; using System.Text; using System.Xml; using System.Xml.XPath; public class AttrToElementReader: XmlTextReader { private bool _ReadAttributes = false; private bool _ReadAttributeValue = false; private string _AttributeName = String.Empty; private XmlNodeType _NodeType = XmlNodeType.None; public AttrToElementReader(String fileName) : base(fileName) { base.WhitespaceHandling = WhitespaceHandling.None; // Intentionally Empty. } public override bool Read() { if (!_ReadAttributes) { bool baseRead = base.Read(); _ReadAttributes = (baseRead && XmlNodeType.Element == base.NodeType && 0 < base.AttributeCount); return baseRead; } // Reading attribues; if (_ReadAttributeValue) { _ReadAttributeValue = base.ReadAttributeValue(); if (!_ReadAttributeValue) { // End of attribute. // End element. _NodeType = XmlNodeType.EndElement; } else { _NodeType = XmlNodeType.None; } return true; } _ReadAttributes = base.MoveToNextAttribute(); if (_ReadAttributes) { _ReadAttributeValue = true; _NodeType = XmlNodeType.Element; _AttributeName = base.Name; return true; } else { _ReadAttributeValue = false; _NodeType = XmlNodeType.None; _AttributeName = String.Empty; return Read(); } } public override XmlNodeType NodeType { get { if (XmlNodeType.None == _NodeType) { return base.NodeType; } return _NodeType; } } public override String Value { get { if (XmlNodeType.None == _NodeType) { return base.Value; } return String.Empty; } } public override String Name { get { if (XmlNodeType.None == _NodeType) { return base.Name; } return _AttributeName; } } }//AttrToElementReader
Chaining XmlReaders
The following example shows an implementation class, called XmlReaderReader, which is used as a class to chain XmlReaders together to provide a flow of readers, by delegating the calls. This is useful in creating readers that filter specific inputs and is a performant solution to specific parsing on XML.
A class derived from this XmlReaderReader can take any XmlReader as input. In the following example, the XmlCustomReader overloads the Read method and skips past price element nodes, thereby removing them from the stream.
' This sample demonstrate the ability to chain XmlReaders together by ' implementing an XmlReaderReader class which aggregates any given ' XmlReader and then delegates the calls to it Namespace Test Public Class MyApp Public Shared Sub Main() Dim reader As New XmlTextReader("books.xml") Dim customreader As New XmlCustomReader(reader) customreader.ReadandWrite() End Sub Class XmlCustomReader Inherits XmlReaderReader Public Sub New(reader As XmlTextReader) MyBase.New(reader) End Sub Public Overrides Function Read() As Boolean Dim result As Boolean result = MyBase.Read() Select Case MyBase.NodeType Case XmlNodeType.Element If MyBase.Name.Equals("price") Then MyBase.Skip() End If Case Else End Select Return result End Function Public Sub ReadandWrite() ' Read each node in the tree. While Read() Select Case NodeType Case XmlNodeType.Element Console.Write(("<" + Name)) While MoveToNextAttribute() Console.Write((" " + Name + "='" + Value + "'")) End While Console.Write(">") Case XmlNodeType.Text Console.Write(Value) Case XmlNodeType.CDATA Console.Write(Value) Case XmlNodeType.ProcessingInstruction Console.Write(("<?" + Name + " " + Value + "?>")) Case XmlNodeType.Comment Console.Write(("<!--" + Value + "-->")) Case XmlNodeType.Document Console.Write("<?xml version='1.0'?>") Case XmlNodeType.Whitespace Console.Write(Value) Case XmlNodeType.SignificantWhitespace Console.Write(Value) Case XmlNodeType.EndElement Console.Write(("</" + Name + ">")) End Select End While End Sub End Class Public Class XmlReaderReader Inherits XmlTextReader Private _Reader As XmlTextReader Public Sub New(reader As XmlTextReader) _Reader = reader End Sub ' XmlReader methods and properties. Public Overrides ReadOnly Property NodeType() As XmlNodeType Get Return _Reader.NodeType End Get End Property Public Overrides ReadOnly Property Name() As [String] Get Return _Reader.Name End Get End Property Public Overrides ReadOnly Property LocalName() As [String] Get Return _Reader.LocalName End Get End Property Public Overrides ReadOnly Property NamespaceURI() As [String] Get Return _Reader.NamespaceURI End Get End Property Public Overrides ReadOnly Property Prefix() As [String] Get Return _Reader.Prefix End Get End Property Public Overrides ReadOnly Property HasValue() As Boolean Get Return _Reader.HasValue End Get End Property Public Overrides ReadOnly Property Value() As String Get Return _Reader.Value End Get End Property Public Overrides ReadOnly Property Depth() As Integer Get Return _Reader.Depth End Get End Property Public Overrides ReadOnly Property BaseURI() As String Get Return _Reader.BaseURI End Get End Property Public Overrides ReadOnly Property IsEmptyElement() As Boolean Get Return _Reader.IsEmptyElement End Get End Property Public Overrides ReadOnly Property IsDefault() As Boolean Get Return _Reader.IsDefault End Get End Property Public Overrides ReadOnly Property QuoteChar() As Char Get Return _Reader.QuoteChar End Get End Property Public Overrides ReadOnly Property XmlSpace() As XmlSpace Get Return _Reader.XmlSpace End Get End Property Public Overrides ReadOnly Property XmlLang() As String Get Return _Reader.XmlLang End Get End Property Public Overrides ReadOnly Property AttributeCount() As Integer Get Return _Reader.AttributeCount End Get End Property Overloads Public Overrides Function GetAttribute(name As String) As String Return _Reader.GetAttribute(name) End Function Overloads Public Overrides Function GetAttribute(name As String, namespaceURI As String) As String Return _Reader.GetAttribute(name, namespaceURI) End Function Overloads Public Overrides Function GetAttribute(i As Integer) As String Return _Reader.GetAttribute(i) End Function Default Public Overrides Overloads ReadOnly Property Item(i As Integer) As String Get Return _Reader(i) End Get End Property Default Public Overrides Overloads ReadOnly Property Item(name As String) As String Get Return _Reader(name) End Get End Property Default Public Overrides Overloads ReadOnly Property Item(name As String, namespaceURI As String) As String Get Return _Reader(name, namespaceURI) End Get End Property Overloads Public Overrides Function MoveToAttribute(name As String) As Boolean Return _Reader.MoveToAttribute(name) End Function Overloads Public Overrides Function MoveToAttribute(name As String, ns As String) As Boolean Return _Reader.MoveToAttribute(name, ns) End Function Overloads Public Overrides Sub MoveToAttribute(i As Integer) _Reader.MoveToAttribute(i) End Sub Public Overrides Function MoveToFirstAttribute() As Boolean Return _Reader.MoveToFirstAttribute() End Function Public Overrides Function MoveToNextAttribute() As Boolean Return _Reader.MoveToNextAttribute() End Function Public Overrides Function MoveToElement() As Boolean Return _Reader.MoveToElement() End Function ' This is the only place that needs to be changed. Public Overrides Function Read() As Boolean Return _Reader.Read() End Function Public Overrides ReadOnly Property EOF() As Boolean Get Return _Reader.EOF End Get End Property Public Overrides Overloads Sub Close() _Reader.Close() End Sub Public Overrides ReadOnly Property ReadState() As ReadState Get Return _Reader.ReadState End Get End Property Public Overrides Function ReadString() As String Return _Reader.ReadString() End Function Public Overrides Function ReadInnerXml() As String Return _Reader.ReadInnerXml() End Function Public Overrides Function ReadOuterXml() As String Return _Reader.ReadOuterXml() End Function Public Overrides ReadOnly Property NameTable() As XmlNameTable Get Return _Reader.NameTable End Get End Property Public Overrides Function LookupNamespace(prefix As String) As String Return _Reader.LookupNamespace(prefix) End Function Public Overrides Overloads Sub ResolveEntity() _Reader.ResolveEntity() End Sub Public Overrides Function ReadAttributeValue() As Boolean Return _Reader.ReadAttributeValue() End Function End Class End Class End Namespace [C#]using System; using System.Xml; // This sample demonstrate the ability to chain XmlReaders together by // implementing an XmlReaderReader class which aggregates any given // XmlReader and then delegates the calls to it. namespace Test { public class MyApp { public static void Main() { XmlTextReader reader = new XmlTextReader("books.xml"); XmlChainingReader customreader = new XmlChainingReader(reader); customreader.ReadandWrite(); } class XmlChainingReader : XmlReaderReader { public XmlChainingReader (XmlReader reader) : base (reader) {} public override bool Read () { bool result; result = base.Read(); switch (base.NodeType) { case XmlNodeType.Element: if (base.Name.Equals("price")) base.Skip(); break; default: break; } return result; } public void ReadandWrite() { // Read each node in the tree. while (Read()) { switch (NodeType) { case XmlNodeType.Element: Console.Write("<" + Name); while (MoveToNextAttribute()) Console.Write(" " + Name + "='" + Value + "'"); Console.Write(">"); break; case XmlNodeType.Text: Console.Write(Value); break; case XmlNodeType.CDATA: Console.Write(Value); break; case XmlNodeType.ProcessingInstruction: Console.Write("<?" + Name + " " + Value + "?>"); break; case XmlNodeType.Comment: Console.Write("<!--" + Value + "-->"); break; case XmlNodeType.Document: Console.Write("<?xml version='1.0'?>"); break; case XmlNodeType.Whitespace: Console.Write(Value); break; case XmlNodeType.SignificantWhitespace: Console.Write(Value); break; case XmlNodeType.EndElement: Console.Write("</" + Name + ">"); break; } } } } public class XmlReaderReader : XmlReader { XmlReader _Reader; public XmlReaderReader (XmlReader reader ) { _Reader = reader; } // XmlReader methods and properties. public override XmlNodeType NodeType { get { return _Reader.NodeType; } } public override String Name { get { return _Reader.Name; } } public override String LocalName { get { return _Reader.LocalName; } } public override String NamespaceURI { get { return _Reader.NamespaceURI; } } public override String Prefix { get { return _Reader.Prefix; } } public override bool HasValue { get { return _Reader.HasValue; } } public override string Value { get { return _Reader.Value; } } public override int Depth { get { return _Reader.Depth; } } public override string BaseURI { get { return _Reader.BaseURI; } } public override bool IsEmptyElement { get { return _Reader.IsEmptyElement; } } public override bool IsDefault { get { return _Reader.IsDefault; } } public override char QuoteChar { get { return _Reader.QuoteChar; } } public override XmlSpace XmlSpace { get { return _Reader.XmlSpace; } } public override string XmlLang { get { return _Reader.XmlLang; } } public override int AttributeCount { get { return _Reader.AttributeCount; } } public override string GetAttribute(string name) { return _Reader.GetAttribute( name ); } public override string GetAttribute(string name, string namespaceURI) { return _Reader.GetAttribute( name, namespaceURI ); } public override string GetAttribute(int i) { return _Reader.GetAttribute( i ); } public override string this [ int i ] { get { return _Reader[ i ]; } } public override string this [ string name ] { get { return _Reader[ name ]; } } public override string this [ string name,string namespaceURI ] { get { return _Reader[ name, namespaceURI ]; } } public override bool MoveToAttribute(string name) { return _Reader.MoveToAttribute( name ); } public override bool MoveToAttribute(string name, string ns) { return _Reader.MoveToAttribute( name, ns ); } public override void MoveToAttribute(int i) { _Reader.MoveToAttribute( i ); } public override bool MoveToFirstAttribute() { return _Reader.MoveToFirstAttribute(); } public override bool MoveToNextAttribute() { return _Reader.MoveToNextAttribute(); } public override bool MoveToElement() { return _Reader.MoveToElement(); } // // This is the only place that needs to be changed. // public override bool Read() { return _Reader.Read(); } public override bool EOF { get { return _Reader.EOF; } } public override void Close() { _Reader.Close(); } public override ReadState ReadState { get { return _Reader.ReadState; } } public override string ReadString() { return _Reader.ReadString(); } public override string ReadInnerXml() { return _Reader.ReadInnerXml(); } public override string ReadOuterXml() { return _Reader.ReadOuterXml(); } public override XmlNameTable NameTable { get { return _Reader.NameTable; } } public override string LookupNamespace(string prefix) { return _Reader.LookupNamespace( prefix ); } public override void ResolveEntity() { _Reader.ResolveEntity(); } public override bool ReadAttributeValue() { return _Reader.ReadAttributeValue(); } } } }
See Also
Reading XML with the XmlReader | Reading XML Data with XmlTextReader | Reading Node Trees with XmlNodeReader | Validating XML with XmlValidatingReader | XmlReader Class | XmlReader Members | XmlNodeReader Class | XmlNodeReader Members | XmlTextReader Class | XmlTextReader Members | XmlValidatingReader Class | XmlValidatingReader