2

I have a problem. In my Xamarin Forms app I do a webcall to my webpage, where I collect XML to use in the app. I parse the XML to 3 different Lists.

  1. Albums
  2. Images
  3. Formats

Now here is what my xml looks like:

<Data>
    <Albums>
        <Album>
            <Image></Image>
            <Image></Image>
            <Image></Image>
        </Album>
        <Album>
            <Image></Image>
            <Image></Image>
        </Album>
    </Albums>
    <Images>
        <Image></Image>
        <Image></Image>
        <Image></Image>
        <Image></Image>
    </Images>
    <Formats>
        <Format></Format>
        <Format></Format>
    </Formats>
</Data>

After parsing it, the wanted result is:

lstAlbums.Count = 2
lstImages.Count = 4
lstFormats.Count = 2

But apparently it counts all the <> tags in the full xml, so lstImages has a count of 9, because 5 from the albums and 4 from the <Images>

Here is my c# code:

if (!string.IsNullOrEmpty(xmlString))
{
    doc = XDocument.Parse(xmlString);
}

//Check if xml has any elements 
if (!string.IsNullOrEmpty(xmlString) && doc.Root.Elements().Any())
{
    App.lstAlbums = doc.Descendants("Albums").Descendants("Album").Select(d =>
    new Album
    {
        Id = Convert.ToInt32(d.Element("Id").Value),
        Name = d.Element("Name").Value,
        Images = doc.Descendants("Album").Descendants("Image").Select(a =>
            new myImage
            {
                Id = Convert.ToInt32(a.Element("Id").Value),
                Name = a.Element("Name").Value,
                Size = a.Element("Size").Value,
                Price = Convert.ToDecimal(a.Element("Price").Value)
            }).ToList(),
        Prijs = Convert.ToDecimal(d.Element("Price").Value)
    }).ToList();

    App.lstImages = doc.Descendants("Images").Descendants("Image").Select(e =>
    new myImage
    {
        Id = Convert.ToInt32(e.Element("Id").Value),
        Name = e.Element("Name").Value
    }).ToList();

    App.lstFormats = doc.Descendants("Formats").Descendants("Format").Select(e =>
    new Format
    {
        Id = Convert.ToInt32(e.Element("Id").Value),
        Size = e.Element("Size").Value,
        Price = Convert.ToDecimal(e.Element("Price").Value)
    }).ToList();
}

How can I fix this?

3
  • 1
    The Descendents method is recursive; if you only intend to look one level, use Elements instead, but frankly this looks like a good fit for XmlSerializer instead of manual parsing. Commented Jan 30, 2020 at 18:59
  • Can you provide me with an example code for one of my lists, for example Albums? Commented Jan 30, 2020 at 19:00
  • 2
    I'd deserialise this, manual parsing is just a lot of code that already exists. Commented Jan 30, 2020 at 19:14

2 Answers 2

4

Frankly, this is a job for XmlSerializer. The following should work:

[XmlRoot("Data")]
public class MyData {
    [XmlArray("Albums")]
    [XmlArrayItem("Album")]
    public List<Album> Albums {get;} = new List<Album>();

    [XmlArray("Images")]
    [XmlArrayItem("Image")]
    public List<string> Images {get;} = new List<string>();

    [XmlArray("Formats")]
    [XmlArrayItem("Format")]
    public List<string> Formats {get;} = new List<string>();
}

public class Album {
    [XmlElement("Image")]
    public List<string> Images {get;} = new List<string>();
}

usage:

var serializer = new XmlSerializer(typeof(MyData));
var obj = (MyData)serializer.Deserialize(source);

And if your real xml is more complex: just copy the xml into the clipboard, and edit => paste special => paste xml as classes

(there are also sites/tools that let you convert your xml to c# code, of varying quality - for example https://xmltocsharp.azurewebsites.net/, but note that this doesn't do a great job around the arrays etc)

Sign up to request clarification or add additional context in comments.

9 Comments

Okay, I added your code, but it crashes on this line: var serializer = new XmlSerializer(typeof(MyData)); with the error: System.InvalidOperationException: 'There was an error reflecting type 'MyApp.Models.MyData'.'
@A.Vreeswijk and what does the inner-exception say? it is usually pretty chatty about what the problem is
@A.Vreeswijk also: works fine here - did you perhaps change the accessibility? gist.github.com/mgravell/0180b1b46eb4388b3aa733c5aee1afd3
I think why I get this error. I did a few changes, because your code wasn't complete for my code. I need to add the classes: Image and Format. You already added Album. Can you please update your code with the following classes, so I can see what I did wrong: Album => Id, Name, List<Image> Images --- Image => Id, Name, Price --- Format => Id, Size
|
-1

Try using xPath.

Something like

(IEnumerable)doc.XPathEvaluate("//Albums/Album")

and

(IEnumerable)doc.XPathEvaluate("//Images/Image")

2 Comments

And how can I assign that to my Lists?
iterate over the IEnumerable (or select from it). You'll want to cast each item in the IEnumerable to an XElement (because you have knowledge of what the XML structure is). Then extract the attributes from the XElement. XElement has Attribute and Attributes methods. XmlSerializer could be a better option, but this should be an easy swap for the code you alread have.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.