在.NET中纠正“混合”类型的XML序列化和反序列化

我当前的任务涉及编写用于处理HL7 CDA文件的类库。
这些HL7 CDA文件是具有已定义XML模式的XML文件,因此我使用xsd.exe生成用于XML序列化和反序列化的.NET类。

XML Schema包含各种类型,其中包含mixed =“true”属性 ,指定此类型的XML节点可能包含与其他XML节点混合的普通文本。
其中一种类型的XML模式的相关部分如下所示:

             

生成的此类型代码如下所示:

 ///  [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(TypeName="StrucDoc.Paragraph", Namespace="urn:hl7-org:v3")] public partial class StrucDocParagraph { private StrucDocCaption captionField; private object[] itemsField; private string[] textField; private string idField; // ...fields for other attributes... ///  public StrucDocCaption caption { get { return this.captionField; } set { this.captionField = value; } } ///  [System.Xml.Serialization.XmlElementAttribute("br", typeof(StrucDocBr))] [System.Xml.Serialization.XmlElementAttribute("sub", typeof(StrucDocSub))] [System.Xml.Serialization.XmlElementAttribute("sup", typeof(StrucDocSup))] // ...other possible nodes... public object[] Items { get { return this.itemsField; } set { this.itemsField = value; } } ///  [System.Xml.Serialization.XmlTextAttribute()] public string[] Text { get { return this.textField; } set { this.textField = value; } } ///  [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] public string ID { get { return this.idField; } set { this.idField = value; } } // ...properties for other attributes... } 

如果我反序列化段落节点如下所示的XML元素:

 first line

third line

结果是项目和文本数组的读取方式如下:

 itemsField = new object[] { new StrucDocBr(), new StrucDocBr(), }; textField = new string[] { "first line", "third line", }; 

由此无法确定文本和其他节点的确切顺序。
如果我再次序列化 ,结果看起来如下:

  

first linethird line

默认的序列化程序只是首先序列化项目,然后是文本。

我尝试在StrucDocParagraph类上实现IXmlSerializable ,以便我可以控制内容的反序列化和序列化,但它相当复杂,因为涉及的类很多,我还没有找到解决方案,因为我不知道是否努力得到回报。

是否有某种简单的解决方法解决这个问题,或者甚至可以通过IXmlSerializable进行自定义序列化? 或者我应该只使用XmlDocumentXmlReader / XmlWriter来处理这些文档?

要解决这个问题,我不得不修改生成的类:

  1. XmlTextAttributeText属性移动到Items属性并添加参数Type = typeof(string)
  2. 删除Text属性
  3. 删除textField字段

结果生成的代码(已修改)如下所示:

 ///  [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(TypeName="StrucDoc.Paragraph", Namespace="urn:hl7-org:v3")] public partial class StrucDocParagraph { private StrucDocCaption captionField; private object[] itemsField; private string idField; // ...fields for other attributes... ///  public StrucDocCaption caption { get { return this.captionField; } set { this.captionField = value; } } ///  [System.Xml.Serialization.XmlElementAttribute("br", typeof(StrucDocBr))] [System.Xml.Serialization.XmlElementAttribute("sub", typeof(StrucDocSub))] [System.Xml.Serialization.XmlElementAttribute("sup", typeof(StrucDocSup))] // ...other possible nodes... [System.Xml.Serialization.XmlTextAttribute(typeof(string))] public object[] Items { get { return this.itemsField; } set { this.itemsField = value; } } ///  [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] public string ID { get { return this.idField; } set { this.idField = value; } } // ...properties for other attributes... } 

现在,如果我反序列化段落节点如下所示的XML元素:

 first line

third line

结果是项目数组的读取方式如下:

 itemsField = new object[] { "first line", new StrucDocBr(), new StrucDocBr(), "third line", }; 

正是我需要的 ,项目的顺序和内容是正确的
如果我再次序列化 ,结果再次正确:

 first line

third line

让我指向正确方向的是Guillaume的答案,我也认为必须这样。 然后在MSDN文档中有这个到XmlTextAttribute

您可以将XmlTextAttribute应用于返回字符串数组的字段或属性。 您还可以将该属性应用于Object类型的数组,但必须将Type属性设置为string。 在这种情况下,插入到数组中的任何字符串都被序列化为XML文本。

所以序列化和反序列化工作现在正确,但我不知道是否还有其他副作用。 也许不可能再用xsd.exe从这些类生成一个模式,但我还是不需要它。

我有同样的问题,并遇到了改变xsd.exe生成的.cs的解决方案。 虽然它确实有效,但我对改变生成的代码感到不舒服,因为我需要记住在重新生成类的任何时候都要这样做。 它还导致了一些尴尬的代码,必须为mailto元素测试并转换为XmlNode []。

我的解决方案是重新考虑xsd。 我放弃了混合型的使用,基本上定义了我自己的混合型。

我有这个

 XML: some text me@email.comsome more text      

并改为

 XML: some text me@email.comsome more text                     

我生成的代码现在给了我一个myText类:

 public partial class myText{ private object[] itemsField; ///  [System.Xml.Serialization.XmlElementAttribute("mailto", typeof(myTextTextMailto))] [System.Xml.Serialization.XmlElementAttribute("text", typeof(myTextText))] public object[] Items { get { return this.itemsField; } set { this.itemsField = value; } } } 

现在,在serilization / deserialisation中保留了元素的顺序,但是我必须针对myTextTextMailtomyTextText类型测试/ cast to / program。

我以为我会把它作为替代方法,对我有用。

关于什么

 itemsField = new object[] { "first line", new StrucDocBr(), new StrucDocBr(), "third line", };