On creating custom XmlReaders/XmlWriters in .NET 2.0, Part 2

| 8 Comments | No TrackBacks

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.

+ XmlWrappingWriter class.

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.

Related Blog Posts

No TrackBacks

TrackBack URL: http://www.tkachenko.com/cgi-bin/mt-tb.cgi/587

8 Comments

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? ;-)

Leave a comment