XmlValidatingReader problems over derived XmlReaders
This whole validation ickiness deserved two posts, so I didn't mention it in the last XmlValidatingReader post.
The XML format that I'm parsing and validating isn't the savvyest of formats as it was created years ago before the XML Schema specification was complete. While it has a namespace and it's an official specification, the instance documents don't have a namespace. They are entirely "unqualified." So, basically I'm trying to validate XML documents with a namespace against a schema that expects namespaces.
Additionally, the elementFormDefault is set to "unqualified." There's a great explanation of what elementFormDefault means here.
The documents come in like this:
Before I'd look hard at the schema I had assumed that I could load them with an XmlNamespaceUpgradeReader. This is a derivation of XmlTextReader that does nothing but lie about the Namespace of every element. I'm using System.Xml on .NET 1.1.
public class XmlNamespaceUpgradeReader : XmlTextReader
public XmlNamespaceUpgradeReader( TextReader reader, string oldNamespaceUri, string newNamespaceURI ):base( reader )
this.oldNamespaceUri = oldNamespaceUri;
this.newNamespaceUri = newNamespaceURI;
public override string NamespaceURI
// we are assuming XmlSchemaForm.Unqualified, therefore
// we can't switch the NS here
if ( this.NodeType != XmlNodeType.Attribute &&
base.NamespaceURI == oldNamespaceUri )
For example, if I did this:
XmlTextReader reader = new XmlNamespaceUpgradeReader(
XmlDocument doc = new XmlDocument();
I would end up with this resulting XML:
Seemed like this would validate. Well, not so much. The document, as you can see, is fine. It's exactly what you'd expect. But, the I remember/noticed that the document was elementFormDefault="unqualified" meaning that only the root node needs the namespace. So...
...which results in a document like this:
This document should now validate, and it fact it does in my test applications. When the document is loaded directly from a test file it works fine. When I run it directly through one of the extended "fake-out" XmlTextReaders, it doesn't work. It's as if my readers don't exist at all, even though their code does indeed execute.
To be clear:
Original Doc -> XmlTextReader -> XmlValidatingReader -> doesn't validate (as expected)
Original Doc -> XmlNamespaceUpgradingReader -> XmlValidatingReader -> doesn't validate (but it should!)
Original Doc -> XmlNamespaceUpgradingReader -> XmlDocument -> write to file -> read from file -> XmlValidatingReader -> doesn't validate (as expected, it's "overqualified")
Original Doc -> XmlRootNamespaceUpgradingReader -> XmlDocument -> write to file -> read from file -> XmlValidatingReader -> DOES VALIDATE (as expected)
Why don't the "fake-out" XmlTextReaders work when chained together and feeding the XmlValidatingReader directly, but they do work when there's an intermediate format?
A few things about the XmlValidatingReader in .NET 1.1 (since it's obsolete in 2.0). While its constructor takes the abstract class XmlReader, internally it insists on an XmlTextReader. This is documented, but buried IMHO. Reflector shows us:
XmlTextReader reader1 = reader as XmlTextReader;
if (reader1 == null)
throw new ArgumentException(Res.GetString("Arg_ExpectingXmlTextReader"), "reader");
<conjecture>When a class takes an abstract base class - the one it "should" - but really requires a specific derivation/implementation internally, it's a good hint that the OO hierarchy wasn't completely thought out and/or a refactoring that was going to happen in a future version never happened.</conjecture>
Regardless, System.Xml in .NET 2.0 is much nicer and as well though-out as System.Xml 1.x was, 2.0 is considerably more thought out. However, I'm talking about 1.1.
<suspicion>I take this little design snafu as a strong hint that the XmlValidatingReader in .NET 1.1 has carnal knowledge of XmlTextReader and is probably making some assumptions about the underlying stream and doing some caching rather than taking my fake-out XmlReader's word for it.</suspicion>
If you're on, or were on, the System.Xml team let me know what the deal is and I'll update this post.
I know that the XmlRootNamespaceUpgradingReader works because the XML is correct when it's written out to an intermediate. However, the InfoSet that the XmlValidatingReader acts on is somehow now the same. How did we solve it? Since XmlValidatingReader needs an XmlTextReader that is more "legit," we'll give it one
Original Doc -> XmlRootNamespaceUpgradingReader -> XmlDocument -> CloneXmlReader -> XmlValidatingReader -> DOES VALIDATE
This is cheesy, but if a better way is found at least it's compartmentalized and I can fix it in one place. We quickly run through the input XmlTextReader, write the Infoset out to a MemoryStream and return a "fresh" XmlTextReader and darn it if it doesn't work just fine.
Madness. Many thanks to Tomas Restrepo for his help and graciousness while debugging this issue!