【问题标题】:Serializing WITHOUT xmlns没有 xmlns 的序列化
【发布时间】:2010-06-22 15:10:17
【问题描述】:

我有几个扩展方法来处理我的类的序列化,因为这可能是一个耗时的过程,所以它们为每个类创建一次,并通过这个方法分发。

public static XmlSerializer GetSerializerFor(Type typeOfT)
{
    if (!serializers.ContainsKey(typeOfT))
    {
        var xmlAttributes = new XmlAttributes();
        var xmlAttributeOverrides = new XmlAttributeOverrides();

        System.Diagnostics.Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));

        xmlAttributes.Xmlns = false;
        xmlAttributeOverrides.Add(typeOfT, xmlAttributes);

        var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
        serializers.Add(typeOfT, newSerializer);
    }

    return serializers[typeOfT];
}

这是由扩展方法.Serialize()调用的

public static XElement Serialize(this object source)
{
    try
    {
        var serializer = XmlSerializerFactory.GetSerializerFor(source.GetType());
        var xdoc = new XDocument();
        using (var writer = xdoc.CreateWriter())
        {
            serializer.Serialize(writer, source, new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") }));
        }

        return (xdoc.Document != null) ? xdoc.Document.Root : new XElement("Error", "Document Missing");
    }
    catch (Exception x)
    {
        return new XElement("Error", x.ToString());
    }
}

不幸的是,在对自动生成的类进行序列化时,它们应用了 XmlTypeAttribute(Namespace="http://tempuri.org/") 属性。

这会导致非自动生成的对应对象的反序列化失败。

我需要序列化程序完全忽略并且不应用命名空间,但我在第一块代码中编写的内容似乎并没有删除它,我仍然以这样的 xml 结束

<Note>
  <ID xmlns="http://tempuri.org/">12</ID>
  <Author xmlns="http://tempuri.org/">
    <ID>1234</ID>
    <Type>Associate</Type>
    <IsAvailable>false</IsAvailable>
  </Author>
  <Created xmlns="http://tempuri.org/">2010-06-22T09:38:01.5024351-05:00</Created>
  <Text xmlns="http://tempuri.org/">This is an update</Text>
</Note>

而不是相同,减去xmlns="http://tempuri.org/" 属性。

请帮忙,谢谢,这快把我逼疯了!

编辑:

我知道问题所在,只是不知道如何解决。

我的课,不仅仅是简单的类型。

它包含具有其他类类型的属性。它们也是使用 XmlTypeAttribute(Namespace = "http://tempuri.org/") 属性自动生成的。所以发生的事情是,当序列化发生时,它序列化我的类的属性,它们没有经过我的自定义序列化,因此,应用了属性并且没有被覆盖。

现在我只需要弄清楚如何跳那个箍。有什么想法吗?

编辑 2:

以下可以在没有 xmlns 的情况下进行序列化...但是我在反序列化端遇到了问题,只是不确定它是否相关

public static XmlSerializer GetSerializerFor(Type typeOfT)
{
    if (!serializers.ContainsKey(typeOfT))
    {
        var xmlAttributes = new XmlAttributes();
        var xmlAttributeOverrides = new XmlAttributeOverrides();

        System.Diagnostics.Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));

        xmlAttributes.XmlType = new XmlTypeAttribute
        {
            Namespace = ""
        };

        xmlAttributes.Xmlns = false;

        var types = new List<Type> {typeOfT, typeOfT.BaseType};

        foreach (var property in typeOfT.GetProperties())
        {
            types.Add(property.PropertyType);
        }

        types.RemoveAll(t => t.ToString().StartsWith("System."));

        foreach (var type in types)
        {
            xmlAttributeOverrides.Add(type, xmlAttributes);
        }

        var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides);
        //var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, extraTypes.ToArray(), new XmlRootAttribute(), string.Empty);
        //var newSerializer = new XmlSerializer(typeOfT, string.Empty);

        serializers.Add(typeOfT, newSerializer);
    }

    return serializers[typeOfT];
}

编辑3: 最终使用来自的解决方案 How to remove all namespaces from XML with C#?

public static XElement RemoveAllNamespaces(this XElement source)
{
    return !source.HasElements
               ? new XElement(source.Name.LocalName)
                     {
                         Value = source.Value
                     }
               : new XElement(source.Name.LocalName, source.Elements().Select(el => RemoveAllNamespaces(el)));
}

【问题讨论】:

  • 你的最后一个解决方案应该被命名为RemoveAllAttributes

标签: c# xml-serialization namespaces


【解决方案1】:

一个可行的解决方案,记录在案!

var ns = new XmlSerializerNamespaces();
ns.Add("", ""); 
var serializer = new XmlSerializer(yourType); 
serializer.Serialize(xmlTextWriter, someObject, ns);

