为啥 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;
// ...
【讨论】:
谢谢。但对我不起作用。按照建议将属性添加到类及其属性后,我得到了每个新元素,如下所示:<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">
它是有效的,但是所有这些命名空间信息已经在文档的根目录中。所以我希望找到一种方法,只添加一个带有 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”属性,我该如何阻止这种行为?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 PoolingClientConnectionManager 中不推荐使用所有方法?