18

I have a single XElement looking like this:

<row flag="1" sect="" header="" body="" extrainfo="0" />

Then I have a class looking like this:

public class ProductAttribute
{
    public string Flag { get; set; }
    public string Sect { get; set; }
    public string Header { get; set; }
    public string Body { get; set; }
    public string Extrainfo { get; set; }
}

How can I convert this XElement into a ProductAttribute object?

Fedor
  • 1,548
  • 3
  • 28
  • 38
Numm3n
  • 1,021
  • 2
  • 9
  • 26

6 Answers6

19

You have to put the correct serialization attributes on your class and class members

[Serializable()]
[XmlRoot(ElementName = "row")]
public class ProductAttribute
{
    [XmlAttribute("flag")]
    public string Flag { get; set; }
    [XmlAttribute("sect")]
    public string Sect { get; set; }
    [XmlAttribute("header")]
    public string Header { get; set; }
    [XmlAttribute("body")]
    public string Body { get; set; }
    [XmlAttribute("extrainfo")]
    public string Extrainfo { get; set; }
}
jbl
  • 15,179
  • 3
  • 34
  • 101
  • 1
    Best solution so far, if it would work. But I get: `Attribute System.Xml.Serialization.XmlElementAttribute is not valid on this declaration type. It is valid on 'Property,Field,Parameter,ReturnValue' declarations only` – Numm3n Sep 04 '13 at 08:10
  • 1
    But what you don't explain / show is the actual conversion from `XElement` to `ABC`. – Andrew Truckle Jan 14 '22 at 06:02
14

You could do this way:

1) At first you should give attributes to the class:

[XmlRoot("row")]
public class ProductAttribute
{
    [XmlAttribute("flag")]
    public string Flag { get; set; }
    [XmlAttribute("sect")]
    public string Sect { get; set; }
    [XmlAttribute("header")]
    public string Header { get; set; }
    [XmlAttribute("body")]
    public string Body { get; set; }
    [XmlAttribute("extrainfo")]
    public string Extrainfo { get; set; }
}

2) Now you can deserialize your XElement or simple xml string like this:

ProductAttribute productAttribute = new ProductAttribute();
XElement xElement = XElement.Parse(
"<row flag='1' sect='3' header='4444' body='3434' extrainfo='0' />");

//StringReader reader = new StringReader(
//"<row flag='1' sect='3' header='4444' body='3434' extrainfo='0' />");

StringReader reader = new StringReader(xElement.ToString());
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ProductAttribute));
productAttribute = (ProductAttribute)xmlSerializer.Deserialize(reader);

I hope it helps you.

10

Have you tried:

XElement element = //Your XElement
var serializer = new XmlSerializer(typeof(ProductAttribute));
(ProductAttribute)serializer.Deserialize(element.CreateReader()) 
Alberto
  • 15,626
  • 9
  • 43
  • 56
  • Yes, I've tried but i only get: ` was not expected.` – Numm3n Sep 04 '13 at 08:03
  • You should put the correct serialization attributes on ProductAttribute class. Like XmlElement for the class and XmlAttribute for each property. – Alberto Sep 04 '13 at 08:09
  • Thanks. But I'm not allowed to put `[XmlElement("row")]` on the class. `Attribute System.Xml.Serialization.XmlElementAttribute is not valid on this declaration type. It is valid on 'Property,Field,Parameter,ReturnValue' declarations only` – Numm3n Sep 04 '13 at 08:17
  • If you get ` was not expected` there is a solution here: https://stackoverflow.com/a/1557145/3059082 – Wildcat Matt Sep 03 '21 at 15:06
3

I would add a constructor that takes in a XElement.

public class ProductAttribute
{
    public string Flag { get; set; }
    public string Sect { get; set; }
    public string Header { get; set; }
    public string Body { get; set; }
    public string Extrainfo { get; set; }

    public ProductAttribute(XElement xElement){
        Flag = (string)element.Attribute("flag");
        Sect = (string)element.Attribute("sect").Value;
        Header = (string)element.Attribute("header ").Value;
        Body = (string)element.Attribute("body").Value;
        Extrainfo = (string)element.Attribute("extrainfo").Value;
    }
}

Then you can just call

var productAttribute = new ProductAttribute(element);

If you wanted to make that dynamic you could use reflection get the properties on the class then loop over then and searching the XElement for that attribute then setting that property much in the same way. However I would keep it simple as the object is not complex.

Rob
  • 1,071
  • 8
  • 10
2

This seems fairly easy (at least without error checking...):

var res = new ProdicAttribute {
  Flag = (string)element.Attribute("flag"),
  Sect = (string)element.Attribute("sect"),
  ...
}
Richard
  • 106,783
  • 21
  • 203
  • 265
  • 1
    This is manual mapping. But what if I have a XElement with 200 attributes? I was hoping that C#/.net would have a simpler solution – Numm3n Sep 04 '13 at 08:05
  • Getting the XML serialisation attributes right is non-trivial (and I find it error prone)... I don't see this as any more work. Plus it helps with separation of concerns :-). – Richard Sep 04 '13 at 08:38
0
var element = XElement.Parse("<row flag="1" sect="" header="" body="" extrainfo="0" />");

var productAttribute = new ProductAttribute {
    Flag = (string)element.Attribute("flag"),
    Sect = (string)element.Attribute("sect"),
    Header = (string)element.Attribute("header"),
    Body = (string)element.Attribute("body"),
    Extrainfo = (string)element.Attribute("extrainfo")
};

But I don't think all ProductAttribute class properties should be typed as string.

MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263