我可以在XSD C#生成的类创建的XML中的同一标签上具有null属性和其他属性吗?
我有一堆C#类,它们是从XSD自动生成的.然后,我基于这些C#类生成XML文件.到目前为止没有任何东西.
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.
问题:
生成的XML文件正在通过验证,验证需要使用 xsi:nil ="true"
的所有XML标签具有额外的属性.基本上,标签应如下所示:< testTag.01 xsi:nil ="true" NV ="123123"/>
,但是我无法在C#中实现.我的代码是:
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
//}
此代码生成< testTag.01> SomeValue</testTag.01>
或< testTag.01 xsi:nil ="true"/>
.
如果我取消注释 ELSE ,结果将是:< testTag.01> SomeValue</testTag.01>
或< testTag.01NV ="123123"/>
.
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.
这是自动生成的C#类:
Here is the auto-generated C# class:
///[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")]
/// [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")]
公共局部类testTag01 {
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;
}
} }
我不想更改该部分,但我知道不这样做就不可能.我也试图将SomeEnum设置为Nullable.公共SomeEnum?值
,但抛出异常:
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
不直接支持绑定到同时具有 xsi:nil ="true"
的元素以及其他属性值;请参见 Xsi:nil属性绑定支持:nil属性和其他属性.
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.
如果您希望能够生成一个没有内容且具有两个属性的元素,一个名为 NV
,另一个始终为 xsi:nil ="true"
,则可以修改您的 testTag01
类,使其具有 NV
属性以及具有正确名称空间和名称的合成属性:
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 { } }
}
如果您有时想要具有 xsi:nil ="true"
,但在其他时候希望元素具有与您的 SomeEnum
相对应的内容>,您需要做一些复杂的事情,因为当元素具有内容时,必须禁止 xsi:nil ="true"
:
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);
}
}
}
}
}
(同时具有 xsi:nil ="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.)
然后像这样使用它:
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 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();
}
}
}