我可以在由 XSD C# 生成的 class 创建的 XML 中的同一标记处具有空属性和其他属性吗?
Can I have null attribute and other attribute at the same tag in XML created by XSD C# generated class?
我有一堆 C# classes,它们是从 XSD 自动生成的。然后我根据那些 C# classes 生成 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" />
。
所以我不知道如何获得验证工具所需的格式。有什么想法吗?
P.S.
这是自动生成的 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;
}
} }
我不想改变那部分,但我知道不做是不可能的。我也尝试将 SomeEnum 设置为 Nullable。 public SomeEnum? Value
,但抛出异常:
Cannot serialize member 'Value' of type System.Nullable`1[]. XmlAttribute/XmlText cannot be used to encode complex types.
XmlSerializer
不直接支持绑定到同时具有 xsi:nil="true"
和其他属性值的元素;参见 Xsi:nil Attribute Binding Support: The nil attribute and other attributes。
因此,您需要手动发出属性。
如果您希望能够生成一个没有内容和两个属性的元素,一个名为 NV
,另一个 always 为 xsi:nil="true"
,您可以修改您的 testTag01
class 以获得 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
//
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"
和内容的元素将违反 XML standard;希望您没有。)
然后像这样使用它:
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>
原型 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();
}
}
}
正如预期的那样,没有开箱即用的解决方案,所以我即兴发挥了一下,在 post 处理逻辑中实现了我的目标。
我正在解析生成的 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");
上面的答案完全有道理,但由于这些 类 是自动生成的,我将按照我的方式处理 post,因为如果提供商更改 XSD架构,我的解决方案不需要任何额外的工作。还是谢谢了。
我有一堆 C# classes,它们是从 XSD 自动生成的。然后我根据那些 C# classes 生成 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" />
。
所以我不知道如何获得验证工具所需的格式。有什么想法吗?
P.S.
这是自动生成的 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; } } }
我不想改变那部分,但我知道不做是不可能的。我也尝试将 SomeEnum 设置为 Nullable。 public SomeEnum? Value
,但抛出异常:
Cannot serialize member 'Value' of type System.Nullable`1[]. XmlAttribute/XmlText cannot be used to encode complex types.
XmlSerializer
不直接支持绑定到同时具有 xsi:nil="true"
和其他属性值的元素;参见 Xsi:nil Attribute Binding Support: The nil attribute and other attributes。
因此,您需要手动发出属性。
如果您希望能够生成一个没有内容和两个属性的元素,一个名为 NV
,另一个 always 为 xsi:nil="true"
,您可以修改您的 testTag01
class 以获得 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
//
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"
和内容的元素将违反 XML standard;希望您没有。)
然后像这样使用它:
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>
原型 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();
}
}
}
正如预期的那样,没有开箱即用的解决方案,所以我即兴发挥了一下,在 post 处理逻辑中实现了我的目标。
我正在解析生成的 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");
上面的答案完全有道理,但由于这些 类 是自动生成的,我将按照我的方式处理 post,因为如果提供商更改 XSD架构,我的解决方案不需要任何额外的工作。还是谢谢了。