【问题标题】:XML changes after Serialization序列化后的 XML 更改
【发布时间】:2017-08-14 16:45:45
【问题描述】:

我注意到我的 xml 在序列化后发生了变化。例如
* Message 元素开头的 ns 消失
* xmlns:ns 属性变为xmlns
* Message 元素中添加了新属性 - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"
* Header 元素中的新属性 - xmlns

如何保持xml的原始形式并防止这些属性被添加?

下面是原始 XML 的样子:

<?xml version="1.0" encoding="UTF-8"?>
<ns:Message xmlns:ns="http://example.com">
  <Header version="1.0">
    <Sender>3015207400109</Sender>
    <Receiver>8711200999903</Receiver>
    <MessageID>000D2613F64AC021ED783C084735EC78E53</MessageID>
    <CreationDateTime>2017-03-21T08:00:47Z</CreationDateTime>
  </Header>
</ns:Message>

这是序列化后的xml:

<?xml version="1.0" encoding="UTF-8"?>
<Message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com">
  <Header version="1.0" xmlns="">
    <Sender>3015207400109</Sender>
    <Receiver>8711200999903</Receiver>
    <MessageID>000D2613F64AC021ED783C084735EC78E53</MessageID>
    <CreationDateTime>2017-03-21T08:00:47Z</CreationDateTime>
  </Header>
</Message>

下面的代码是代表Message xml 的(生成的)类。

[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://example.com")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://example.com", IsNullable = false)]
public partial class Message
{

    private Header headerField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace = "")]
    public Header Header
    {
        get
        {
            return this.headerField;
        }
        set
        {
            this.headerField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class Header
{

    private ulong senderField;

    private ulong receiverField;

    private string messageIDField;

    private System.DateTime creationDateTimeField;

    private decimal versionField;

    /// <remarks/>
    public ulong Sender
    {
        get
        {
            return this.senderField;
        }
        set
        {
            this.senderField = value;
        }
    }

    /// <remarks/>
    public ulong Receiver
    {
        get
        {
            return this.receiverField;
        }
        set
        {
            this.receiverField = value;
        }
    }

    /// <remarks/>
    public string MessageID
    {
        get
        {
            return this.messageIDField;
        }
        set
        {
            this.messageIDField = value;
        }
    }

    /// <remarks/>
    public System.DateTime CreationDateTime
    {
        get
        {
            return this.creationDateTimeField;
        }
        set
        {
            this.creationDateTimeField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public decimal version
    {
        get
        {
            return this.versionField;
        }
        set
        {
            this.versionField = value;
        }
    }
}

【问题讨论】:

  • 两个 XML 文档在语义上是相同的。差异是否会给您带来一些问题?如果有,是什么?

标签: c# xml serialization


【解决方案1】:

您显示的两个 XML 文件在语义上是相同的。因此,我建议不要担心 XmlSerializer 插入 XML 标准命名空间或选择与原始文件中使用的不同的前缀方案这一事实。

如果出于某种原因,您必须抑制标准命名空间的输出并且必须保留原始文件的前缀方案,那么您可以这样做。

首先,要在根级别省略 xsixsd 命名空间,请按照 Omitting all xsi and xsd namespaces when serializing an object in .NET? 中的说明进行操作:

var s = new XmlSerializer(objectToSerialize.GetType());
var  ns = new XmlSerializerNamespaces();
ns.Add("","");
s.Serialize(xmlWriter, objectToSerialize, ns);

接下来,为了保持 xml 的原始形式,您必须首先以某种方式捕获在读取文件时遇到的实际 XML 命名空间和前缀,并将它们保存在 Message 类中以供重复使用之后。幸运的是 XmlSerializer 确实支持这一点:您可以将 XmlSerializerNamespaces 值的公共属性或字段添加到 Message 并用 [XmlNamespaceDeclarations] 标记它。该成员现在将捕获反序列化期间遇到的命名空间,并在序列化期间将这些命名空间添加回来。

把这两个想法放在一起,你可以修改你的Message类型如下:

public partial class Message
{
    [XmlNamespaceDeclarations]
    public XmlSerializerNamespaces XmlFileNamespaces { get; set; }

    /// <summary>
    /// returns a XmlSerializerNamespaces to use when serializing a Message as the root XML object.
    /// If Message was previously deserialized from XML, the actual namespaces observed will be returned.
    /// Otherwise, a default will be returned that suppresses output of the xmlns:xsi and xmlns:xsd namespace attributes.
    /// </summary>
    [XmlIgnore]
    public XmlSerializerNamespaces XmlRootNamespaces
    {
        get
        {
            if (XmlFileNamespaces != null)
                return XmlFileNamespaces;
            var xmlNamespaces = new XmlSerializerNamespaces();
            xmlNamespaces.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
            // xmlNamespaces.Add("ns", "http://example.com"); // Or, if you prefer, add this namespace as well as disabling xmlns:xsi and xmlns:xsd.
            return xmlNamespaces;
        }
    }
}

并从 XML 序列化到 XML,如下所示:

var message = xml.LoadFromXml<Message>();

var reserializedXml = message.GetXml(message.XmlRootNamespaces);

使用以下扩展方法:

public static class XmlSerializationHelper
{
    public static T LoadFromXml<T>(this string xmlString)
    {
        using (StringReader reader = new StringReader(xmlString))
        {
            return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
        }
    }

    public static string GetXml<T>(this T obj, XmlSerializerNamespaces ns)
    {
        using (var textWriter = new Utf8StringWriter())
        {
            var settings = new XmlWriterSettings() { Indent = true }; // For cosmetic purposes.
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                new XmlSerializer(obj.GetType()).Serialize(xmlWriter, obj, ns);
            return textWriter.ToString();
        }
    }
}

// http://stackoverflow.com/questions/3862063/serializing-an-object-as-utf-8-xml-in-net
public class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding
    {
        get { return Encoding.UTF8; }
    }
}

原型fiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 2011-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    相关资源
    最近更新 更多