Проблема .NET Serialize XmlNode - PullRequest
3 голосов
/ 07 января 2010

Итак, я пытаюсь просто декорировать класс, чтобы сериализовать его как XML. Вот пример моей проблемы.

[XmlElement("Dest")]
    public XmlNode NewValue { get; set; }

Реальная проблема здесь в том, что иногда в этой реализации XmlNode может быть XmlElement или XmlAttribute. когда это элемент, этот код работает нормально, но когда он становится атрибутом, сериализатор выдает следующую ошибку:

System.InvalidOperationException: невозможно записать узел типа XmlAttribute в качестве значения элемента. Используйте XmlAnyAttributeAttribute с массивом XmlNode или XmlAttribute для записи узла в качестве атрибута.

Я попробовал XmlAnyAttribute, но и это не удалось. Проще говоря, как я могу сериализовать XmlNode?

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

    [XmlIgnore()]
    public XmlNode OldValue { get; set; }

    [XmlElement("Dest")]
    public XmlNode SerializedValue
    {
        get
        {
            if (OldValue == null)
            {
                return null;
            }
            if (OldValue.NodeType == XmlNodeType.Attribute)
            {
                XmlDocumentFragment frag = OldValue.OwnerDocument.CreateDocumentFragment();

                XmlElement elem = (frag.OwnerDocument.CreateNode(XmlNodeType.Element, "SerializedAttribute", frag.NamespaceURI) as XmlElement);

                elem.SetAttribute(OldValue.Name, OldValue.Value);

                return elem;
            }
            else
            {
                return OldValue;
            }
        }
        set
        {
            if (value == null)
            {
                OldValue = null;
                return;
            }
            if ((value.Attributes != null) && (value.NodeType == XmlNodeType.Element) && ((value.ChildNodes == null) || (value.ChildNodes.Count == 0)))
            {
                OldValue = value.Attributes[0];
            }
            else
            {
                OldValue = value;
            }
        }
    }

Ответы [ 3 ]

1 голос
/ 07 января 2010

Вы можете попытаться взломать его (я согласен, это не очень приятно):

XmlNode v;

[XmlElement("Dest")]
public XmlNode NewValue { get{return v as XmlElement;} set{v = value;} }

[XmlAttribute("Dest")]
public NewValue { get{return v as XmlAttribute;} set{v = value;} }
1 голос
/ 07 января 2010

Кажется странным, что вы смешиваете сериализацию Xml с узлами Xml и, как вы сказали, этот узел может быть атрибутом или элементом. Обычно вы бы сериализовали XmlNode как часть XmlDocument, используя функции XmlDocument.Save ().

Я думаю, что может быть проще сериализовать XmlNode в виде строки. Может быть, что-то вроде этого:

[XmlIgnore]
public XmlNode NewValue { get; set; }

[XmlElement("Dest")]
public string NewValueString { get; set; }
{ 
    get { return NewValue.OuterXml; } // Edit: this property can't directly
    set { NewValue.OuterXml = value; } // set OuterXml
}

Массивная правка:

На секунду подумал ....

Вы смешиваете два разных способа работы с Xml, и нет прямого способа заставить это работать.

Нельзя использовать сериализацию Xml со свойством типа XmlNode или XmlAttribute или XmlElement. XmlNode и его подклассы не имеют открытого конструктора без параметров, необходимого для сериализации Xml. Они могут быть созданы только через XmlDocument. Кроме того, сериализация Xml работает путем отражения и сохранения всех общедоступных свойств get / set, а XmlNode и подклассы не имеют свойств, предназначенных для этого.

Вы по-прежнему можете сериализовать XmlNode в виде строки (вы просто не можете реализовать ее напрямую, как показано выше), затем вам придется выполнить некоторый шаг постобработки после десериализации xml, чтобы воссоздать XmlNode.

Но опять же, вы смешиваете два разных способа работы с Xml, и это вызывает у меня некоторые предупреждающие флажки.

0 голосов
/ 07 января 2010

Поскольку вы не можете смешивать и сопоставлять с механизмами по умолчанию, вам, скорее всего, потребуется написать свой собственный сериализатор. Сделав это, вы можете переключить свой код для экспорта / импорта данных так, как вам нужно, с помощью логических операторов вокруг вашего объекта.

...