繁体   English   中英

使用自定义IXmlSerializable时缺少xsi和xsd命名空间

[英]xsi and xsd namespaces missing when using custom IXmlSerializable

我遇到以下问题。 每当我在C#类中使用默认XML序列化时,.NET序列化引擎都会自动添加名称空间xsixsd 但是,当通过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的序列化表单缺少xsdxsi命名空间。

如何使OuterCustom行为与Outer相同? 我在代码中缺少什么吗? 我自定义序列化做错了吗?

因此,关于如何摆脱其他名称空间 ,这里有很多问题,但是似乎没有人问到如何将其取回

首先-用于兼容XML解析器的XML版本之间没有区别。 只要节点具有正确的关联名称空间,定义名称空间前缀是否/如何/在何处定义都没有关系。

因为这个问题明确地与样式有关,将名称空间声明放在何处,所以可以自己调用什么是好的,什么不是。 在此特定情况下,目标是避免重复的xmlns属性,并将其在树中移至更高位置。

只要它们在同一节点上不冲突,就可以在任何需要的地方编写xmlns属性。 使用XmlWriter.WriteAttributeString方法添加它们:

writer.WriteAttributeString(
  "xmlns", "prefix", null, "urn:mynamespace");

为避免重复声明,请使用XmlWriter.LookupPrefix检查是否已为给定名称空间定义了前缀。

确保xsdxsi前缀的示例代码(通过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转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM