我遇到以下问题。每当我在C#类中使用默认的XML序列化时,.NET序列化引擎会自动添加名称空间xsi
和xsd
。但是,当通过IXmlSerializable
定义序列化时,不会添加名称空间。
示例:此代码:
class Program
{
static void Main(string[] args)
{
OutputSerialized(new Outer() { Inner = new Inner() });
OutputSerialized(new OuterCustom() { Inner = new Inner() });
}
static void OutputSerialized<T>(T t)
{
var sb = new StringBuilder();
using (var textwriter = new StringWriter(sb))
new XmlSerializer(typeof(T)).Serialize(textwriter, t);
Console.WriteLine(sb.ToString());
}
}
[Serializable] public class Inner { }
[Serializable] public class Outer { public Inner Inner { get; set; } }
public class OuterCustom : IXmlSerializable
{
public Inner Inner;
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteStartElement("Inner");
new XmlSerializer(typeof(Inner)).Serialize(writer, Inner);
writer.WriteEndElement();
}
public System.Xml.Schema.XmlSchema GetSchema() { return null; }
public void ReadXml(System.Xml.XmlReader reader) { /**/ }
}
产生以下输出:
<?xml version="1.0" encoding="utf-16"?>
<Outer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Inner />
</Outer>
<?xml version="1.0" encoding="utf-16"?>
<OuterCustom>
<Inner>
<Inner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
</Inner>
</OuterCustom>
您可以看到OuterCustom
的序列化表单缺少xsd
和xsi
名称空间。
如何让OuterCustom
的行为与Outer
相同?我在代码中遗漏了什么吗?我在自定义序列化中做错了吗?
关于如何摆脱额外的命名空间,这里有很多问题,但似乎没有人问过如何让他们回来。
答案 0 :(得分:1)
首先,对于兼容的XML解析器,所提到的XML版本之间没有区别。只要节点具有正确的名称空间关联,是否/ how / where定义名称空间前缀并不重要。
由于这个问题明确地涉及样式,在哪里放置名称空间声明,一个人自己调用什么是好的,什么不是。在这种特殊情况下,目标是避免重复的xmlns
属性并在树中将它们移到更高的位置。
只要在同一节点上不冲突,就可以在需要的地方编写xmlns属性。使用XmlWriter.WriteAttributeString方法添加它们:
writer.WriteAttributeString(
"xmlns", "prefix", null, "urn:mynamespace");
为避免重复声明 - 使用XmlWriter.LookupPrefix
检查是否已为给定命名空间定义了前缀确保xsd
和xsi
前缀(由Vlad)的示例代码:
const string xsiNamespace = System.Xml.Schema.XmlSchema.InstanceNamespace;
const string xsdNamespace = System.Xml.Schema.XmlSchema.Namespace;
public static void EnsureDefaultNamespaces(System.Xml.XmlWriter writer)
{
if (writer.LookupPrefix(xsiNamespace) == null)
writer.WriteAttributeString("xmlns", "xsi", null, xsiNamespace);
if (writer.LookupPrefix(xsdNamespace) == null)
writer.WriteAttributeString("xmlns", "xsd", null, xsdNamespace);
}
如果需要进行更多改变以实现漂亮的XML,那么替代方法是允许序列化完成,而不是处理XML以调整前缀定义(即规范化为所需的前缀,收集所有名称空间并在顶部定义所有名称)。可以用C#代码读取XML,甚至可以创建XSLT转换。