I want to use a XmlTextReader
that ignores Namespaces and does not check characters. To ignore namespaces I can set the property Namespaces=false
a
In my case, as part of a provider's api versioning strategy, I came accross the need of supporting different response namespaces while deserialising with XmlSerializer to the same C# class.
The responses are basically the same, but the root namespace in the response is different depending on the credentials passed to the service.
So, I have used XmlWrappingReader approach to rename the namespace returned by the service to the namespace that the C# classes have attached through the XmlTypeAttribute.
But just one caveat: use string intering as I suspect the XmlSerializer is using Object.ReferenceEquals while reading from the XmlReader to match against the target namespace in the c# class.
In my case, the replacementNs parameter was obtained from the type's XmlTypeAttribute through reflection and apparently was not the exact same object reference as the string internally used by the XmlSerializer.
I almost lost my hair with this silly thing…
public class ReplaceNsXmlReader : XmlWrappingReader
{
private readonly string replacementNs;
public ReplaceNsXmlReader(XmlReader reader, string replacementNs)
: base(reader)
{
//
// NOTE: String.Intern is here needed for the XmlSerializer
// that will be using this reader to deserialize correctly
//
this.replacementNs = String.Intern(replacementNs);
}
public override string NamespaceURI
{
get => replacementNs;
}
}
It is not that hard.
My task was to deserialize xml files of the same structure which can be with or without a default namespace declaration.
First I found this discussion with the XmlTextReader solution: NamespaceIgnorantXmlTextReader. But MSDN recommends not to use XmlTextReader and use XmlReader instead.
So we need to do the same thing on the XmlReader.
XmlReader is an abstract class and we need to do a wrapper first. Here is a good article how to do it. And here is a ready XmlWrappingReader.
Then we need to extend it:
public class XmlExtendableReader : XmlWrappingReader
{
private bool _ignoreNamespace { get; set; }
public XmlExtendableReader(TextReader input, XmlReaderSettings settings, bool ignoreNamespace = false)
: base(XmlReader.Create(input, settings))
{
_ignoreNamespace = ignoreNamespace;
}
public override string NamespaceURI
{
get
{
return _ignoreNamespace ? String.Empty : base.NamespaceURI;
}
}
}
That's it. Now we can use it and control both XmlReaderSettings and a namespace treatment:
XmlReaderSettings settings = new XmlReaderSettings()
{
CheckCharacters = false,
ConformanceLevel = ConformanceLevel.Document,
DtdProcessing = DtdProcessing.Ignore,
IgnoreComments = true,
IgnoreProcessingInstructions = true,
IgnoreWhitespace = true,
ValidationType = ValidationType.None
};
using (XmlExtendableReader xmlreader = new XmlExtendableReader(reader, settings, true))
_entities = ((Orders)_serializer.Deserialize(xmlreader)).Order;