我可以有空属性和其他属性在相同的标记在XML中创建的XSD c#生成类

本文关键字:属性 XSD 创建 XML 其他 我可以 | 更新日期: 2023-09-27 18:15:52

我有一堆c#类,它们是从XSD自动生成的。然后基于这些c#类生成XML文件。到目前为止还不存在。

问题:

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

     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
        //}

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

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

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

公立小学下面是自动生成的c#类:

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

公共部分类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;
    }
} }

我不想改变那部分,但我知道不做是不可能的。我也曾试图设置SomeEnum为空。public SomeEnum? Value,但抛出异常:

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

我可以有空属性和其他属性在相同的标记在XML中创建的XSD c#生成类

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

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

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

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 { } }
}

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

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);
                }
            }
        }
    }
}

(同时具有xsi:nil="true"和content的元素将违反XML标准;希望你没有。)

然后像这样使用:

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");
        }
    }
}

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>

Prototype fiddle使用这些扩展方法:

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();
        }
    }
}

正如预期的那样,没有现成的解决方案,所以我即兴发挥了一下,并在后处理逻辑中实现了我的目标。

我正在解析生成的XML,如果我正在寻找一个节点与xsi:nil属性,但没有NV属性-我添加NV属性与默认值。对于具有NV属性的节点也是如此,但没有xsi:nil。

代码如下:

        XmlDocument doc = new XmlDocument();// instantiate XmlDocument and load XML from file
        doc.Load("somepath.xml");
        //Get the nodes with NV attribute(using XPath) and add xsi:nill to that nodes
        XmlNodeList nodes = doc.SelectNodes("//*[@NV]");
        foreach (XmlNode node in nodes)
        {
            XmlAttribute nilAttr = doc.CreateAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance");
            nilAttr.Value = "true";
            node.Attributes.Append(nilAttr);
        }
        //Get the nodes with xsi:nill attribute(using XPath) and add NV with default value to that nodes
        XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
        nsManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        XmlNodeList nilNodes = doc.SelectNodes("//*[@xsi:nil]", nsManager);
        foreach (XmlNode node in nilNodes)
        {
            XmlAttribute nvAttr = doc.CreateAttribute("NV");
            nvAttr.Value = "7701003";
            node.Attributes.Append(nvAttr);
        }
        doc.Save("somepath.xml");

上面的答案完全有意义,但由于这些类是自动生成的,我将按照我的方式进行后处理,因为如果提供者更改了XSD模式,我的解决方案不需要任何额外的工作。谢谢。