我可以在 XSD C# 生成的类创建的 XML 中的同一标记处具有空属性和其他属性吗? [英] Can I have null attribute and other attribute at the same tag in XML created by XSD C# generated class?

查看:15
本文介绍了我可以在 XSD C# 生成的类创建的 XML 中的同一标记处具有空属性和其他属性吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一堆 C# 类,它们是从 XSD 自动生成的.然后我根据这些 C# 类生成 XML 文件.到目前为止什么都不存在.

问题:

生成的 XML 文件正在通过验证,验证需要为所有带有 xsi:nil="true" 的 XML 标记添加一个额外属性.基本上标签应该看起来像:<testTag.01 xsi:nil="true" NV="123123"/>,但我无法在 C# 中实现.我的代码是:

<块引用>

 if (myObject.TestTag.HasValue){t.testTag01 = 新的 testTag01();t.testTag01.Value = myObject.TestTag.Value;}//别的//{//t.testTag01 = new testTag01();//t.testTag01.NV = "123123";//未记录//}

此代码生成 <testTag.01>SomeValue</testTag.01><testTag.01 xsi:nil="true"/>.

如果我取消注释 ELSE,结果将是:<testTag.01>SomeValue</testTag.01><testTag.01NV="123123"/>.

所以我不知道如何获得验证工具所需的格式.有什么想法吗?

附言

这是自动生成的 C# 类:

<块引用>

///[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd","4.0.30319.33440")] [System.SerializableAttribute()][System.Diagnostics.DebuggerStepThroughAttribute()][System.ComponentModel.DesignerCategoryAttribute("code")][System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true,命名空间="http://www.blabla.org")]

