Deserialize Xml и получить его версию строки за один раз [дубликат]

Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.

Пример:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Вы можно просто избежать этого, проверив, является ли переменная не нулевой:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .

Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!

Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • string

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей запятой
  • decimal
  • bool
  • Пользовательские структуры

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

3 ответа

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

  1. Перенесите XmlTextAttribute из свойства Text в свойство 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>

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

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

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

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

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

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

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

22
ответ дан Stefan 28 August 2018 в 01:21
поделиться
  • 1
    Это больше не работает (моя версия System.Xml 4.0.0). Проблема заключается в том, что он отслеживает имена элементов в массиве Items через массив строк ItemsElementName, и элементы должны соответствовать 1-к-1. Это требование вызывает ошибку, если вы работаете с объектной моделью, которую вы заполнили путем десериализации XML-документа, потому что XMLSerializer не помещает репрезентативные записи в массив ItemsElementName. Таким образом, текстовый узел, за которым следует элемент xml, за которым следует текстовый узел, приводит к 3 записям в вашем массиве Items, но только 1 в ItemElementName. – shahzbot 30 October 2017 в 21:25
  • 2
    Спасибо, у меня была такая же проблема с схемой CDL HL7, и это сработало отлично :) – user544511 14 May 2018 в 11:52

У меня была та же проблема, что и у этого, и натолкнулся на это решение изменения .cs, сгенерированного xsd.exe. Хотя это действительно сработало, мне было неудобно изменять сгенерированный код, так как мне нужно было бы это делать, когда я восстанавливал классы. Это также привело к некоторому неудобному коду, который должен был протестировать и передать в XmlNode [] для элементов mailto.

Моим решением было переосмыслить 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;
        }
    }
}

порядок элементов теперь сохраняется в сериализации / десериализации, но мне нужно проверить / cast to / program на типы myTextTextMailto и myTextText.

Просто подумал, что я брошу это как альтернативный подход, который работал для меня.

3
ответ дан Feenster 28 August 2018 в 01:21
поделиться
  • 1
    Я согласен с тем, что ваш подход является предпочтительным решением этой проблемы для тех, кто определяет и использует свою собственную XML-схему. Моя проблема заключалась в том, что у меня не было возможности изменить XSD, потому что он контролировался третьей стороной. Поэтому мне пришлось модифицировать сгенерированные классы, которые по причинам, которые вы указали, должны быть выполнены только в том случае, если нет другого пути. – Stefan 25 March 2011 в 09:04

Как насчет

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

?

0
ответ дан Guillaume 28 August 2018 в 01:21
поделиться
  • 1
    Это приводит к исключению InvalidOperationException при попытке сериализации объекта (из-за строк внутри элементов ItemsField, arrayField может содержать только объекты тех типов, которые задаются атрибутами [XmlElement] для публичных объектов «Элементы»). – Stefan 6 April 2010 в 07:37
  • 2
    Вы можете найти помощь здесь: msdn.microsoft.com/en-us/library/kz8z99ds.aspx Любое предупреждение о проверке схемы? – Guillaume 6 April 2010 в 09:06
  • 3
    Я уже нашел эту страницу во время моих поисков, речь идет о другой проблеме. Схема моих документов xml верна, я проверяю ее как перед десериализацией, так и после сериализации. Но сейчас я нашел ответ на свою проблему, ваше предложение с массивом itemsField было уже близко, для этого потребовались дополнительные изменения в сгенерированном коде. Я отправлю его через несколько минут. – Stefan 6 April 2010 в 10:09
Другие вопросы по тегам:

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