我需要在序列化期间生成以下XML: (片段)
<IncidentEvent a:EventTypeText="Beginning" xmlns:a="http://foo">
<EventDate>2013-12-18</EventDate>
<EventTime>00:15:28</EventTime>
</IncidentEvent>
有问题的课程如下:
public class IncidentEvent
{
public string EventDate { get; set; }
public string EventTime { get; set; }
[XmlAttribute("EventTypeText", Namespace = "http://foo")]
public string EventTypeText { get; set; }
}
似乎序列化程序注意到名称空间已经在xmlns:root中声明,并且忽略了我的属性。我也尝试了以下内容:
[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:
<ett:IncidentEvent EventTypeText="Beginning" xmlns:ett="http://foo">
<ett:EventDate>2013-12-18</ett:EventDate>
<ett:EventTime>00:15:28</ett:EventTime>
</ett:IncidentEvent>
这不是我想要的。元素不应该是前缀,属性应该是。需要什么才能让序列化程序了解我想要的内容?
答案 0 :(得分:5)
这可能是XmlSerializer
中的错误。
正如您所注意到的,即使明确设置XmlAttributeAttribute.Namespace
,该属性也不会在某些情况下作为前缀。从测试开始,当属性名称空间恰好与当前正在编写的元素的名称空间相同时,就会发生这种情况。
例如:
[XmlRoot(Namespace = "http://foo")]
public class IncidentEvent
{
[XmlAttribute("EventTypeText", Namespace = "http://foo")]
public string EventTypeText { get; set; }
}
序列化为以下XML:
<q1:IncidentEvent EventTypeText="an attribute" xmlns:q1="http://foo" />
由于该属性没有前缀,它实际上不在任何名称空间中,如in the XML standard所述:未加前缀的属性名称的名称空间名称始终没有值。
但是,以下内容:
[XmlRoot(Namespace = "http://foo")]
public class IncidentEvent
{
[XmlAttribute("EventTypeText", Namespace = "http://bar")]
public string EventTypeText { get; set; }
}
使用正确加前缀的属性进行序列化:
<q1:IncidentEvent p1:EventTypeText="an attribute" xmlns:p1="http://bar" xmlns:q1="http://foo" />
解决方法是明确设置[XmlAttribute(Form = XmlSchemaForm.Qualified)]
。因此:
[XmlRoot(Namespace = "http://foo")]
public class IncidentEvent
{
[XmlAttribute("EventTypeText", Namespace = "http://foo", Form = XmlSchemaForm.Qualified)]
public string EventTypeText { get; set; }
}
序列化为
<q1:IncidentEvent q1:EventTypeText="an attribute" xmlns:q1="http://foo" />
根据需要。
答案 1 :(得分:1)
我做了一些研究可能会有以下答案帮助
对于具有名称空间前缀的属性,您必须指定除指定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
答案 2 :(得分:0)
命名空间用于区分具有相同名称的两个XML元素。由于不同的XML元素可以具有相同的属性名称但含义不同。因此,没有为属性使用名称空间标记的优点,因为XML属性仅被视为“元素名称空间”的一部分。 在你的例子中
<ett:IncidentEvent EventTypeText="Beginning" xmlns:ett="http://foo">
<ett:EventDate>2013-12-18</ett:EventDate>
<ett:EventTime>00:15:28</ett:EventTime>
</ett:IncidentEvent>
EventTypeText
是namespace ett:IncidentEvent的一部分
有关XML命名空间的详细信息,请参阅http://www.w3.org/TR/REC-xml-names/
答案 3 :(得分:0)
我会给出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方法之外的任何东西。
我仍然不确定这是否是最佳方式,但它现在有效。