公共部分类 testTag01 {

私有字符串 nvField;私有 SomeEnum 值字段;///<备注/>[System.Xml.Serialization.XmlAttributeAttribute()]公共字符串 NV {得到 {返回这个.nvField;}放 {this.nvField = 值;}}///<备注/>[System.Xml.Serialization.XmlTextAttribute()]公共 SomeEnum 值 {得到 {返回 this.valueField;}放 {this.valueField = 值;}} }

我不想改变那部分,但我知道不这样做是不可能的.我还尝试将 SomeEnum 设置为 Nullable.public SomeEnum?值,但抛出异常:

无法序列化 System.Nullable`1[] 类型的成员值".XmlAttribute/XmlText 不能用于编码复杂类型.

解决方案

XmlSerializer 不直接支持绑定到同时具有 xsi:nil="true" 的元素连同其他属性值;请参阅 Xsi:nil 属性绑定支持:nil 属性和其他属性.

因此,您需要手动发出属性.

如果您希望能够生成一个没有内容和两个属性的元素,一个名为 NV 而另一个 alwaysxsi:nil="true",您可以修改您的 testTag01 类,使其具有 NV 属性以及具有正确命名空间和名称的合成属性:

公共类testTag01{[Xml属性]公共字符串 NV { 获取;放;}[XmlAttribute("nil", 命名空间 = "http://www.w3.org/2001/XMLSchema-instance")]公共字符串无{得到{返回真";} 放 { } }}

如果您有时想要 xsi:nil="true" 但在其他时候希望元素具有与您的 SomeEnum,你需要做一些更复杂的事情,因为当元素有内容时 xsi:nil="true" 必须被抑制:

公共类testTag01{[Xml属性]公共字符串 NV { 获取;放;}[XmlAttribute("nil", 命名空间 = "http://www.w3.org/2001/XMLSchema-instance")]公共字符串 Nil { 获取 { 返回 SomeEnum == null ?真":空;} 放 { } }public bool ShouldSerializeNil() { return SomeEnum == null;}[Xml忽略]公共SomeEnum?SomeEnum { 得到;放;}[Xml文本]公共字符串 SomeEnumText{得到{if (SomeEnum == null)返回空值;返回 SomeEnum.Value.ToString();}放{//看这里是否需要解析 XmlEnumAttribute 属性//http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value价值=价值.修剪();如果(字符串.IsNullOrEmpty(值))SomeEnum = null;别的{尝试{SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, false);}捕捉(例外){SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, true);}}}}}

(同时具有 xsi:nil="true" 和内容的元素将违反 XML 标准;希望你没有那个.)

然后像这样使用它:

公共类TestClass{[XmlElement("testTag.01")]公共 testTag01 TestTag { 获取;放;}公共静态无效测试(){测试(新 TestClass { TestTag = new testTag01 { NV = "123123" } });测试(新 TestClass { TestTag = new testTag01 { NV = "123123", SomeEnum = SomeEnum.SomeValue } });}私有静态无效测试(TestClass 测试){var xml = test.GetXml();var test2 = xml.LoadFromXML();Console.WriteLine(test2.GetXml());Debug.WriteLine(test2.GetXml());如果(test2.TestTag.NV != test.TestTag.NV){throw new InvalidOperationException("test2.TestTag.NV != test.TestTag.NV");}}}

XML 输出如下所示:

<块引用>

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

或者

<块引用>

<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><testTag.01 NV="123123">SomeValue</testTag.01></TestClass>

使用这些扩展方法制作fiddle的原型:

公共静态类 XmlSerializationHelper{public static T LoadFromXML(这个字符串 xmlString, XmlSerializer 序列化器 = null){T 返回值 = 默认值(T);使用 (StringReader reader = new StringReader(xmlString)){对象结果 = (serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);如果(结果为 T){返回值 = (T) 结果;}}返回返回值;}公共静态字符串 GetXml(this T obj, XmlSerializerNamespaces ns = null, XmlWriterSettings settings = null, XmlSerializer serializer = null){使用 (var textWriter = new StringWriter()){设置=设置??新 XmlWriterSettings() { Indent = true, IndentChars = " " };//出于美观目的.使用 (var xmlWriter = XmlWriter.Create(textWriter, settings))(序列化器??新的 XmlSerializer(typeof(T))).Serialize(xmlWriter,obj,ns);返回 textWriter.ToString();}}}

I have a bunch of C# classes, which are auto generated from an XSD. Then I generate XML files based on those C# classes. Nothing existing so far.

The problem:

The generated XML files are going through validation and the validation requires an extra attribute to all XML tags with xsi:nil="true". Basically the tags should look like : <testTag.01 xsi:nil="true" NV="123123" />, but I can't achieve that in C#. My code is:

     if (myObject.TestTag.HasValue)
        {
            t.testTag01 = new testTag01();
            t.testTag01.Value = myObject.TestTag.Value;
        }
        //else
        //{
        //    t.testTag01 = new testTag01();
        //    t.testTag01.NV = "123123";//Not Recorded
        //}

This code generates <testTag.01>SomeValue</testTag.01> or <testTag.01 xsi:nil="true"/>.

If I uncomment the ELSE, the result would be: <testTag.01>SomeValue</testTag.01> or <testTag.01 NV="123123" />.

So I have no idea how to get to the format, which is required by the validation tool. Any ideas ?

P.S.

Here is the auto-generated C# class:

/// [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.blabla.org")]

public partial class testTag01 {

private string nvField;

private SomeEnum valueField;

/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute()]
public string NV {
    get {
        return this.nvField;
    }
    set {
        this.nvField = value;
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public SomeEnum Value {
    get {
        return this.valueField;
    }
    set {
        this.valueField = value;
    }
} }

I wouldn't like to alter that part, but I understand it is impossible without doing it. Also I have tried to set SomeEnum to be Nullable. public SomeEnum? Value, but is throwing an exception:

Cannot serialize member 'Value' of type System.Nullable`1[]. XmlAttribute/XmlText cannot be used to encode complex types.

解决方案

XmlSerializer doesn't directly support binding to elements that simultaneously have xsi:nil="true" along with other attribute values; see Xsi:nil Attribute Binding Support: The nil attribute and other attributes.

Thus, you need to emit the attribute manually.

If you want to be able to generate an element with no content and two attributes, one named NV and the other always being xsi:nil="true", you can modify your testTag01 class to have the NV property as well as a synthetic property having the correct namespace and name:

public class testTag01 
{
    [XmlAttribute]
    public string NV { get; set; }

    [XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public string Nil { get { return "true"; } set { } }
}

If you sometimes want to have xsi:nil="true" but at other times want the element to have content corresponding to your SomeEnum, you need to do something a bit more complicated, since the xsi:nil="true" must be suppressed when the element has content:

public class testTag01
{
    [XmlAttribute]
    public string NV { get; set; }

    [XmlAttribute("nil", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public string Nil { get { return SomeEnum == null ? "true" : null; } set { } }

    public bool ShouldSerializeNil() { return SomeEnum == null; }

    [XmlIgnore]
    public SomeEnum? SomeEnum { get; set; }

    [XmlText]
    public string SomeEnumText
    {
        get
        {
            if (SomeEnum == null)
                return null;
            return SomeEnum.Value.ToString();
        }
        set
        {
            // See here if one needs to parse XmlEnumAttribute attributes
            // http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value
            value = value.Trim();
            if (string.IsNullOrEmpty(value))
                SomeEnum = null;
            else
            {
                try
                {
                    SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, false);
                }
                catch (Exception)
                {
                    SomeEnum = (SomeEnum)Enum.Parse(typeof(SomeEnum), value, true);
                }
            }
        }
    }
}

(An element that simultaneously has both xsi:nil="true" and content would be a violation of the XML standard; hopefully you don't have that.)

Then use it like:

public class TestClass
{
    [XmlElement("testTag.01")]
    public testTag01 TestTag { get; set; }

    public static void Test()
    {
        Test(new TestClass { TestTag = new testTag01 { NV = "123123" } });
        Test(new TestClass { TestTag = new testTag01 { NV = "123123", SomeEnum = SomeEnum.SomeValue } });
    }

    private static void Test(TestClass test)
    {
        var xml = test.GetXml();

        var test2 = xml.LoadFromXML<TestClass>();

        Console.WriteLine(test2.GetXml());
        Debug.WriteLine(test2.GetXml());

        if (test2.TestTag.NV != test.TestTag.NV)
        {
            throw new InvalidOperationException("test2.TestTag.NV != test.TestTag.NV");
        }
    }
}

The XML output looks like:

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

Or

<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <testTag.01 NV="123123">SomeValue</testTag.01>
</TestClass>

Prototype fiddle using these extension methods:

public static class XmlSerializationHelper
{
    public static T LoadFromXML<T>(this string xmlString, XmlSerializer serializer = null)
    {
        T returnValue = default(T);

        using (StringReader reader = new StringReader(xmlString))
        {
            object result = (serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
            if (result is T)
            {
                returnValue = (T)result;
            }
        }
        return returnValue;
    }

    public static string GetXml<T>(this T obj, XmlSerializerNamespaces ns = null, XmlWriterSettings settings = null, XmlSerializer serializer = null)
    {
        using (var textWriter = new StringWriter())
        {
            settings = settings ?? new XmlWriterSettings() { Indent = true, IndentChars = "  " }; // For cosmetic purposes.
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                (serializer ?? new XmlSerializer(typeof(T))).Serialize(xmlWriter, obj, ns);
            return textWriter.ToString();
        }
    }
}

这篇关于我可以在 XSD C# 生成的类创建的 XML 中的同一标记处具有空属性和其他属性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