【问题标题】:Remove xml element with xsi:nil="true" C# serialization使用 xsi:nil="true" C# 序列化删除 xml 元素
【发布时间】:2019-02-18 04:59:26
【问题描述】:

我有一个 XML,它有一些值,有时可能有如下所示的空值:我不希望在 XML 中列出所有具有空值的节点!元素在类中设置为IsNullable = true。任何建议,因为我在 Google 中尝试了很多东西.. 没有任何帮助!

<?xml version="1.0" encoding="utf-8"?>
<Materials>
  <Material>
    <MaterialName>ABC</MaterialName>
    <Weight Value="0.303">
      <Weight_A xsi:nil="true" />
      <Weight_B xsi:nil="true" />
    </Weight>
    <Density Value="800">
      <Density_A xsi:nil="true" />
      <Density_B xsi:nil="true" />
    </Density>
    <Volume Value="8771.427" />
  </Material>
  <Material>
    <MaterialName>ABC</MaterialName>
    <Weight>
      <V5_Weight>2.009</V5_Weight>
      <V6_Weight>1.3318154561904</V6_Weight>
    </Weight>
    <Density>
      <V5_density>1000</V5_density>
      <V6_density>663</V6_density>
    </Density>
    <Volume Value="2008771.427" />
  </Material>
</Materials>

类结构如下:

[XmlRoot(ElementName = "Weight")]
public class Weight
{
    [XmlElement(ElementName = "Weight_A", IsNullable = true)]
    public string Weight_A { get; set; }

    [XmlElement(ElementName = "Weight_B", IsNullable = true)]
    public string Weight_B { get; set; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }

}

[XmlRoot(ElementName = "Density")]
public class Density
{
    [XmlElement(ElementName = "Density_A", IsNullable = true)]
    public string Density_A { get; set; }
    [XmlElement(ElementName = "Density_B", IsNullable = true)]
    public string Density_B { get; set; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

[XmlRoot(ElementName = "Volume")]
public class Volume
{
    [XmlElement(ElementName = "Volume_A")]
    public string Volume_A { get; set; }
    [XmlElement(ElementName = "Volume_B")]
    public string Volume_B { get; set; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

[XmlRoot(ElementName = "Material")]
public class Material
{
    [XmlElement(ElementName = "MaterialName")]
    public string MaterialName { get; set; }
    [XmlElement(ElementName = "Weight")]
    public Weight Weight { get; set; }

    [XmlElement(ElementName = "Density")]
    public Density Density { get; set; }
    [XmlElement(ElementName = "Volume")]
    public Volume Volume { get; set; }
}

[XmlRoot(ElementName = "Materials")]
public class Materials
{
    [XmlElement(ElementName = "Material")]
    public List<Material> Material { get; set; }
}

【问题讨论】:

  • 请发布您的课程
  • 这个答案stackoverflow.com/questions/37838640/… 允许更细粒度地控制属性何时被序列化,但我怀疑你的 [XmlAttribute] 有问题。
  • 您的 XML 格式不正确。它缺少xsi: 命名空间前缀的定义,可能是因为它是某个较大文档的片段。很可能应该是&lt;Materials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;,你能确认一下吗?

标签: c# xml serialization xmlserializer


【解决方案1】:

基本问题是您设置了XmlElementAttribute.IsNullable = true。来自docs

获取或设置一个值,该值指示XmlSerializer 是否必须将设置为null 的成员序列化为xsi:nil 属性设置为true 的空标记。

因此,理论上您可以将其设置为 false(或根本不设置),并且不会为空值发出 xsi:nil 属性:

[XmlRoot(ElementName = "Weight")]
public class Weight
{
    [XmlElement(ElementName = "Weight_A" /*, IsNullable = true*/)]
    public string Weight_A { get; set; }
    [XmlElement(ElementName = "Weight_B" /*, IsNullable = true*/)]
    public string Weight_B { get; set; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

[XmlRoot(ElementName = "Density")]
public class Density
{
    [XmlElement(ElementName = "Density_A"/*, IsNullable = true*/)]
    public string Density_A { get; set; }
    [XmlElement(ElementName = "Density_B"/*, IsNullable = true*/)]
    public string Density_B { get; set; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

但是,如果您这样做,您可能会遇到反序列化遗留 XML 文件的问题,即字符串值的 xsi:nil 元素现在将被反序列化为空字符串,而不是 null 字符串。 (演示小提琴#1 here。)如果这成为一个问题,您必须保留XmlElementAttribute.IsNullable = true 设置,而是使用this answer 中描述的条件序列化模式之一到ShouldSerialize*() vs *Specified Conditional Serialization Pattern

[XmlRoot(ElementName = "Weight")]
public class Weight
{
    [XmlElement(ElementName = "Weight_A", IsNullable = true)]
    public string Weight_A { get; set; }

    public bool ShouldSerializeWeight_A() { return Weight_A != null; }

    [XmlElement(ElementName = "Weight_B", IsNullable = true)]
    public string Weight_B { get; set; }

    public bool ShouldSerializeWeight_B() { return Weight_B != null; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

[XmlRoot(ElementName = "Density")]
public class Density
{
    [XmlElement(ElementName = "Density_A", IsNullable = true)]
    public string Density_A { get; set; }

    public bool ShouldSerializeDensity_A() { return Density_A != null; }

    [XmlElement(ElementName = "Density_B", IsNullable = true)]
    public string Density_B { get; set; }

    public bool ShouldSerializeDensity_B() { return Density_B != null; }

    [XmlAttribute(AttributeName = "Value")]
    public string Value { get; set; }
}

完成此操作后,&lt;NodeName xsi:nil="true" /&gt; 元素将在反序列化期间映射到 null 字符串,并在序列化期间完全跳过。

注意事项:

  • 您的 XML 格式不正确。它缺少xsi: 命名空间前缀的定义,可能是因为它是某个较大文档的片段。这个答案假定它应该是:

    <Materials 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    
  • 某些元素根本不绑定到您的 c# 数据模型,包括:

    <V5_Weight>2.009</V5_Weight>
    <V6_Weight>1.3318154561904</V6_Weight>
    

    <V5_density>1000</V5_density>
    <V6_density>663</V6_density>
    

    这个答案并没有试图解决这个问题(如果它实际上是一个问题)。

小提琴样本 #2 here.

【讨论】:

  • 谢谢!!它就像一个魅力!我有 xsi: 命名空间前缀,但在发布问题时删除了它:(
猜你喜欢
  • 1970-01-01
  • 2015-11-29
  • 2015-03-10
  • 2021-02-07
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多