【问题标题】:Prevent <xsi:nil="true"> on Nullable Value Types when Serializing to XML序列化为 XML 时防止可空值类型上的 <xsi:nil="true">
【发布时间】:2011-01-16 04:39:25
【问题描述】:

我在我的可序列化类中添加了一些可为空的值类型。我使用XmlSerializer 执行序列化,但是当值设置为null 时,我得到一个带有xsi:nil="true" 的空节点。这是我在Xsi:nil Attribute Binding Support 发现的正确行为。

有没有办法关闭这个选项,以便在值类型为null时不输出任何内容?

【问题讨论】:

    标签: .net serialization xml-serialization xml-nil


    【解决方案1】:

    我也遇到过同样的问题。这是我读到的关于在序列化为 XML 时处理可空值类型的地方之一:http://stackoverflow.com/questions/244953/serialize-a-nullable-int

    他们提到使用内置模式,例如为可空值类型创建附加属性。就像一个名为

    的属性
    public int? ABC
    

    您必须添加 要么public bool ShouldSerializeABC() {return ABC.HasValue;} 或公开bool ABCSpecified { get { return ABC.HasValue; } }

    我只是序列化到 xml 以发送到 sql 存储过程,所以我也避免更改我的类。我正在对我的 .value() 查询中的所有可空元素进行[not(@xsi:nil)] 检查。

    【讨论】:

    • 我只是简单地在 XML 序列化后扫描 XML 并删除任何 xsi:nil="true" 节点。
    【解决方案2】:

    我必须为每个可空值添加一个ShouldSerialize 方法。

    [Serializable]
    public class Parent
    {
        public int? Element { get; set; }
    
        public bool ShouldSerializeElement() => Element.HasValue;
    }
    

    【讨论】:

      【解决方案3】:

      我发现 公共布尔ABC指定 是唯一使用 .NET 4.0 的。我还必须添加 XmlIgnoreAttribute

      这是我在 Web Reference Resource.cs 文件中抑制名为 ABC 的字符串的完整解决方案:

      // backing fields
      private string abc;
      private bool abcSpecified; // Added this - for client code to control its serialization
      
      // serialization of properties
      [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
      public string ABC
      {
          get
          {
              return this.abc;
          }
          set
          {
              this.abc= value;
          }
      }
      
      // Added this entire property procedure
      [System.Xml.Serialization.XmlIgnoreAttribute()]
      public bool ABCSpecified
      {
          get
          {
              return this.abcSpecified;
          }
          set
          {
              this.abcSpecified = value;
          }
      }
      

      【讨论】:

      • “指定”属性上的 XmlIgnoreAttribute 不是必需的,同一属性上的设置器也是如此。
      【解决方案4】:

      SpecifiedShouldSerialize 等所有元方法只是 microsoft .Net XML 结构的糟糕编程设计。如果您无法直接访问要序列化的类,情况会变得更加复杂。

      在他们的序列化方法中,他们应该只添加一个类似“ignoreNullable”的属性。

      我当前的解决方法是序列化 xml,然后使用以下函数删除所有具有 nil="true" 的节点。

      /// <summary>
      /// Remove optional nullabe xml nodes from given xml string using given scheme prefix.
      /// 
      /// In other words all nodes that have 'xsi:nil="true"' are being removed from document.
      /// 
      /// If prefix 'xmlns:xsi' is not found in root element namespace input xml content is returned.
      /// </summary>
      /// <param name="xmlContent"></param>
      /// <param name="schemePrefix">Scheme location prefix</param>
      /// <returns></returns>
      public static String RemoveNilTrue(String xmlContent, String schemePrefix = "xsi")
      {
          XmlDocument xmlDocument = new XmlDocument();
          xmlDocument.LoadXml(xmlContent);
      
          XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDocument.NameTable);
      
          bool schemeExist = false;
      
          foreach (XmlAttribute attr in xmlDocument.DocumentElement.Attributes)
          {
              if (attr.Prefix.Equals("xmlns", StringComparison.InvariantCultureIgnoreCase)
                  && attr.LocalName.Equals(schemePrefix, StringComparison.InvariantCultureIgnoreCase))
              {
                  nsMgr.AddNamespace(attr.LocalName, attr.Value);
                  schemeExist = true;
                  break;
              }
          }
      
          // scheme exists - remove nodes
          if (schemeExist)
          {
              XmlNodeList xmlNodeList = xmlDocument.SelectNodes("//*[@" + schemePrefix + ":nil='true']", nsMgr);
      
              foreach (XmlNode xmlNode in xmlNodeList)
                  xmlNode.ParentNode.RemoveChild(xmlNode);
      
              return xmlDocument.InnerXml;
          }
          else
              return xmlContent;
      }
      

      【讨论】:

        【解决方案5】:

        这可能是最不复杂的答案,但我通过简单的字符串替换为我解决了这个问题。

        .Replace(" xsi:nil=\"true\" ", "");

        无论如何,我首先要序列化为字符串。我可以稍后保存到文件中。

        它使我的所有 XmlWriterSettings 保持不变。我发现她搞砸了另一种解决方案:)

            private static string Serialize<T>(T details)
            {
                var serializer = new XmlSerializer(typeof(T));
                using (var ms = new MemoryStream())
                {
                    var settings = new XmlWriterSettings
                    {
                        Encoding = Encoding.GetEncoding("ISO-8859-1"),
                        NewLineChars = Environment.NewLine,
                        ConformanceLevel = ConformanceLevel.Document,
                        Indent = true,
                        OmitXmlDeclaration = true
                    };
        
                    using (var writer = XmlWriter.Create(ms, settings))
                    {
                        serializer.Serialize(writer, details);
                        return Encoding.UTF8.GetString(ms.ToArray()).Replace(" xsi:nil=\"true\" ", "");
                    }
                }
            }
        

        【讨论】:

          【解决方案6】:

          我是这样完成的:

              private bool retentionPeriodSpecified;
              private Nullable<int> retentionPeriod;
          
              [XmlElement(ElementName = "retentionPeriod", IsNullable = true, Order = 14)]
              public Nullable<int> RetentionPeriod { get => retentionPeriod; set => retentionPeriod = value; }
          
              [System.Xml.Serialization.XmlIgnore()]
              public bool RetentionPeriodSpecified
              {
                  get { return !(retentionPeriod is null); }
              }
          

          【讨论】:

            猜你喜欢
            • 2015-03-10
            • 2019-02-18
            • 1970-01-01
            • 2015-11-29
            • 1970-01-01
            • 2010-09-07
            • 2017-10-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多