0

I have an XML file which I can't modify by myself. It contains the following root element:

<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" noNamespaceSchemaLocation="some.xsd">

As you can see the prefix xsi: is missing for noNamespaceSchemaLocation. This causes the XmlReader to not find the schema information while validating. If I add the prefix all is good. But as I said I can't modify the XML file (besides testing). I get them from an external source and my tool should automatically validate them.

Is there a possibility to make the XmlReader interpret noNamespaceSchemaLocation without the xsi: prefix? I don't want to add the prefix inside the XML in a preprocessing step or something like that as the sources should exactly remain as they are.

5
  • 1
    Depending on who your external source is, why don't you file a bugreport for them? Commented Mar 27, 2017 at 9:34
  • How do you validate your Xml? XmlValidatingReader? Commented Mar 27, 2017 at 9:39
  • @Staeff Unfortunately this is useless. They won't fix it cause they won't validate their own sources. This is only the tip of the iceberg. You won't believe what stuff they call XML. And as we need the data, we have to handle it. We had some small victories but if they change something it takes months. Commented Mar 27, 2017 at 12:54
  • @xanatos XmlReader with XmlReaderSettings. Commented Mar 27, 2017 at 12:54
  • @xanatos how to do that using XmlReader and XmlReadersettings if my Uri containing XSD is having the prefix , for example, foo://path/name.xsd Commented Nov 28, 2019 at 11:26

2 Answers 2

3

The XML is wrong and you need to fix it. Either get your supplier to improve the quality of what they send, or repair it on arrival.

I don't know why you want to retain the broken source (all quality standards say that's bad practice), but it's certainly possible to keep the broken original as well as the repaired version.

Sign up to request clarification or add additional context in comments.

2 Comments

Saddly this is the story of my job life. I get crap and have to make gold out of it. Those sources are old and nobody feels responsible. And I can't fix them by myself because of access restrictions. But thanks for the reply. I'll try to convince someone to fix this.
It seems to be a common problem, judging from SO, that organisations don't complain about faulty data nearly as much as they would complain, for example, if they were sent faulty microchips. They should.
2

The internals of XmlReader are ugly and undocumented. So this solution is like playing with fire.

What I propose is: a XmlTextReader that "adds" the missing namespace. You can feed directly this FixingXmlTextReader to a XDocument.Load() OR you can feed it to a XmlTextReader/XmlValidatingReader (they all have a constructor/Create that accept a XmlReader as a parameter)

public class FixingXmlTextReader : XmlTextReader
{
    public override string NamespaceURI
    {
        get
        {
            if (NodeType == XmlNodeType.Attribute && base.LocalName == "noNamespaceSchemaLocation")
            {
                return NameTable.Add("http://www.w3.org/2001/XMLSchema-instance");
            }

            return base.NamespaceURI;
        }
    }

    public override string Prefix
    {
        get
        {
            if (NodeType == XmlNodeType.Attribute && base.NamespaceURI == string.Empty && base.LocalName == "noNamespaceSchemaLocation")
            {
                return NameTable.Add("xsi");
            }

            return base.Prefix;
        }
    }

    public override string Name
    {
        get
        {
            if (NodeType == XmlNodeType.Attribute && base.NamespaceURI == string.Empty && base.LocalName == "noNamespaceSchemaLocation")
            {
                return NameTable.Add(Prefix + ":" + LocalName);
            }

            return base.Name;
        }
    }

    public override string GetAttribute(string localName, string namespaceURI)
    {
        if (localName == "noNamespaceSchemaLocation" && namespaceURI == "http://www.w3.org/2001/XMLSchema-instance")
        {
            namespaceURI = string.Empty;
        }

        return base.GetAttribute(localName, namespaceURI);
    }

    public override string GetAttribute(string name)
    {
        if (name == "xsi:noNamespaceSchemaLocation")
        {
            name = "noNamespaceSchemaLocation";
        }

        return base.GetAttribute(name);
    }

    // There are tons of constructors, take the ones you need
    public FixingXmlTextReader(Stream stream) : base(stream)
    {
    }

    public FixingXmlTextReader(TextReader input) : base(input)
    {
    }

    public FixingXmlTextReader(string url) : base(url)
    {
    }
}

Like:

using (var reader = new FixingXmlTextReader("XMLFile1.xml"))
using (var reader2 = XmlReader.Create(reader, new XmlReaderSettings
{
}))
{
    // Use the reader2!
}

or

using (var reader = new FixingXmlTextReader("XMLFile1.xml"))
{
    var xdoc = new XmlDocument();
    xdoc.Load(reader);
}

5 Comments

Unfortunately this doesn't work. But maybe I used it wrong. I tried the following code: using (FixingXmlTextReader fixingReader = new FixingXmlTextReader(file)) using (XmlReader reader = XmlReader.Create(fixingReader, settings)) { while (reader.Read()) ; } The debugger only enters the NamespaceURI getter but none of the other properties/methods of FixingXmlTextReader.
@RobertS. It won't enter everywhere... I've added more overloads than necessary. But sadly, as I've written, it isn't an exact science the working of XmlReader :-(
@RobertS. In the settings add: ValidationType = ValidationType.Schema, ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.ProcessSchemaLocation, XmlResolver = new XmlUrlResolver()
@RobertS. Found the problem... Retry... There is a "funny" caching of strings inside XmlReader... I didn't know.
I really appreciate your effort. It works now. ;) But I have to accept Michaels answer as he is right: Fixing wrong sources is better than creating workarounds to handle them. But I gave your answer a thumbs up. :) Thanks again.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.