1

在 C# 中,当处理包含在 schema 中定义为nillable="true"and的元素的 XML 时minOccurs="0",区分 nil 元素和省略元素的最优雅的解决方案是什么?

用例是这样一种情况,服务接收一个 XML 片段,其中包含表示记录中所有已更改字段的元素,但没有未更改的字段。

例如,当记录从{ a: 1; b: 2; c: 3; }变为{ a: 1; b: 4; c: null }时,服务可能会收到:

<change>
  <b>4</b>
  <c xsi:nil="true" />
</change>

当记录从{ a: 1; b: 2; c: 3; }(相同){ a: 1; b: 4; c: 3 }更改为('c' 没有更改)时,服务可能会收到:

<change>
  <b>4</b>
</change>

但是,在 C# 中,这两个具有不同含义的片段都映射到一个看起来像{ a: null; b: 4; c: null; }. 解析 XML 时,有关 c 显式为 nil 或根本不存在的信息会丢失。我们不确定 a 和 b 是否应该设置为 null 或保持不变。

在此示例中,您可能会建议消息应包含所有字段以避免混淆(以及识别正在更改的记录的内容),但我们正在处理有关大量记录的实际消息,其中只需要发送实际是相关的。我们处理的不仅仅是整数字段,而是各种简单和复杂的类型。

我认为 XML 片段相当优雅和清晰,但是在 C# 应用程序中处理它们时,您建议的最优雅和清晰的解决方案是什么?

4

2 回答 2

0

假设您正在使用XmlSerializer,您可以添加一个额外的布尔属性来记住某个属性是否已被显式设置。此外,如果属性的名称XXXSpecifiedXXX相关“真实”属性的名称,则XmlSerializer在序列化时将省略该属性。例如:

public class TestClass
{
    string _value = null;

    [XmlElement("Value", IsNullable=true)]
    public string Value
    {
        get { return _value; }
        set
        {
            _value = value;
            ValueSpecified = true;
        }
    }

    [XmlIgnore]
    public bool ValueSpecified { get; set; }

    public static void Test()
    {
        Test(new TestClass());
        Test(new TestClass() { Value = null });
        Test(new TestClass() { Value = "Something" });
    }

    static void Test(TestClass test)
    {
        var xml = test.GetXml();
        Debug.WriteLine(xml);
        var testBack = xml.LoadFromXML<TestClass>();
        Debug.Assert(testBack.Value == test.Value && testBack.ValueSpecified == test.ValueSpecified);
    }
}

三个测试用例的 XML 输出是:

<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />

<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Value xsi:nil="true" />
</TestClass>

<TestClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Value>Something</Value>
</TestClass>

可以看到,空属性和未设置属性的区别是成功序列化和反序列化。

有关详细信息,请参阅此处:MinOccurs 属性绑定支持 。(文档描述了对公共字段的支持,但该功能也适用于公共属性。)

于 2015-04-21T18:44:02.833 回答
0

使用 Linq-to-Xml 您可以解析字符串/流/文件并确定元素节点是否包含值。

XElement change = XElement.Parse(string); // .Load(stream or file)
var changes = change.Elements()
                    .Where(x => (string)x != null)
                    // The above Where() determines your empty from non-empty
                    .Select(x => 
                    { 
                        Name = x.Name.LocalName, 
                        Value = (string)x 
                    })
                    .ToList();
于 2015-04-21T18:27:11.127 回答