Корректная сериализация XML и десериализация “смешанных” типов в.NET

Моя текущая задача включает запись библиотеки классов для обработки файлов HL7 CDA.
Эти файлы HL7 CDA являются XML-файлами с определенной XML-схемой, таким образом, я использовал xsd.exe для генерации классов.NET для сериализации XML и десериализации.

XML-схема содержит различные типы, которые содержат смешанное = "истинный" атрибут, указывая, что узел 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>

Результат состоит в том, что объект и текстовые массивы читаются как это:

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

От этого нет никакого возможного способа определить точный порядок текста и других узлов.
Если я сериализирую это снова, результат точно походит на это:

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

Сериализатор по умолчанию просто сериализирует объекты сначала и затем текст.

Я пытался реализовать IXmlSerializable на классе StrucDocParagraph так, чтобы я мог управлять десериализацией и сериализацией содержания, но это довольно сложно с тех пор, существует столько включенных классов, и я еще не пришел к решению, потому что я не знаю, окупается ли усилие.

Есть ли некоторое легкое обходное решение к этой проблеме или она даже возможный путем выполнения пользовательской сериализации через IXmlSerializable? Или если я просто использую XmlDocument или XmlReader/XmlWriter обработать эти документы?

18
задан Stefan Podskubka 2 April 2010 в 15:16
поделиться

2 ответа

Чтобы решить эту проблему, мне пришлось изменить сгенерированные классы:

  1. Переместите XmlTextAttribute из Text ] к свойству Items и добавьте параметр Type = typeof (string)
  2. Удалите свойство Text
  3. Удалите textField field

В результате сгенерированный код (измененный) выглядит следующим образом:

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

результат состоит в том, что массив элементов читается следующим образом:

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

Это именно то, что мне нужно , порядок элементов и их содержимого правильный .
И если я сериализую это снова, результат снова будет правильным:

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

В правильном направлении меня указал ответ Гийома, я также подумал, что это должно быть возможно вот так. А затем в документации MSDN к XmlTextAttribute :

Вы можете применить XmlTextAttribute к полю или свойству, которое возвращает {{ 1}} массив строк. Вы также можете применить атрибут к массиву типа Object, но вы должны установить для свойства Type значение string.В этом случае любые строки , вставленные в массив, сериализуются как текст XML.

Итак, сериализация и десериализация сейчас работают правильно, но я не знаю, есть ли другие побочные эффекты. Возможно, с помощью xsd.exe больше невозможно сгенерировать схему из этих классов, но мне это все равно не нужно.

22
ответ дан 30 November 2019 в 08:32
поделиться

А как насчет

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

?

0
ответ дан 30 November 2019 в 08:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: