1

Had a quick question: am currently trying to learn how to work with XML files and wanted to run a question by you:

I have run into a bit of an issue that I could certainly use some help with. I have created a simple little XML file (Users.XML) below:

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <users>
      <user>
        <firstname>Might</firstname>
        <lastname>Guy</lastname>
        <username>SomeUser</username>
      </user>
      <user>
        <firstname>Bob</firstname>
        <lastname>Marley</lastname>
        <username>BobMarley</username>
      </user>       
    </users>

What I want to do is find a way to query that file to get specific information about a user. First name, last name, doesn't matter. Now, after poking around I found what many folks considered to be one of the better ways is:

string firstName;

var data = from item in doc.Descendants("users")
                   where item.Element("user").Element("username").Value == "SomeUser"
                   select new
                   {
                       fname = item.Element("user").Element("firstname").Value
                   };

//Checking to see if anything was found. I know this isn't necessary to pull
//the information. I'm just doing this so I can know to throw an error to the
//screen if none is found
    if (data.Count() > 0)
//Now pull the data. Should only be 1 hit
        foreach (var p in data)
        {
            firstName = p.ToString();
        }
    else
        MessageBox.Show("No such user found");

Now, this example code does give me the first name of the user. BUT, the actual content of firstName is "fname = Might". All I want it to contain is "Might". Of course, if I drop the "fname =" from the select then it throws an error about not naming the field, so I sort of hit a wall. I tried googling for a solution, but since I'm not sure WHAT I'm googling it hasn't brought me much luck.

So I have 3 questions. If it would be easier just to point me in the direction of a tutorial that contains the information, I would also be thrilled with that! Not just looking for an easy fix, looking to figure out why this is how it is since I'm trying to learn XML and not just complete a task.

-A) Is it possible using this method to simply have firstName contain "Might", and not "fname = Might". If so, how? If not, is there another way to do it that would?

-B) Why do I need the "fname ="? Is this something to do with LINQ, or is it part of something else entirely? Besides LINQ/XML stuff, I haven't been able to find examples of this anywhere else yet so I haven't been able to get a more detailed explanation on why it is like it is.

-C) Is this an acceptable method to go about what I'm trying to do in the example, aka query an XML file for a specific piece of information based on some field (the username, in this case)? If not, could you point me towards whatever method might be better?

7
  • 1
    Side note: You should call FirstOrDefault(). Commented Jan 21, 2013 at 20:17
  • 1
    You might want to do some reading on anonymous types Commented Jan 21, 2013 at 20:22
  • 1
    "Might Guy"...is that a Naruto reference? Haha Commented Jan 21, 2013 at 20:24
  • @RobH I sure will! Thank you! Commented Jan 21, 2013 at 20:29
  • @P.Brian.Mackey haha yea it is. I considered naming the user "DynamicEntry" but decided not to =D Commented Jan 21, 2013 at 20:31

3 Answers 3

1

The problem here is that you're using p.ToString() instead of p.fname. How's this:

string firstName, lastName;

var data = from item in doc.Descendants("user")
           where item.Element("username").Value == "SomeUser"
           select new
           {
               fname = item.Element("firstname").Value,
               lname = item.Element("lastname").Value
           };

var p = data.FirstOrDefault();
if(p != null)
{
    firstName = p.fname;
    lastName = p.lname;
}
else
{
    MessageBox.Show("No such user found");
}

To answer your question B, you do not need to use the fname = syntax. If you only want one value, instead of:

   select new
   {
       fname = item.Element("firstname").Value,
   };

You could just use:

   select item.Element("firstname").Value;

The select new { key = value, key2 = value2 } syntax allows you to put several values into an object of an anonymous class, from which you can easily pull out the values you need, by name.

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

1 Comment

That's excellent! Thank you very much for your help. This is exactly the information that I needed, especially the answer for B.
1

Your select statement is a projection.

This is telling the compiler to create a new anonymous object that has one property - fname with the value of the attribute.

select new
{
  fname = item.Element("user").Element("firstname").Value
};

It is the almost the same as doing something like this - except the compiler does it automagically for you.

public class SomeObject
{
  public string fname { get; set; }
  public override ToString()
  {
    return "fname = " + fname;
  }
}

var data = from item in doc.Descendants("users")
                   where item.Element("user").Element("username").Value == "SomeUser"
                   select new SomeObject { fname = item.Element("user").Element("firstname").Value }

Your foreach is then iterating over every element and calling toString on the object..

foreach (var p in data)
{
  firstName = p.ToString();
}

If you change your foreach to this it will fix the problem:

foreach (var p in data)
{
  firstName = p.fname;
}

1 Comment

Awesome! Thank you for that explanation of the "fname =". That clears it up wonderfully! I'm sure I overlooked it many times, but I had absolutely no luck finding an explanation close to that online haha. Thank you again!
1

Use:

var data = from item in doc.Descendants("users")
               where item.Element("username").Value == "SomeUser"
               select new
               {
                   fname = item.Element("firstname").Value
               };

var user = data.FirstOrDefault();
var firstName = user.fname;

You are getting "fname=Might", because you are calling ToString on whole anonymous object returned from the query. The anonymous object returned from the query actually has property called fname.

To your C) question: It is correct approach to read data from xml file with this LinqToXml ;-)

1 Comment

Thank you very much! Also glad to hear about C =D Every time I searched XML work I kept running into "User LINQ" for everything, so it became my goal to use it exclusively.

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.