【问题标题】:Deserialize Xml with empty elements in C#在 C# 中使用空元素反序列化 Xml
【发布时间】:2011-02-27 07:21:33
【问题描述】:

试图将来自供应商的一些 xml 片段反序列化为对象。问题是我在每个 empy 元素标签上都得到了无效的格式。当所有元素都有值时,我可以反序列化对象没有问题。或者省略空元素。

Xml 代码段:


1

C# 类:

[Serialilbe()]     
public class foo
{ 
   public foo(){}
   [XmlElementAttribute(IsNullable = true)]
   public int? propOne {get;set;} 
   [XmlElementAttribute(IsNullable = true)]
   public int? propTwo {get;set;}   
 }

我可以对类进行设置以调整解析吗?

有没有一种简单的方法可以应用 xsl 来删除这些元素?

我应该使用正则表达式来删除要反序列化的空元素吗?

更好的方法?

【问题讨论】:

  • 您是否通过相同的接口(即 XmlSerializer 类)进行序列化?
  • 附带说明,XMLSerializer 即将被弃用。您可以考虑使用 DataContractSerializer。

标签: c# xml serialization


【解决方案1】:

见这篇文章:Can XmlSerializer deserialize into a Nullable?

简而言之,如果您想使用 Nullable 类型,您的 Xml 应该如下所示:

<foo xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
<propOne>1</propOne>
<propTwo xsi:nil='true'/>
</foo>

两个变化是添加命名空间,并在 null 元素上显式设置 xsi:nil 为 true。

如果您无法控制您的 Xml,这里描述了一种更高级的技术:Using XmlSerializer to deserialize into a Nullable

【讨论】:

  • “使用 XmlSerializer 反序列化为 Nullable”链接已失效。一种方法是实现 IXmlSerializable 并在 ReadXml() 中将空转换为 null。类似于stackoverflow.com/a/625463/1034683
【解决方案2】:

为简单起见,为什么不使用 XmlDocument 和 XPath 显式解析 xml?使用 XPath 显式访问每个 xml 节点,例如

XmlNode node = xml.SelectSingleNode ("foo/PropOne");
if (node != null)
{
     propOneValue = node.innerText;
}

【讨论】:

  • 我假设他想反序列化为一个类/类型,而不必一个一个地提取值。
【解决方案3】:

清除这些节点的最统一方法似乎是将 RegEx 过滤器添加到反序列化器。

    public static T Deserialize<T>(string xml){
        XmlSerializer xs = new XmlSerializer(typeof(T));
        string cleanXml = Regex.Replace(xml, @"<[a-zA-Z].[^(><.)]+/>",
                                        new MatchEvaluator(RemoveText));
        MemoryStream memoryStream = new MemoryStream((new UTF8Encoding()).GetBytes(cleanXml));
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        return (T)xs.Deserialize(memoryStream);
    }
  static string RemoveText(Match m) { return "";}

【讨论】:

  • 如果有一个完整的元素没有值怎么办:&lt;Element&gt;&lt;/Element&gt;。我已经编写了自己的逻辑来删除它,但是它太慢而且文件太大。我们可以编写 RegEx 来检测这一点吗?
【解决方案4】:

如果您无法控制入站 XML,另一种选择是通过让反序列化器假装变量是字符串来解决此问题:

[Serializable()]     
public class foo
{ 
  public foo(){}

  [XmlElement("propOne")]
  [EditorBrowsable(EditorBrowsableState.Never)]
  public string propOneString {get;set;}

  [XmlIgnore]
  private int? propOneInternal = null;
  [XmlIgnore]
  private bool propOneSet = false;

  [XmlIgnore]
  public int? propOne
  {
    get
    {
      if (!propOneSet)
      {
        if(!string.IsNullOrEmpty(propOneString)
        {
          propOneInternal = int.Parse(propOneString);
        }
        //else leave as pre-set default: null
        propOneSet = true;
      }
      return propOneInternal;
    }
    set { propOneInternal = value; }
  }
}

反序列化器很乐意在字符串元素为空时对其进行解析,因此您可以使用它。

这不是特别好,但如果你只需要覆盖一两个标签就可以了

【讨论】:

  • 编辑:propOneString 显然应该是一个字符串,而不是一个 int :)
  • 是的,对我来说最简单的方法。只需要处理一个标签。谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
  • 2021-09-06
  • 2023-03-30
  • 2016-12-02
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多