Search code examples
c#xmlnamespacesdatacontractserializer

DataContractSerializer with Multiple Namespaces


I am using a DataContractSerializer to serialize an object to XML. The main object is SecurityHolding with the namespace "http://personaltrading.test.com/" and contains a property called Amount that's a class with the namespace "http://core.test.com". When I serialize this to XML I get the following:

<ArrayOfSecurityHolding xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://personaltrading.test.com/">
  <SecurityHolding>
    <Amount xmlns:d3p1="http://core.test.com/">
        <d3p1:Amount>1.05</d3p1:Amount>
        <d3p1:CurrencyCode>USD</d3p1:CurrencyCode>
    </Amount>
    <BrokerageID>0</BrokerageID>
    <BrokerageName i:nil="true" />
    <RecordID>3681</RecordID>
  </SecurityHolding></ArrayOfSecurityHolding>

Is there anyway I can control the d3p1 prefix? Am I doing something wrong or should I be doing something else?


Solution

  • Firstly, the choice of namespace alias should make no difference to a well-formed parser.

    But; does it have to be DataContractSerializer? With XmlSerializer, you can use the overload of Serialize that accepts a XmlSerializerNamespaces. This allows you to pick and choose the namespaces and aliases that you use.

    Ultimately; DataContractSerializer is not intended to give full xml control; that isn't its aim. If you want strict xml control, XmlSerializer is a better choice, even if it is older (and has some nuances/foibles of its own).

    Full example:

    using System;
    using System.Xml.Serialization;
    public class Amount
    {
        public const string CoreNamespace = "http://core.test.com/";
        [XmlElement("Amount", Namespace=CoreNamespace)]
        public decimal Value { get; set; }
        [XmlElement("CurrencyCode", Namespace = CoreNamespace)]
        public string Currency { get; set; }
    }
    [XmlType("SecurityHolding", Namespace = SecurityHolding.TradingNamespace)]
    public class SecurityHolding
    {
        public const string TradingNamespace = "http://personaltrading.test.com/";
    
        [XmlElement("Amount", Namespace = Amount.CoreNamespace)]
        public Amount Amount { get; set; }
    
        public int BrokerageId { get; set; }
        public string BrokerageName { get; set; }
        public int RecordId { get; set; }
    }
    static class Program
    {
        static void Main()
        {
            var data = new[] {
                new SecurityHolding {
                    Amount = new Amount {
                        Value = 1.05M,
                        Currency = "USD"
                    },
                    BrokerageId = 0,
                    BrokerageName = null,
                    RecordId = 3681
                }
            };
            var ser = new XmlSerializer(data.GetType(),
                new XmlRootAttribute("ArrayOfSecurityHolding") { Namespace = SecurityHolding.TradingNamespace});
            var ns = new XmlSerializerNamespaces();
            ns.Add("foo", Amount.CoreNamespace);
            ser.Serialize(Console.Out, data, ns);
        }
    }
    

    Output:

    <ArrayOfSecurityHolding xmlns:foo="http://core.test.com/" xmlns="http://personaltrading.test.com/">
      <SecurityHolding>
        <foo:Amount>
          <foo:Amount>1.05</foo:Amount>
          <foo:CurrencyCode>USD</foo:CurrencyCode>
        </foo:Amount>
        <BrokerageId>0</BrokerageId>
        <RecordId>3681</RecordId>
      </SecurityHolding>
    </ArrayOfSecurityHolding>