【讨论】:

  • 当然是更好的解决方案。像魅力一样工作!
  • 作为记录,这将删除 xsixsd,但如果您有带有命名空间的 XmlTypeAttributes,它将添加一个新的 xmlns:prefix=&lt;namespace&gt; 并将前缀添加到所有标签在您的课程中指定。
  • 这对我来说真的很完美,在尝试了这么多不同的事情之后,这些事情都没有副作用。非常感谢。
  • 得说,不。我在每个元素上都得到xmlns=""
  • 适用于 .NET Core。使用 System.Xml;使用 System.Xml.Serialization;
【解决方案2】:

没问题 - 只需将一个空字符串作为默认命名空间传递给 XML 序列化程序:

XmlSerializer newSerializer = 
   new XmlSerializer(typeOfT, "");

不幸的是,如果您确实需要定义 XmlAttributeOverrides 和默认命名空间,则没有简单的构造函数重载 - 所以您可以跳过 XmlAttributeOverrides 并使用我提到的构造函数,或者您需要使用定义的构造函数所有可能的参数(包括 XmlAttributeOverrides 和默认 XML 命名空间 - 等等)。

【讨论】:

  • 这实际上是我之前所拥有的,它不起作用,它仍在使用类上 XmlTypeAttribute 的值。我只是尝试了以下方法,但它也没有工作var newSerializer = new XmlSerializer(typeOfT, xmlAttributeOverrides, new Type[]{}, new XmlRootAttribute(), "");
  • 我知道问题所在......只是不是解决方案。请参阅我对原始问题所做的修改。
  • 没有用。其实不是答案。 VihidN 的回答对我有用!
【解决方案3】:
 public static byte[] SerializeByteByType(object objectToSerialize, Type type)
    {
        XmlWriterSettings xmlSetting = new XmlWriterSettings()
        {
            NewLineOnAttributes = false,
            OmitXmlDeclaration = true,
            Indent = false,
            NewLineHandling = NewLineHandling.None,
            Encoding = Encoding.UTF8,
            NamespaceHandling = NamespaceHandling.OmitDuplicates
        };

        using (MemoryStream stm = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(stm, xmlSetting))
            {
                var xmlAttributes = new XmlAttributes();
                var xmlAttributeOverrides = new XmlAttributeOverrides();

                xmlAttributes.Xmlns = false;
                xmlAttributes.XmlType = new XmlTypeAttribute() { Namespace = "" };
                xmlAttributeOverrides.Add(type, xmlAttributes);

                XmlSerializer serializer = new XmlSerializer(type, xmlAttributeOverrides);
                //Use the following to serialize without namespaces
                XmlSerializerNamespaces xmlSrzNamespace = new XmlSerializerNamespaces();
                xmlSrzNamespace.Add("", "");

                serializer.Serialize(writer, objectToSerialize, xmlSrzNamespace);
                stm.Flush();
                stm.Position = 0;
            }

            return stm.ToArray();
        }
    }         

【讨论】:

  • 代替“xmlAttributeOverrides.Add(type, xmlAttributes);”必须是:“var types = type.Assembly.GetTypes().Where(t => string.Equals(t.Namespace, currentType.Namespace, StringComparison.Ordinal)); var xmlAttributeOverrides = new XmlAttributeOverrides(); foreach (var t在类型中) xmlAttributeOverrides.Add(t, xmlAttributes);"
【解决方案4】:
    public static string SerializeToXml(object obj)
    {
        UTF8Encoding encoding = new UTF8Encoding(false);

        var xmlAttributes = new XmlAttributes();
        xmlAttributes.Xmlns = false;
        xmlAttributes.XmlType = new XmlTypeAttribute() { Namespace = "" };

        var xmlAttributeOverrides = new XmlAttributeOverrides();

        var types = obj.GetType().Assembly.GetTypes().Where(t => string.Equals(t.Namespace, obj.GetType().Namespace, StringComparison.Ordinal));
        foreach (var t in types) xmlAttributeOverrides.Add(t, xmlAttributes);

        XmlSerializer sr = new XmlSerializer(obj.GetType(), xmlAttributeOverrides);

        MemoryStream memoryStream = new MemoryStream();
        StreamWriter writer = new StreamWriter(memoryStream, encoding);

        XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
        namespaces.Add(string.Empty, string.Empty);

        // get the stream from the writer
        memoryStream = writer.BaseStream as MemoryStream;

        sr.Serialize(writer, obj, namespaces);

        // apply encoding to the stream 
        return (encoding.GetString(memoryStream.ToArray()).Trim());
    }

它甚至适用于包含嵌套对象的复杂对象 感谢 user3444796 和 Mentor

【讨论】:

    【解决方案5】:

    工作解决方案(没有空的 xmlns 属性):

    var ns = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
    XmlSerializer serializer = new XmlSerializer(typeof(XmlInfo));
    XmlDocument doc = new XmlDocument();
    using (var ms = new MemoryStream()) {
        serializer.Serialize(ms, this, ns);
        ms.Position = 0;
        doc.Load(ms);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-06
      • 2018-06-28
      • 2012-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-28
      • 1970-01-01
      相关资源
      最近更新 更多