XML 属性未获取命名空间前缀
Posted
技术标签:
【中文标题】XML 属性未获取命名空间前缀【英文标题】:XML attribute not getting namespace prefix 【发布时间】:2021-12-14 00:41:24 【问题描述】:我需要在序列化过程中生成以下 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: 根中声明,并且忽略了我的属性。我还尝试了以下方法:
[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>
这不是我想要的。元素不应该是前缀,属性应该是。需要什么才能让序列化程序了解我想要什么?
【问题讨论】:
【参考方案1】:这可能是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" />
根据需要。
【讨论】:
【参考方案2】:我做了一些研究可能会得到以下答案的帮助
要使属性具有命名空间前缀,您必须指定与指定 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
【讨论】:
如果您需要将此对象序列化为另一个对象的子对象,这似乎会崩溃。当我在一种情况下对其进行测试时它运行良好,但我忘记了另一种情况。不过,很好的答案。【参考方案3】:命名空间旨在区分具有相同名称的两个 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
是命名空间 ett:IncidentEvent 的一部分
XML 命名空间请参考http://www.w3.org/TR/REC-xml-names/
【讨论】:
XML 需要针对我无法控制的 XSD 进行验证。我需要做的就是编写符合架构的 XML。我的第一个片段是手写的,但它确实有效。我只需要弄清楚如何让序列化程序做同样的事情。【参考方案4】:我将把答案归功于 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 方法之外我不需要实现任何东西。
我仍然不确定这是否是最好的方式,但它目前有效。
【讨论】:
以上是关于XML 属性未获取命名空间前缀的主要内容,如果未能解决你的问题,请参考以下文章
JAXB:为啥在生成的 xml 文档中未使用定义的命名空间前缀?