Home > Mobile >  Why the XContainer.Add method adds an "xmlns" attribute to the added element no matter wha
Why the XContainer.Add method adds an "xmlns" attribute to the added element no matter wha

Time:10-26

I am working with a WebMethod that appends a new Person object to an existing Xml file. I want to do this using the XmlSerializer so I don't have to do the serialization manually. So far, my object gets serialized the way I want it. So the Person object is passed to a method that serialize it and returns an XElement with the object's info. The problem is that when I add this XElement to the Root of my XDocument, an empty xmlns attribute gets added. So far I tried adding empty XmlSerializerNamespaces, I tried to remove it manually with Attribute-Remove but I cannot even get the attribute, what I get is the Id attribute that I actually need. Is there a way to accomplish adding an XElement to an XDocument without this behavior? Any light would be greatly appreciated. Thanks.

Here is my xml, the last person was added using the WebMethod:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="People-template.xslt" type="text/xsl"?>
<People xmlns="https://www.some-random_thing/SuperApp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://www.some-random_thing/SuperApp People-schema.xsd">
  <Person Id="1">
    <Name>John Smith</Name>
    <Phone>0299882211</Phone>
    <Department>1</Department>
    <Address>
      <Street>1 Code Lane</Street>
      <City>Javaville</City>
      <State>CA</State>
      <Zip>01003</Zip>
      <Country>USA</Country>
    </Address>
  </Person>
<Person Id="2" xmlns="">
    <Name>Sue White</Name>
    <Phone>0388992255</Phone>
    <Department>2</Department>
    <Address>
      <Street>16 Bit Way</Street>
      <City>Byte Cove</City>
      <State>QLD</State>
      <Zip>1101</Zip>
      <Country>Australia</Country>
    </Address>

The WebMethod goes like:

[WebMethod]
        public string InsertPerson(string name, string phone, int department, string street, string city, string state, int zip, string country)
        {
            Person newPerson = new Person()
            {
                Id = PersonXmlHelper.GetNextPersonId(),
                Name = name,
                Phone = phone,
                Department = department,
                Address = new Address()
                {
                    Street = street,
                    City = city,
                    State = state,
                    Zip = zip,
                    Country = country
                }
            };
            XElement personEl = PersonXmlHelper.ToXElement<Person>(newPerson);

            doc.Root.Add(personEl);
            doc.Save(filePath);
            return "New person was successfully added";
        }

And this is the method I am using to serialize Person:

 public static XElement ToXElement<T>(this object obj)
        {
            var serializer = new XmlSerializer(typeof(T));
            XmlSerializerNamespaces xns = new XmlSerializerNamespaces();
            xns.Add("", "");
            XmlWriterSettings settings = new XmlWriterSettings() 
            { 
                Indent = true, 
                NamespaceHandling = NamespaceHandling.OmitDuplicates, 
                OmitXmlDeclaration = true 
            };

            var sw = new StringWriter();
            var xmlWriter = XmlWriter.Create(sw, settings);

            serializer.Serialize(xmlWriter, obj, xns);
            string xml = sw.ToString();

            Debug.WriteLine(XElement.Parse(xml));
            return XElement.Parse(xml);
        }

The Debug.Writeline prints this:

<Person Id="7">
  <Name>Mary Jane</Name>
  <Phone>0422888990</Phone>
  <Department>2</Department>
  <Address>
    <Street>99 Integeration street</Street>
    <City>Floating bay</City>
    <State>SA</State>
    <Zip>1111</Zip>
    <Country>Australia</Country>
  </Address>
</Person>

But the final result when I open the file is the Person with Id and the xmlns="" attribute that messes up with the schema.

CodePudding user response:

People and its descendant elements are in the https://www.some-random_thing/SuperApp namespace (as indicated by the xmlns attribute). When you add your new elements, you must add them in the same namespace.

You need to apply the appropriate attributes to your classes in the hierarchy.

[XmlRoot("Person", Namespace="https://www.some-random_thing/SuperApp")]
public class Person
{
    [XmlElement("Name", Namespace="https://www.some-random_thing/SuperApp")]
    public string Name { get; set; }
    // ...
}

CodePudding user response:

After many other attempts I solved it by adding SaveOptions.OmitDuplicateNamespaces argument to the XDocument.Save method. And also I add a Schema declaration in the root element of the document so it stopped adding the extra attribute to every new element. I am doing a little dance of joy. It works!!! The InsertPerson method:

[WebMethod]
        public string InsertPerson(string name, string phone, int department, string street, string city, string state, int zip, string country)
        {
            Person newPerson = new Person()
            {
                Id = PersonXmlHelper.GetNextPersonId(),
                Name = name,
                Phone = phone,
                Department = department,
                Address = new Address()
                {
                    Street = street,
                    City = city,
                    State = state,
                    Zip = zip,
                    Country = country
                }
            };
            XElement personEl = PersonXmlHelper.ToXElement<Person>(newPerson);
            Debug.WriteLine(personEl);

            doc.Root.Add(personEl);
            doc.Save(filePath, SaveOptions.OmitDuplicateNamespaces);
            return "New person was successfully added";
        }

The method to convert Person to XElement:

public static XElement ToXElement<T>(this object obj)
        {
            var serializer = new XmlSerializer(typeof(T), ns.NamespaceName);
            XmlWriterSettings settings = new XmlWriterSettings() 
            { 
                OmitXmlDeclaration = true 
            };

            var sw = new StringWriter();
            var xmlWriter = XmlWriter.Create(sw, settings);

            serializer.Serialize(xmlWriter, obj);
            string xml = sw.ToString();

            return XElement.Parse(xml);
        }

The root element :

<People xmlns="https://www.some-random_thing/SuperApp" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:schemaLocation="https://www.some-random_thing/SuperApp People-schema.xsd">

And finally the Person class:

public class Person
    {
        [XmlAttribute("Id")]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Phone { get; set; }
        public int Department { get; set; }
        public Address Address { get; set; }
    }
  • Related