"Namespace prefix not defined" when it actually is defined

21,410

Your deserialization code could look something like this:

    XmlSerializer sz = new XmlSerializer(typeof(booksType));
    var reader = new XmlNodeReader(booksXmlNode);
    var books = sz.Deserialize(reader);

[EDIT] This is better, because the namespace declarations are preserved with the XmlNode, whereas converting to an XML string via OuterXml appears to slice off the namespace declaration for the ns1 prefix, and the serializer then barfs on the type attribute value containing this prefix. I imagine this is a bug in the XML implementation but maybe an XML guru can confirm this.

This should get you past the error you are seeing, but whether it solves the problem completely I'm not sure.

[FURTHER EDIT] As noted in the comments below, there is a bug in the .NET XmlSerializer which is causing the deserialization to fail. Stepping through the deserialization code in the generated assembly, there is a point where the following condition is tested:

(object) ((System.Xml.XmlQualifiedName)xsiType).Namespace == (object)id2_namespace)) 

Although the Namespace property of the XmlQualifiedName has the same value ('namespace') as the string variable id2_namespace, the condition is evaluating to false because it is coded as an object identity test rather than a test for string value equivalence. Failing this condition leads directly to the exception reported by OP.

As far as I can see, this bug will always cause deserialization to fail whenever the XML for the object being deserialized uses one prefix on the object's root element name, and another prefix (defined as the same namespace) on that element's xsi:type attribute.

Share:
21,410
wilee
Author by

wilee

By day: web and data application developer for a Very Large Enterprise By night: web and data application developer for a Very Large Enterprise

Updated on January 29, 2020

Comments

  • wilee
    wilee about 4 years

    I'm having trouble deserializing XML with an "undefined" namespace prefix which really is defined.

    We've published an internal web service in C# which serves a variety of clients. A new client's IDE insists on declaring xsi:type for every element in its XML output, and they can't turn off this "feature".

    The XML message they produce goes like this, where "namespace" is the correct namespace.

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
      <myOperation xsi:type="ns1:namespace" xmlns="namespace" xmlns:ns1="namespace">
        <inputString xsi:type="xsd:string">ABCDEF</inputString>
        <books xsi:type="ns1:booksType">
          <bookID xsi:type="xsd:string">ABC123</bookID>
          <bookID xsi:type="xsd:string">DEF456</bookID>
        </books>
        <!-- ... snip... -->
      </myOperation>
    </soapenv:Body>
    

    <books> is basically an array of strings.

    The service method accepts as XmlNode, but XmlSerializer throws a "prefix 'ns1' not defined" error. (It is defined in a parent node, but apparently that is not good enough.) I have a similar problem using wsdl.exe to generate classes and deserialize the input for me.

    Using XmlNamespaceManager to specify prefixes doesn't seem right -- akin to magic numbers, and I can't predict which prefix a given consumer will declare anyway. Is there a way to handle this without stripping the attributes out (books.Attributes.RemoveAll)? That doesn't feel particularly elegant either.

    I've found that books.OuterXML does not contain any information for 'ns1' unless I hack the element inbound to use that prefix (), so I can see why it complains, but I don't yet understand why 'ns1' isn't recognized from its previous definition above.

    Many thanks for any help, or at least education, someone can provide.

    Edits: it works fine if I change <books> to use the prefix, i.e. <ns1:books xsi:type="ns1:booksType">. This works whether I've defined xmlns or no. That may be consistent with this answer, but I still don't see how I would feasibly declare the prefix in the service code.

    @Chris, certainly. Hope I can strike a balance between "stingy with closed source" and "usable for those who would help". Here "books" is the XmlNode received in the service method parameter. (Not to get off topic, but will also humbly take suggestions to improve it in general; I'm still a novice.)

    XmlSerializer xmlSerializer = new XmlSerializer(typeof(booksType));
    StringReader xmlDataReader = new StringReader(books.OuterXml);
    books = (booksType)xmlSerializer.Deserialize(xmlDataReader);
    

    The class is pretty much this:

    [Serializable()]
    [XmlRoot("books", Namespace = "namespace")]
    [XmlTypeAttribute(TypeName = "booksType", Namespace = "namespace")]
    public class booksType
    {
        [XmlElement(ElementName = "bookID")]
        public string[] bookIDs { get; set; }
    }