Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

c# - XML Serialization Namespaces

I have an issue with the Namespaces that my code is producing. What I'd Like is the XML below:

<?xml version="1.0" encoding="utf-8"?>
<ClassToSerialize Type="Customer" Name="Some Name" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.123.org/namespace C:SchemaClassToSerialize.xsd" 
xmlns:Test="http://www.Test.org/" xmlns="http://www.nrf-arts.org/namespace">
  <Address>
    <Line1>Addr1</Line1>
    <Line2>Addr2</Line2>
  </Address>
</ClassToSerialize>

What I'm getting is this XML:

<?xml version="1.0" encoding="utf-8"?>
<ClassToSerialize xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:schemaLocation="http://www.123.org/namespace C:SchemaClassToSerialize.xsd"
 xmlns:Test="http://www.Test.org/" xmlns:xmlns="http://www.nrf-arts.org/namespace" Type="Customer" Name="Some Name">
  <Address>
    <Line1>Addr1</Line1>
    <Line2>Addr2</Line2>
  </Address>
</ClassToSerialize>

Main differences are:

1. xmlns:schemaLocation= needs to be xsi:schemaLocation=
2. xmlns:xmlns= needs to be xmlns=
3. Attributes Order, I would prefer the Attributes to be presented before the namespace attributes (This is not a big Issue, just nice to have)

Currently what I am doing is to replace the values in the serialized string in 1 & 2 above with the values I want, a hack that works but i suspect there is a way to modify the namespace code to do this at that point?

Here is the code I am using, how can i change GetNameSpace() to do what I need in points 1 & 2, also can i re-order the attributes?:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ClassToSerialize myInstance = new ClassToSerialize();
        myInstance.Type = "Customer";
        myInstance.Name = "Some Name";
        myInstance.AddressField = new Address("Addr1", "Addr2");

        String sString = SerializeObject<ClassToSerialize>(myInstance, GetNameSpace());

        //Hack to achieve what I want from namespaces
        sString = sString.Replace("xmlns:schemaLocation=", "xsi:schemaLocation=");
        sString = sString.Replace("xmlns:xmlns=", "xmlns=");
    }

    private XmlSerializerNamespaces GetNameSpace()
    {
        XmlSerializerNamespaces xsNS = new XmlSerializerNamespaces();

        xsNS.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        xsNS.Add("xmlns", "http://www.nrf-arts.org/namespace");
        xsNS.Add("schemaLocation", "http://www.123.org/namespace C:\Schema\ClassToSerialize.xsd");
        xsNS.Add("Test", "http://www.Test.org/");

        return xsNS;
    }

    public static string SerializeObject<X>(X toSerialize, XmlSerializerNamespaces xmlNameSpace)
    {
        string strRetVal = "";
        try
        {
            XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
            StringWriter textWriter = new StringWriter();

            using (StringWriter writer = new Utf8StringWriter())
            {
                xmlSerializer.Serialize(writer, toSerialize, xmlNameSpace);
                strRetVal = writer.ToString();
            }
        }
        catch (Exception ex)
        {
            string strError = ex.ToString();
        }

        return strRetVal;
    }
}

public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding
    {
        get { return Encoding.UTF8; }
    }
}

    public class ClassToSerialize
{
    [XmlAttribute()]
    public string Type { get; set; }

    [XmlAttribute()]
    public string Name { get; set; }

    [XmlElement("Address")]
    public Address AddressField { get; set; }
}

public class Address
{
    [XmlElement, DefaultValue("")]
    public string Line1 { get; set; }

    [XmlElement, DefaultValue("")]
    public string Line2 { get; set; }

    public Address()
    {

    }

    public Address(string L1, string L2)
    {
        Line1 = L1;
        Line2 = L2;
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
  1. You can add xsi:schemaLocation by adding a synthetic property along the lines of the answer in How to add xsi schemalocation to root c # object XmlSerializer -- but use a property instead of a field. If you use a field you will actually add to the footprint of your class in memory.

  2. To define a default namespace xmlns="http://www.nrf-arts.org/namespace", you can apply [XmlRoot("ClassToSerialize", Namespace="http://www.nrf-arts.org/namespace")] to your ClassToSerialize or allocate an XmlRootAttribute override and pass it to the XmlSerializer constructor. Be sure to cache the serializer if you do the latter.

  3. Other than implementing IXmlSerializable, which is somewhat burdensome, I don't know if it's possible to control the attribute order with XmlSerializer. However, the XML specification states "the order of attribute specifications in a start-tag or empty-element tag is not significant", so I recommend not worrying about it.

Thus the following should do the trick. Note I moved your GetNameSpace() inside ClassToSerialize and renamed it GetAdditionalNamespaces():

[XmlRoot("ClassToSerialize", Namespace="http://www.nrf-arts.org/namespace")]
public class ClassToSerialize
{
    public static XmlSerializerNamespaces GetAdditionalNamespaces()
    {
        XmlSerializerNamespaces xsNS = new XmlSerializerNamespaces();

        xsNS.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        xsNS.Add("Test", "http://www.Test.org/");

        return xsNS;
    }

    [XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public string XSDSchemaLocation
    {
        get
        {
            return "http://www.123.org/namespace C:\Schema\ClassToSerialize.xsd";
        }
        set
        {
            // Do nothing - fake property.
        }
    }

    [XmlAttribute()]
    public string Type { get; set; }

    [XmlAttribute()]
    public string Name { get; set; }

    [XmlElement("Address")]
    public Address AddressField { get; set; }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...