This is second part of the post. Find first part here.
So what is a better way of creating custom XmlReader/XmlWriter in .NET 2.0? Here is the idea - have an utility wrapper class, which wraps XmlReader/XmlWriter and does nothing else. Then derive from this class and override methods you are interested in. These utility wrappers are called XmlWrapingReader and XmlWrapingWriter. They are part of System.Xml namespace, but unfortunately they are internal ones - Microsoft XML team has considered making them public, but in the Whidbey release rush decided to postpone this issue. Ok, happily these classes being pure wrappers have no logic whatsoever so anybody who needs them can indeed create them in a 10 minutes. But to save you that 10 minutes I post these wrappers here. I will include XmlWrapingReader and XmlWrapingWriter into the next Mvp.Xml library release.
Btw, most likely the Mvp.Xml project will be rehosted to the CodePlex. SourceForge is ok, but the idea is that more Microsoft-friendly environment will induce more contributors both XML MVPs and others.
+
XmlWrappingReader class.
using System;
using System.Xml;
using System.Xml.Schema;
namespace Mvp.Xml.Common
{
public class XmlWrappingReader : XmlReader, IXmlLineInfo
{
protected XmlReader reader;
protected IXmlLineInfo readerAsIXmlLineInfo;
public XmlWrappingReader(XmlReader baseReader)
{
this.Reader = baseReader;
}
public override void Close()
{
this.reader.Close();
}
protected override void Dispose(bool disposing)
{
((IDisposable) this.reader).Dispose();
}
public override string GetAttribute(int i)
{
return this.reader.GetAttribute(i);
}
public override string GetAttribute(string name)
{
return this.reader.GetAttribute(name);
}
public override string GetAttribute(string name, string namespaceURI)
{
return this.reader.GetAttribute(name, namespaceURI);
}
public virtual bool HasLineInfo()
{
if (this.readerAsIXmlLineInfo != null)
{
return this.readerAsIXmlLineInfo.HasLineInfo();
}
return false;
}
public override string LookupNamespace(string prefix)
{
return this.reader.LookupNamespace(prefix);
}
public override void MoveToAttribute(int i)
{
this.reader.MoveToAttribute(i);
}
public override bool MoveToAttribute(string name)
{
return this.reader.MoveToAttribute(name);
}
public override bool MoveToAttribute(string name, string ns)
{
return this.reader.MoveToAttribute(name, ns);
}
public override bool MoveToElement()
{
return this.reader.MoveToElement();
}
public override bool MoveToFirstAttribute()
{
return this.reader.MoveToFirstAttribute();
}
public override bool MoveToNextAttribute()
{
return this.reader.MoveToNextAttribute();
}
public override bool Read()
{
return this.reader.Read();
}
public override bool ReadAttributeValue()
{
return this.reader.ReadAttributeValue();
}
public override void ResolveEntity()
{
this.reader.ResolveEntity();
}
public override void Skip()
{
this.reader.Skip();
}
public override int AttributeCount
{
get
{
return this.reader.AttributeCount;
}
}
public override string BaseURI
{
get
{
return this.reader.BaseURI;
}
}
public override bool CanResolveEntity
{
get
{
return this.reader.CanResolveEntity;
}
}
public override int Depth
{
get
{
return this.reader.Depth;
}
}
public override bool EOF
{
get
{
return this.reader.EOF;
}
}
public override bool HasAttributes
{
get
{
return this.reader.HasAttributes;
}
}
public override bool HasValue
{
get
{
return this.reader.HasValue;
}
}
public override bool IsDefault
{
get
{
return this.reader.IsDefault;
}
}
public override bool IsEmptyElement
{
get
{
return this.reader.IsEmptyElement;
}
}
public virtual int LineNumber
{
get
{
if (this.readerAsIXmlLineInfo != null)
{
return this.readerAsIXmlLineInfo.LineNumber;
}
return 0;
}
}
public virtual int LinePosition
{
get
{
if (this.readerAsIXmlLineInfo != null)
{
return this.readerAsIXmlLineInfo.LinePosition;
}
return 0;
}
}
public override string LocalName
{
get
{
return this.reader.LocalName;
}
}
public override string Name
{
get
{
return this.reader.Name;
}
}
public override string NamespaceURI
{
get
{
return this.reader.NamespaceURI;
}
}
public override XmlNameTable NameTable
{
get
{
return this.reader.NameTable;
}
}
public override XmlNodeType NodeType
{
get
{
return this.reader.NodeType;
}
}
public override string Prefix
{
get
{
return this.reader.Prefix;
}
}
public override char QuoteChar
{
get
{
return this.reader.QuoteChar;
}
}
protected XmlReader Reader
{
get
{
return this.reader;
}
set
{
this.reader = value;
this.readerAsIXmlLineInfo = value as IXmlLineInfo;
}
}
public override System.Xml.ReadState ReadState
{
get
{
return this.reader.ReadState;
}
}
public override IXmlSchemaInfo SchemaInfo
{
get
{
return this.reader.SchemaInfo;
}
}
public override XmlReaderSettings Settings
{
get
{
return this.reader.Settings;
}
}
public override string Value
{
get
{
return this.reader.Value;
}
}
public override Type ValueType
{
get
{
return this.reader.ValueType;
}
}
public override string XmlLang
{
get
{
return this.reader.XmlLang;
}
}
public override System.Xml.XmlSpace XmlSpace
{
get
{
return this.reader.XmlSpace;
}
}
}
}
+
XmlWrappingWriter class.
using System;
using System.Xml;
namespace Mvp.Xml.Common
{
public class XmlWrappingWriter : XmlWriter
{
protected XmlWriter writer;
public XmlWrappingWriter(XmlWriter baseWriter)
{
this.Writer = baseWriter;
}
public override void Close()
{
this.writer.Close();
}
protected override void Dispose(bool disposing)
{
((IDisposable) this.writer).Dispose();
}
public override void Flush()
{
this.writer.Flush();
}
public override string LookupPrefix(string ns)
{
return this.writer.LookupPrefix(ns);
}
public override void WriteBase64(byte[] buffer, int index, int count)
{
this.writer.WriteBase64(buffer, index, count);
}
public override void WriteCData(string text)
{
this.writer.WriteCData(text);
}
public override void WriteCharEntity(char ch)
{
this.writer.WriteCharEntity(ch);
}
public override void WriteChars(char[] buffer, int index, int count)
{
this.writer.WriteChars(buffer, index, count);
}
public override void WriteComment(string text)
{
this.writer.WriteComment(text);
}
public override void WriteDocType(string name, string pubid, string sysid, string subset)
{
this.writer.WriteDocType(name, pubid, sysid, subset);
}
public override void WriteEndAttribute()
{
this.writer.WriteEndAttribute();
}
public override void WriteEndDocument()
{
this.writer.WriteEndDocument();
}
public override void WriteEndElement()
{
this.writer.WriteEndElement();
}
public override void WriteEntityRef(string name)
{
this.writer.WriteEntityRef(name);
}
public override void WriteFullEndElement()
{
this.writer.WriteFullEndElement();
}
public override void WriteProcessingInstruction(string name, string text)
{
this.writer.WriteProcessingInstruction(name, text);
}
public override void WriteRaw(string data)
{
this.writer.WriteRaw(data);
}
public override void WriteRaw(char[] buffer, int index, int count)
{
this.writer.WriteRaw(buffer, index, count);
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
this.writer.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteStartDocument()
{
this.writer.WriteStartDocument();
}
public override void WriteStartDocument(bool standalone)
{
this.writer.WriteStartDocument(standalone);
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
this.writer.WriteStartElement(prefix, localName, ns);
}
public override void WriteString(string text)
{
this.writer.WriteString(text);
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
{
this.writer.WriteSurrogateCharEntity(lowChar, highChar);
}
public override void WriteValue(bool value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(DateTime value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(decimal value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(double value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(int value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(long value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(object value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(float value)
{
this.writer.WriteValue(value);
}
public override void WriteValue(string value)
{
this.writer.WriteValue(value);
}
public override void WriteWhitespace(string ws)
{
this.writer.WriteWhitespace(ws);
}
public override XmlWriterSettings Settings
{
get
{
return this.writer.Settings;
}
}
protected XmlWriter Writer
{
get
{
return this.writer;
}
set
{
this.writer = value;
}
}
public override System.Xml.WriteState WriteState
{
get
{
return this.writer.WriteState;
}
}
public override string XmlLang
{
get
{
return this.writer.XmlLang;
}
}
public override System.Xml.XmlSpace XmlSpace
{
get
{
return this.writer.XmlSpace;
}
}
}
}
Now instead of deriving from legacy XmlTextReader/XmlTextWriter you derive from XmlWrappingReader/XmlWrappingWriter passing to their constructors XmlReader/XmlWriter created via Create() factory method:
public class RenamingXmlReader : XmlWrappingReader
{
//Provide as many contructors as you need
public RenamingXmlReader(string file)
: base(XmlReader.Create(file)) { }
public override string Name
{
get
{
return (NodeType == XmlNodeType.Element &&
base.Name == "value") ?
"price" : base.Name;
}
}
public override string LocalName
{
get
{
return (NodeType == XmlNodeType.Element &&
base.LocalName == "value") ?
"price" : base.LocalName;
}
}
}
public class RenamingXmlWriter : XmlWrappingWriter
{
//Provide as many contructors as you need
public RenamingXmlWriter(TextWriter output)
: base(XmlWriter.Create(output)) { }
public override void WriteStartElement(string prefix, string localName, string ns)
{
if (string.IsNullOrEmpty(prefix) && localName == "price")
{
localName = "value";
}
base.WriteStartElement(prefix, localName, ns);
}
}
That's it. Not much different from previous option in terms of coding, but free of weird XmlTextReader/XmlTextWriter legacy.
AFAIK there is still one problem with this approach though, which is DTD validation. I mean cascading validating XmlReader on top of custom XmlReader scenario. E.g. if you need to resolve XInclude or rename couple of elements and validate resulting XML against DTD in one shot. In .NET 2.0 if you want to DTD validate XML that comes from another XmlReader that reader must be an instance of XmlTextReader. That's undocumented limitation and it was left sort of deliberatly - after all who cares about DTD nowadays? XML Schema validation is not affected by this limitation.
This is the most valuable information i get so far.
i was looking for some implementation to replace XMLTextWriter,but just stuck for quite some time.
now,i can use it on silverlight
umair, MSXML or XmlLite for native C++, System.Xml for managed C++. And this is only from Microsoft.
does any method exist to write in an xml file using C++?
I'm not following you. That would be nice, but XmlReader.Create() factory method knows only XmlReaderSettings and will ignore any derived extentions.
And after all XmlWrappingReader/XmlWrappingWriter classes are useless on their own, the whole point is extending them.
Just imagine if your code could get some XmlReaderSettings derived instance and just call XmlReader.Create with it. The plain XmlReaderSettings instance could lead to creating a XmlReader instance. A XmlWrappingReaderSettings could lead to creating a XmlWrappingReader.
This way, it looks like a factory, but doesn't smell like it.
Paulo, no. Unfortunately XmlReader/XmlWriter factory model is not extensible.
Can instances of the XmlWrappingReader/XmlWrappingWriter classes be created using the XmlReader/XmlWriter factory model?
CodePlex, eh? ;-)