【问题标题】:How to serialize an object to XML without getting xmlns="..."?如何在不获取 xmlns="..." 的情况下将对象序列化为 XML?
【发布时间】:2010-09-20 12:18:24
【问题描述】:

有没有办法让我在 .NET 中序列化一个对象,而无需 XML 命名空间也自动序列化?似乎默认情况下 .NET 认为应该包含 XSI 和 XSD 命名空间,但我不希望它们在那里。

【问题讨论】:

    标签: .net xml-serialization xml-namespaces


    【解决方案1】:

    啊……没关系。提出问题后的搜索总是会产生答案。我正在序列化的对象是obj,并且已经被定义。将具有单个空命名空间的 XMLSerializerNamespace 添加到集合中就可以了。

    在 VB 中是这样的:

    Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
    Dim ns As New XmlSerializerNamespaces()
    ns.Add("", "")
    
    Dim settings As New XmlWriterSettings()
    settings.OmitXmlDeclaration = True
    
    Using ms As New MemoryStream(), _
        sw As XmlWriter = XmlWriter.Create(ms, settings), _
        sr As New StreamReader(ms)
        xs.Serialize(sw, obj, ns)
        ms.Position = 0
        Console.WriteLine(sr.ReadToEnd())
    End Using
    

    在 C# 中像这样:

    //Create our own namespaces for the output
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    
    //Add an empty namespace and empty value
    ns.Add("", "");
    
    //Create the serializer
    XmlSerializer slz = new XmlSerializer(someType);
    
    //Serialize the object with our own namespaces (notice the overload)
    slz.Serialize(myXmlTextWriter, someObject, ns);
    

    【讨论】:

    • 我在VB中试过了,xsi和xsd属性消失了,但是出现了xmlns:q12=、d3p1:type、xmlns:d3p1等属性。
    • 我尝试了 C# 版本,它删除了 xsi 和 xsd,但在所有 XML 标记名称中添加了 q1: 前缀,这是我不想要的。看起来 C# 示例不完整,引用了 myXmlTextWriter,我认为它需要以与 VB 示例相同的方式进行初始化。
    • @redtetrahedron 你找到摆脱q1 废话的方法了吗?
    • 参考答案stackoverflow.com/questions/31946240/…,如果q1添加为空白命名空间
    【解决方案2】:

    如果您想摆脱多余的xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema",但仍保留您自己的命名空间xmlns="http://schemas.YourCompany.com/YourSchema/",则使用与上述相同的代码,除了这个简单的更改:

    //  Add lib namespace with empty prefix  
    ns.Add("", "http://schemas.YourCompany.com/YourSchema/");   
    

    【讨论】:

      【解决方案3】:

      如果您想删除命名空间,您可能还想删除版本,为了节省您的搜索,我已经添加了该功能,因此下面的代码将同时执行这两项操作。

      我还将它包装在一个通用方法中,因为我正在创建非常大的 xml 文件,这些文件太大而无法在内存中序列化,因此我将输出文件分解并序列化为更小的“块”:

          public static string XmlSerialize<T>(T entity) where T : class
          {
              // removes version
              XmlWriterSettings settings = new XmlWriterSettings();
              settings.OmitXmlDeclaration = true;
      
              XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
              using (StringWriter sw = new StringWriter())
              using (XmlWriter writer = XmlWriter.Create(sw, settings))
              {
                  // removes namespace
                  var xmlns = new XmlSerializerNamespaces();
                  xmlns.Add(string.Empty, string.Empty);
      
                  xsSubmit.Serialize(writer, entity, xmlns);
                  return sw.ToString(); // Your XML
              }
          }
      

      【讨论】:

      • 当心,StringWriter 默认为 UTF-16 编码,这可能会导致下游反序列化问题。 using (var reader = XmlReader.Create(stream)){ reader.Read(); } 这会引发异常,因为声明声明它是 UTF-16,而内容实际上是写为 UTF-8。 System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
      • 要解决这个问题并仍然使用XmlReader,您可以使用var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true); 如果找到 true 将使用 BOM,否则使用您提供的默认值。
      【解决方案4】:

      我建议这个助手类:

      public static class Xml
      {
          #region Fields
      
          private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
          private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});
      
          #endregion
      
          #region Methods
      
          public static string Serialize(object obj)
          {
              if (obj == null)
              {
                  return null;
              }
      
              return DoSerialize(obj);
          }
      
          private static string DoSerialize(object obj)
          {
              using (var ms = new MemoryStream())
              using (var writer = XmlWriter.Create(ms, WriterSettings))
              {
                  var serializer = new XmlSerializer(obj.GetType());
                  serializer.Serialize(writer, obj, Namespaces);
                  return Encoding.UTF8.GetString(ms.ToArray());
              }
          }
      
          public static T Deserialize<T>(string data)
              where T : class
          {
              if (string.IsNullOrEmpty(data))
              {
                  return null;
              }
      
              return DoDeserialize<T>(data);
          }
      
          private static T DoDeserialize<T>(string data) where T : class
          {
              using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
              {
                  var serializer = new XmlSerializer(typeof (T));
                  return (T) serializer.Deserialize(ms);
              }
          }
      
          #endregion
      }
      

      :)

      【讨论】:

      • 很好的答案 :) 我还添加了这一行 stream.Position = 0; 并在我的解决方案中返回了整个流..按预期工作 - 所有减速标签都是删除
      • 仅将命名空间参数添加到序列化程序调用对我来说可以删除默认命名空间。在我看来,编写 new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty}) 而不是 new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")}) 是一种更清晰的编码方式。
      【解决方案5】:

      如果在从生成的类序列化为 xml 时(例如:使用 xsd.exe 时),如果您无法摆脱每个元素的额外 xmlns 属性,那么您会得到类似:

      <manyElementWith xmlns="urn:names:specification:schema:xsd:one" />
      

      然后我会与你分享对我有用的东西(以前的答案和我发现的 here 的混合)

      如下明确设置所有不同的 xmlns:

      Dim xmlns = New XmlSerializerNamespaces()
      xmlns.Add("one", "urn:names:specification:schema:xsd:one")
      xmlns.Add("two",  "urn:names:specification:schema:xsd:two")
      xmlns.Add("three",  "urn:names:specification:schema:xsd:three")
      

      然后将其传递给序列化

      serializer.Serialize(writer, object, xmlns);
      

      您将在根元素中声明三个命名空间,并且不再需要在其他元素中生成相应的前缀

      <root xmlns:one="urn:names:specification:schema:xsd:one" ... />
         <one:Element />
         <two:ElementFromAnotherNameSpace /> ...
      

      【讨论】:

        【解决方案6】:
                XmlWriterSettings settings = new XmlWriterSettings
                {
                    OmitXmlDeclaration = true
                };
        
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                ns.Add("", "");
        
                StringBuilder sb = new StringBuilder();
        
                XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));
        
                using (XmlWriter xw = XmlWriter.Create(sb, settings))
                {
                    xs.Serialize(xw, model, ns);
                    xw.Flush();
                    return sb.ToString();
                }
        

        【讨论】:

          猜你喜欢
          • 2015-02-06
          • 2018-06-28
          • 1970-01-01
          • 2022-10-24
          • 2018-08-26
          • 2021-04-23
          • 2011-09-01
          • 2012-04-16
          • 2021-03-06
          相关资源
          最近更新 更多