1

Is it possible to store the original XML element in a C# class, for example?

Original XML:

 <data someattributea="" someattributeb="" someattributec="" />

C#

using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
    [XmlRoot(ElementName="data")]
    public class Data {
        [XmlAttribute(AttributeName="someattributea")]
        public string Someattributea { get; set; }
        [XmlAttribute(AttributeName="someattributeb")]
        public string Someattributeb { get; set; }
        [XmlAttribute(AttributeName="someattributec")]
        public string Someattributec { get; set; }

        public sourceXML { get; set; }    //this would return <data someattributea="" someattributeb="" someattributec="" />

    }

}

I understand I could deserialize the class again but some XML objects are unknown at design time.

dbc
  • 104,963
  • 20
  • 228
  • 340
RapMaster
  • 21
  • 3
  • There are already a couple questions and answers about this, see [How do I use XmlSerializer to insert an xml string](https://stackoverflow.com/q/1061027/3744182) and [C# - XML - Treat inner xml from a certain element as string](https://stackoverflow.com/q/7534955/3744182). – dbc May 12 '18 at 08:37
  • Do those two answers work for you, or do you need additional help? – dbc May 12 '18 at 08:42
  • Not really, those are using Elements when I need to use Attribute. XmlAnyAttribute does work however (List of Attribute value/name) however you can mixed name Attributes and XmlAnyAttributes in the same class. – RapMaster May 12 '18 at 11:40
  • Right. Duplicate of [XmlSerializer equivalent of IExtensibleDataObject](https://stackoverflow.com/q/2511298/3744182) then, or need more help? – dbc May 12 '18 at 16:53

1 Answers1

0

If you really need to capture everything about the <data /> element including the element name and namespace itself into a string literal, you will need to implement IXmlSerializable and serialize your Data type manually. For instance, here is a prototype implementation:

[XmlRoot(ElementName = ElementName)]
public class Data : IXmlSerializable
{
    public const string ElementName = "data";

    XElement element = new XElement((XName)ElementName);

    public string Someattributea
    {
        get { return (string)element.Attribute("someattributea"); }
        set { element.SetAttribute("someattributea", value); }
    }

    public string Someattributeb
    {
        get { return (string)element.Attribute("someattributeb"); }
        set { element.SetAttribute("someattributeb", value); }
    }

    public string Someattributec
    {
        get { return (string)element.Attribute("someattributec"); }
        set { element.SetAttribute("someattributec", value); }
    }

    public string SourceXML
    {
        get
        {
            return element.ToString();
        }
        set
        {
            if (value == null)
                throw new ArgumentNullException();
            element = XElement.Parse(value);
        }
    }

    #region IXmlSerializable Members

    public XmlSchema GetSchema() { return null; }

    public void ReadXml(XmlReader reader)
    {
        reader.MoveToContent();
        element = (XElement)XNode.ReadFrom(reader);
    }

    public void WriteXml(XmlWriter writer)
    {
        foreach (var attr in element.Attributes())
            writer.WriteAttributeString(attr.Name.LocalName, attr.Name.NamespaceName, attr.Value);
        foreach (var child in element.Elements())
            child.WriteTo(writer);
    }

    #endregion
}

public static class XElementExtensions
{
    public static void SetAttribute(this XElement element, XName attributeName, string value)
    {
        var attr = element.Attribute(attributeName);
        if (value == null)
        {
            if (attr != null)
                attr.Remove();
        }
        else
        {
            if (attr == null)
                element.Add(new XAttribute(attributeName, value));
            else
                attr.Value = value;
        }
    }
}

Notes:

Working .Net fiddle here.

If, on the other hand, you only need to capture unknown elements, attributes and text content, you can use [XmlAnyAttribute], [XmlAnyElement] and [XmlText] (the first two of which are suggested in this answer to XmlSerializer equivalent of IExtensibleDataObject by Marc Gravell). This approach results in a much simpler version of Data:

[XmlRoot(ElementName = "data")]
public class Data
{
    [XmlAttribute(AttributeName = "someattributea")]
    public string Someattributea { get; set; }
    [XmlAttribute(AttributeName = "someattributeb")]
    public string Someattributeb { get; set; }
    [XmlAttribute(AttributeName = "someattributec")]
    public string Someattributec { get; set; }

    [XmlAnyAttribute]
    public XmlAttribute[] Attributes { get; set; }

    [XmlAnyElement]
    [XmlText] // Captures mixed content at the root level as well as child elements.
    public XmlNode[] ChildNodes { get; set; }
}

Working .Net fiddle #2 here.

dbc
  • 104,963
  • 20
  • 228
  • 340