簡體   English   中英

NET中正確的XML序列化和“混合”類型的反序列化

[英]Correct XML serialization and deserialization of “mixed” types in .NET

我當前的任務涉及編寫用於處理HL7 CDA文件的類庫。
這些HL7 CDA文件是具有定義的XML模式的XML文件,因此我使用xsd.exe生成.NET類以進行XML序列化和反序列化。

XML模式包含各種類型,這些類型包含mixed =“ true”屬性 ,該屬性指定此類型的XML節點可以包含與其他XML節點混合的普通文本。
這些類型之一的XML模式的相關部分如下所示:

<xs:complexType name="StrucDoc.Paragraph" mixed="true">
    <xs:sequence>
        <xs:element name="caption" type="StrucDoc.Caption" minOccurs="0"/>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="br" type="StrucDoc.Br"/>
            <xs:element name="sub" type="StrucDoc.Sub"/>
            <xs:element name="sup" type="StrucDoc.Sup"/>
            <!-- ...other possible nodes... -->
        </xs:choice>
    </xs:sequence>
    <xs:attribute name="ID" type="xs:ID"/>
    <!-- ...other attributes... -->
</xs:complexType>

為該類型生成的代碼如下所示:

/// <remarks/>
[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...

    /// <remarks/>
    public StrucDocCaption caption {
        get {
            return this.captionField;
        }
        set {
            this.captionField = value;
        }
    }

    /// <remarks/>
    [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;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string[] Text {
        get {
            return this.textField;
        }
        set {
            this.textField = value;
        }
    }

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

    // ...properties for other attributes...
}

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

<paragraph>first line<br /><br />third line</paragraph>

結果是像這樣讀取item和text數組:

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

由此無法確定文本和其他節點的確切順序。
如果我再次序列化它,結果將看起來完全像這樣:

<paragraph>
    <br />
    <br />first linethird line
</paragraph>

默認的序列化程序只會先序列化項目,然后再序列化文本。

我嘗試在StrucDocParagraph類上實現IXmlSerializable ,以便可以控制內容的反序列化和序列化,但是由於涉及的類太多,而且還沒有找到解決方案,因為它不知道是否存在,所以它相當復雜。努力得到回報。

是否有某種簡單的解決方法解決此問題,或者是否有可能通過IXmlSerializable執行自定義序列化? 還是應該只使用XmlDocumentXmlReader / XmlWriter處理這些文檔?

為了解決這個問題,我不得不修改生成的類:

  1. XmlTextAttributeText屬性移到Items屬性,然后添加參數Type = typeof(string)
  2. 刪除Text屬性
  3. 刪除textField字段

結果, 生成的代碼(已修改)如下所示:

/// <remarks/>
[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...

    /// <remarks/>
    public StrucDocCaption caption {
        get {
            return this.captionField;
        }
        set {
            this.captionField = value;
        }
    }

    /// <remarks/>
    [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;
        }
    }

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

    // ...properties for other attributes...
}

現在,如果我反序列化段落節點如下所示的XML元素:

<paragraph>first line<br /><br />third line</paragraph>

結果是像這樣讀取item數組:

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

正是我所需要的 ,項目的順序及其內容是正確的
如果我再次序列化此結果,則結果再次正確:

<paragraph>first line<br /><br />third line</paragraph>

正確的方向指向我的就是紀堯姆(Guillaume)的答案,我還認為這樣做一定是可能的。 然后在MSDN文檔中有XmlTextAttribute

您可以將XmlTextAttribute應用於返回字符串數組的字段或屬性。 您也可以將屬性應用於Object類型的數組,但是必須將Type屬性設置為string。 在這種情況下,插入到數組中的所有字符串都將序列化為XML文本。

因此,序列化和反序列化現在可以正常工作,但是我不知道是否還有其他副作用。 也許不可能再使用xsd.exe從這些類中生成模式了,但是我還是不需要它。

我遇到了同樣的問題,並遇到了更改xsd.exe生成的.cs的解決方案。 盡管它確實有效,但是我對修改生成的代碼並不滿意,因為我需要在每次重新生成類時記住這樣做。 這也導致了一些尷尬的代碼,這些代碼必須測試並強制轉換為mailto元素的XmlNode []。

我的解決方案是重新考慮xsd。 我放棄了使用混合類型,並本質上定義了我自己的混合類型。

我有這個

XML: <text>some text <mailto>me@email.com</mailto>some more text</text>

<xs:complexType name="text" mixed="true">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="mailto" type="xs:string" />
    </xs:sequence>
  </xs:complexType>

並更改為

XML: <mytext><text>some text </text><mailto>me@email.com</mailto><text>some more text</text></mytext>

<xs:complexType name="mytext">
    <xs:sequence>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="text">
          <xs:complexType>
            <xs:simpleContent>
              <xs:extension base="xs:string" />
            </xs:simpleContent>
          </xs:complexType>
        </xs:element>
        <xs:element name="mailto">
          <xs:complexType>
            <xs:simpleContent>
              <xs:extension base="xs:string" />
            </xs:simpleContent>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:sequence>
  </xs:complexType>

現在,我生成的代碼為我提供了一個myText類:

public partial class myText{

    private object[] itemsField;

    /// <remarks/>
    [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;
        }
    }
}

元素的順序現在保留在序列化/反序列化中,但是我必須針對myTextTextMailtomyTextText類型進行測試/ myTextTextMailto轉換/編程。

只是以為我會將它作為對我有用的替代方法。

關於什么

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM