XML属性没有获取名称空间前缀

我需要在序列化期间生成以下XML :(片段)

 2013-12-18 00:15:28  

有问题的类看起来像这样:

 public class IncidentEvent { public string EventDate { get; set; } public string EventTime { get; set; } [XmlAttribute("EventTypeText", Namespace = "http://foo")] public string EventTypeText { get; set; } } 

似乎序列化程序注意到命名空间已经在xmlns:在根目录中声明,并且忽略了我的属性。 我也尝试了以下内容:

 [XmlRoot(Namespace = "http://foo")] public class IncidentEvent { public string EventDate { get; set; } public string EventTime { get; set; } private XmlSerializerNamespaces _Xmlns; [XmlNamespaceDeclarations] public XmlSerializerNamespaces Xmlns { get { if (_Xmlns == null) { _Xmlns = new XmlSerializerNamespaces(); _Xmlns.Add("ett", "http://foo"); } return _Xmlns; } set { _Xmlns = value; } } [XmlAttribute("EventTypeText", Namespace = "http://foo")] public string EventTypeText { get; set; } } 

这导致以下XML:

   2013-12-18 00:15:28  

这不是我想要的。 元素不应该是前缀,属性应该是。 需要什么才能让序列化程序了解我想要的内容?

我做了一些研究可能会有以下答案帮助

对于具有名称空间前缀的属性,您必须指定不同于您指定的名称http://foo名称空间标记。 以下代码有望解决您的问题。 在代码中,我删除了元素的命名空间,并仅为属性添加。

 public class IncidentEvent { public string EventDate { get; set; } public string EventTime { get; set; } [XmlAttribute("EventTypeText", Namespace = "http://foo")] public string EventTypeText { get; set; } } class Program { static void Main(string[] args) { IncidentEvent xmlObj = new IncidentEvent() { EventDate = "2012.12.01", EventTime = "1:00:00", EventTypeText = "Beginining" }; XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("ett", "http://foo"); XmlSerializer serializer = new XmlSerializer(typeof(IncidentEvent)); serializer.Serialize(Console.OpenStandardOutput(), xmlObj, ns); Console.WriteLine(); } } 

http://www.w3.org/TR/2009/REC-xml-names-20091208/#defaulting

这可能是XmlSerializer的错误。

正如您所注意到的,即使明确设置了XmlAttributeAttribute.Namespace ,该属性也不会在某些情况下作为前缀。 从测试开始,这似乎发生在属性名称空间恰好与当前正在编写的元素的名称空间相同时。

例如:

 [XmlRoot(Namespace = "http://foo")] public class IncidentEvent { [XmlAttribute("EventTypeText", Namespace = "http://foo")] public string EventTypeText { get; set; } } 

序列化为以下XML:

  

由于该属性没有前缀,因此它实际上不在任何名称空间中,如XML标准中所述 : 未加前缀的属性名称的名称空间名称始终没有值

但是,以下内容:

 [XmlRoot(Namespace = "http://foo")] public class IncidentEvent { [XmlAttribute("EventTypeText", Namespace = "http://bar")] public string EventTypeText { get; set; } } 

使用正确的前缀属性进行序列化:

  

解决方法是显式设置[XmlAttribute(Form = XmlSchemaForm.Qualified)] 。 从而:

 [XmlRoot(Namespace = "http://foo")] public class IncidentEvent { [XmlAttribute("EventTypeText", Namespace = "http://foo", Form = XmlSchemaForm.Qualified)] public string EventTypeText { get; set; } } 

序列化为

  

按要求。

命名空间用于区分具有相同名称的两个XML元素。 由于不同的XML元素可以具有相同的属性名称但含义不同。 因此,没有为属性使用名称空间标记的优点,因为XML属性仅被视为“元素名称空间”的一部分。 在你的例子中

  2013-12-18 00:15:28  

EventTypeText是命名空间ett的一部分:IncidentEvent请参阅http://www.w3.org/TR/REC-xml-names/了解XML命名空间

我会给出KKD的答案,但我发现了另一个仍会导致问题的情景。 显然,如果要序列化的对象是另一个对象的子对象,如果父对象的名称空间与子对象的名称空间相同,则序列化程序假定您不需要显式声明子对象的名称空间。

  public class IncidentEvent : IXmlSerializable { public string EventDate { get; set; } public string EventTime { get; set; } public string EventTypeText { get; set; } public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { return null; } public void WriteXml(System.Xml.XmlWriter writer) { writer.WriteAttributeString("ex", "EventTypeText", "http://foo", EventTypeText); } } 

通过实现IXmlSerializable,我可以完全按照我需要的方式手动写出元素和属性。 由于这是一个单向导出,我不需要实现除WriteXml方法之外的任何东西。

我仍然不确定这是不是最好的方式,但它目前是有效的。