Serialize XML from C # class, must define namespaces

advertisements

I'm having trouble getting my top-level element to look exactly like this using the XmlSerializer (and C# attributes):

<rootObject xmlns="http://www.example.com/xmlschemas/nonStandardSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.example.com/xmlschemas/nonStandardSchema1.xsd">
    <otherSerializedObjects />
</rootObject>

Currently, the closest I've gotten is this:

<rootObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    d1p1:schemaLocation="http://www.example.com/xmlschemas/nonStandardSchema1.xsd"
    xmlns:d1p1="xsi"
    xmlns="http://www.example.com/xmlschemas/nonStandardSchema">
    <otherSerializedObjects />
</rootObject>

C#

[XmlRoot("rootObject", Namespace = "http://www.example.com/xmlschemas/nonStandardSchema")]
public class RootObject
{
    [XmlAttribute("schemaLocation", Namespace = "xsi")]
    public string SchemaLocation { get; set; }

    [XmlElement("Image")]
    public Object[] OtherSerializedObjects { get; set; }

    public RootObject()
    {
        OtherSerializedObjects = new Object[]{};
    }
}   

public class Program
{
    static void Main(string[] args)
    {
        var rootObject = new RootObject
        {
            SchemaLocation = "http://www.example.com/xmlschemas/nonStandardSchema1.xsd",
            OtherSerializedObjects = new object[]{}
        };

        var serializer = new XmlSerializer(typeof(RootObject));
        var stringWriter = new StringWriter();
        serializer.Serialize(stringWriter, rootObject);
        Console.WriteLine(stringWriter.ToString());
    }
}

Any ideas?


Firstly, the [XmlAttribute(Namespace=X)] attribute on your schemaLocation field/property needs to have the full namespace for the value of X, not the local namespace shortcut. Incidentally, this can be a property rather than a field. Using a field for this purpose wastes memory.

Secondly, to eliminate the standard xmlns:xsd="http://www.w3.org/2001/XMLSchema", use an XmlSerializer.Serialize overload where you pass in an XmlSerializerNamespaces with just the namespaces you want.

Thus:

[XmlRoot("rootObject", Namespace = "http://www.example.com/xmlschemas/nonStandardSchema")]
public class RootObject
{
    public static XmlSerializerNamespaces GetAdditionalNamespaces()
    {
        XmlSerializerNamespaces xsNS = new XmlSerializerNamespaces();

        xsNS.Add("", "http://www.example.com/xmlschemas/nonStandardSchema");
        xsNS.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

        return xsNS;
    }

    [XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public string XSDSchemaLocation
    {
        get
        {
            return "http://www.example.com/xmlschemas/nonStandardSchema1.xsd";
        }
        set
        {
            // Do nothing - fake property.
        }
    }

    [XmlElement("Image")]
    public Object[] OtherSerializedObjects { get; set; }

    public RootObject()
    {
        OtherSerializedObjects = new Object[]{};
    }
}

And then use it like:

        var rootObject = new RootObject
        {
            OtherSerializedObjects = new object[]{}
        };

        var serializer = new XmlSerializer(typeof(RootObject));
        var stringWriter = new StringWriter();
        var ns = RootObject.GetAdditionalNamespaces();

        var settings = new XmlWriterSettings() { Indent = true, IndentChars = "    " }; // For cosmetic purposes.
        using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
        {
            serializer.Serialize(xmlWriter, rootObject, ns);
        }

        Console.WriteLine(stringWriter.ToString());

Example fiddle.