Groups | Blog | Home
all groups > dotnet xml > april 2004 >

dotnet xml : HOWTO Overcome missing namespace declaration in root node


David B. Bitton
4/21/2004 9:59:50 AM
I am having a problem deserializing XML when the root node is missing a
namespace declaration. My Type has an XmlTypeAttribute with a namespace
defined. If I attempt to deserialize the XML, I get the dreaded

<elementname xmlns=''> was not expected

exception. If I comment out the XmlTypeAttribute, it works just fine. Just
so you know, when I instantiate an instance of an XmlSerializer, I pass a
default namespace to the ctor. Unfortunately that doesn't seem to work.

So, how can I get the XmlSerializer to accept XML that is missing namespace
declarations?

--
--

David B. Bitton
david@codenoevil.com
www.codenoevil.com

Code Made Fresh DailyT

Christoph Schittko [MVP]
4/21/2004 11:44:50 PM
David,

Can you post:

* The serialization class
* the tag of the root element, including all namespace definitions
* the line of code where you instantiate the XmlSerializer

--
Christoph Schittko [MVP]
Software Architect, .NET Mentor

[quoted text, click to view]

David B. Bitton
4/22/2004 10:12:13 AM
Chris,
Look inline below:

--
--

David B. Bitton
david@codenoevil.com
www.codenoevil.com

Code Made Fresh Daily™
"Christoph Schittko [MVP]" <christophdotnetINVALID@austin.rr.com> wrote in
message news:eN4XNSCKEHA.952@TK2MSFTNGP12.phx.gbl...
[quoted text, click to view]

[System.Xml.Serialization.XmlTypeAttribute(Namespace=TransferManifest.DEFAUL
T_NAMESPACE)]
[System.Xml.Serialization.XmlRootAttribute(Namespace=TransferManifest.DEFAUL
T_NAMESPACE, IsNullable=false, ElementName="transfermanifest")]
public class TransferManifest {

public const string DEFAULT_NAMESPACE =
"http://codenoevil.com/TransferManifest.xsd";

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("filelist")]
public FileList[] FileLists;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("folderlist")]
public FolderList[] FolderLists;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("uploadinfo")]
public UploadInfo[] UploadInfos;

#region XML (de)serialization code
public static TransferManifest ReadXml(string xml)
{
XmlSerializer xmlSerializer =
new XmlSerializer(typeof(TransferManifest));

xmlSerializer.UnknownNode+= new
XmlNodeEventHandler(XmlSerializer_UnknownNode);
xmlSerializer.UnknownAttribute+= new
XmlAttributeEventHandler(XmlSerializer_UnknownAttribute);

try
{
TransferManifest transferManifest =
(TransferManifest)xmlSerializer.Deserialize(
new StringReader(xml)
);

return transferManifest;
}
catch(Exception ex)
{
throw new ApplicationException("TransferManifest failed to deserialize: "
+ ex.Message, ex);
}
}

public static string WriteXml(TransferManifest transferManifest)
{
XmlSerializer xmlSerializer =
new XmlSerializer(typeof(TransferManifest), DEFAULT_NAMESPACE);

StringWriter stringWriter = new StringWriter();

xmlSerializer.Serialize(stringWriter, transferManifest);

return stringWriter.ToString();
}

private static void XmlSerializer_UnknownNode
(object sender, XmlNodeEventArgs e)
{
Debug.WriteLine("Unknown Node:" + e.Name + "\t" + e.Text);
}

private static void XmlSerializer_UnknownAttribute
(object sender, XmlAttributeEventArgs e)
{
System.Xml.XmlAttribute attr = e.Attr;
Debug.WriteLine("Unknown attribute " +
attr.Name + "='" + attr.Value + "'");
}
#endregion
}


[quoted text, click to view]

<transfermanifest>

[quoted text, click to view]

Look inside the WriteXml() method above.

[quoted text, click to view]

Christoph Schittko [MVP]
4/22/2004 9:08:13 PM
David,

The code you posted works fine for me with this code:

TransferManifest mfst = new TransferManifest();
string xml = TransferManifest.WriteXml( mfst );
mfst = TransferManifest.ReadXml( xml );

but I removed the three array type properties

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("filelist")]
public FileList[] FileLists;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("folderlist")]
public FolderList[] FolderLists;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("uploadinfo")]
public UploadInfo[] UploadInfos;

because I didn't have the class definitions.

The root element

<transfermanifest>

you posted would not deserialize because it's missing the XML namespace that
you declared with the XmlRoot and XmlType attributes. The root element needs
a namespace declaration like this:

<transfermanifest xmlns=http://codenoevil.com/TransferManifest.xsd>

which your code produces.

You could either post more code, or follow the instructions at [0] on how to
debug deserialization.

--
HTH
Christoph Schittko [MVP]
Software Architect, .NET Mentor

[quoted text, click to view]

David B. Bitton
4/23/2004 11:29:44 AM
Chris,
I am well aware of _why_ the exception occurs. Now I need a way to work
around it. How can I provide a "hint" to the XmlSerializer that if the root
node has either an empty xmlns, or none at all, that the root node namespace
_should_ be something, and it's OK if the node is missing the declaration.

--
--

David B. Bitton
david@codenoevil.com
www.codenoevil.com

Code Made Fresh Daily™
"Christoph Schittko [MVP]" <christophdotnetINVALID@austin.rr.com> wrote in
message news:%23qyfVfNKEHA.3216@tk2msftngp13.phx.gbl...
[quoted text, click to view]

Christoph Schittko [MVP]
4/23/2004 10:52:37 PM
David,

Now I am with you ... and tha bad news is that the XmlSerializer is not
really intended to do what you're trying to do. From an XML perspective,
you're trying to deserialize two entirely different XML formats. While the
two formats share the same element names, their QNames (name+namespace) are
different. An XmlSerializer is really only good at processing one format.

You may be able to work around this with two serializer instances. One that
you instantiate with

XmlSerializer ser1 = new XmlSerializer( typeof( TransferManifest ) );

and another one that you instantiate with XmlOverrideAttributes supplied to
the constructor:

<notTested>
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes atts = new XmlAttributes();
// override the XmlType and XmlRoot attributes
atts.XmlType = new XmlTypeAttribute();
atts.XmlRoot = new XmlRootAttribute();
overrides.Add( typeof( TransferManifest ), atts );
XmlSerializer ser2 = new XmlSerializer( typeof( TransferManifest ),
overrides );
</notTested>

then you read the first element of your XML document with an XmlTextReader
to determine if any namespaces are declared.

TransferManifest tm = null;
XmlTextReader reader = new XmlTextReader( new StringReader( xml ) );
if( reader.Read() )
{
if( reader.NamespaceURI = "" )
{
reader.Close();
tm = ser2.Deserialize( new StringReader( xml ) );
}
else
{
reader.Close();
tm = ser1.Deserialize( new StringReader( xml ) );
}
}

Let me know if this works ...
--

Christoph Schittko [MVP, XmlInsider]
Software Architect, .NET Mentor

[quoted text, click to view]
v-kevy NO[at]SPAM online.microsoft.com
4/24/2004 11:09:49 AM
Hi David,

I agree with Chris on this. Since you're serializing two Xml documents with
different formats, I think you have to create two serializers to get them
work. For workaround, Chris has provided us with a good example. If
anything is unclear, please feel free to reply to the post. I'll try my
best to help.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."
AddThis Social Bookmark Button