C# 处理-元素xsi:nil与no元素

C# 处理-元素xsi:nil与no元素,c#,xml,xml-nil,C#,Xml,Xml Nil,在C#中,当处理包含在模式中定义为nillable=“true”和minOccurs=“0”的元素的XML时,区分nil元素和省略元素的最优雅的解决方案是什么 用例是这样一种情况:服务接收到一个XML片段,其中包含表示已更改的记录的所有字段的元素,但没有一个字段未更改 例如,当记录从{a:1;b:2;c:3;}更改为{a:1;b:4;c:null}时,服务可能会收到: <change> <b>4</b> <c xsi:nil="true" /&g

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

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

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

<change>
  <b>4</b>
  <c xsi:nil="true" />
</change>
<change>
  <b>4</b>
</change>
然而,在C#中,这两个具有不同含义的片段都映射到一个看起来像
{a:null;b:4;C:null;}
的对象。解析XML时,有关c显式为零或不存在的信息将丢失。我们不确定a和b是应该设置为null,还是保持不变

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


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

使用LINQ到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();

假设您使用的是
XmlSerializer
,则可以添加一个额外的布尔属性来记住是否已显式设置属性。此外,如果属性具有指定的名称
XXX
,其中
XXX
是相关“真实”属性的名称,则
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);
    }
}
公共类TestClass
{
字符串_值=null;
[XmlElement(“值”,IsNullable=true)]
公共字符串值
{
获取{返回_值;}
设置
{
_价值=价值;
指定值=真;
}
}
[XmlIgnore]
指定的公共bool值{get;set;}
公共静态无效测试()
{
Test(新的TestClass());
测试(新的TestClass(){Value=null});
测试(newtestclass(){Value=“Something”});
}
静态无效测试(TestClass测试)
{
var xml=test.GetXml();
Debug.WriteLine(xml);
var testBack=xml.LoadFromXML();
Assert(testBack.Value==test.Value&&testBack.ValueSpecified==test.ValueSpecified);
}
}
三个测试用例的XML输出为:


某物
如您所见,null属性和unset属性之间的区别已成功序列化和反序列化


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

我没有在您的帖子中看到您的
minOccurs=0
,您能给出一个示例及其代表的内容吗?
<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>