为啥 XContainer.Add 方法无论如何都会向添加的元素添加“xmlns”属性,我该如何阻止这种行为?

Posted

技术标签:

【中文标题】为啥 XContainer.Add 方法无论如何都会向添加的元素添加“xmlns”属性,我该如何阻止这种行为?【英文标题】:Why the XContainer.Add method adds an "xmlns" attribute to the added element no matter what, how can I stop this behaviour?为什么 XContainer.Add 方法无论如何都会向添加的元素添加“xmlns”属性,我该如何阻止这种行为? 【发布时间】:2021-12-11 02:52:30 【问题描述】:

我正在使用一种将新的 Person 对象附加到现有 Xml 文件的 WebMethod。我想使用 XmlSerializer 来做到这一点,所以我不必手动进行序列化。到目前为止,我的对象按照我想要的方式进行了序列化。因此,Person 对象被传递给对其进行序列化的方法,并返回带有对象信息的 XElement。问题是当我将此 XElement 添加到 XDocument 的根目录时,会添加一个空的 xmlns 属性。到目前为止,我尝试添加空 XmlSerializerNamespaces,我尝试使用 Attribute-Remove 手动删除它,但我什至无法获取属性,我得到的是我实际需要的 Id 属性。有没有办法在没有这种行为的情况下完成将 XElement 添加到 XDocument ?任何光线将不胜感激。谢谢。

这是我的 xml,最后一个人是使用 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>

WebMethod 是这样的:

[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";
        

这是我用来序列化 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);
        

Debug.Writeline 打印这个:

<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>

但是当我打开文件时的最终结果是 Person with Id 和 xmlns="" 属性与架构混淆。

【问题讨论】:

【参考方案1】:

People 及其后代元素位于https://www.some-random_thing/SuperApp 命名空间中(如xmlns 属性所示)。添加新元素时,必须将它们添加到同一个命名空间中。

您需要将适当的属性应用于层次结构中的类。

[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; 
    // ...

【讨论】:

谢谢。但对我不起作用。按照建议将属性添加到类及其属性后,我得到了每个新元素,如下所示:&lt;Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Id="9" xmlns="https://www.some-random-thing/SuperApp"&gt; 它是有效的,但是所有这些命名空间信息已经在文档的根目录中。所以我希望找到一种方法,只添加一个带有 ID 的普通 Person,没有其他属性,就像我的示例中的第一个 Person 元素一样。【参考方案2】:

经过多次尝试后,我通过将 SaveOptions.OmitDuplicateNamespaces 参数添加到 XDocument.Save 方法来解决它。而且我在文档的根元素中添加了一个 Schema 声明,因此它停止向每个新元素添加额外的属性。我正在跳一段欢乐的舞蹈。有用!!! InsertPerson 方法:

[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";
        

Person转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);
        

根元素:

<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">

最后是 Person 类:

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; 
    

【讨论】:

以上是关于为啥 XContainer.Add 方法无论如何都会向添加的元素添加“xmlns”属性,我该如何阻止这种行为?的主要内容,如果未能解决你的问题,请参考以下文章

为啥要池化无状态会话 bean?

为啥 scrollTo() 方法不适用于 iframe?

为啥 PoolingClientConnectionManager 中不推荐使用所有方法?

为啥@Transactional 会自动保存到数据库

servlet中为啥doget要调用dopost?默认调用哪个?默认都调用?

为啥我的子类没有继承父类的所有方法?