We help IT Professionals succeed at work.

Read/Write/Parse XML custom settings file

gjok
gjok asked
on
296 Views
Last Modified: 2010-05-18
Hi
I need some advice on storing and retreiving XML data for my Windows Appliction.
Ive not used XML before, and am not familiar with the existing .NET assemblies. There are plenty of good examples out there, but they all seem to be for data made up of the common elements, such as Title, Author, Publisher.

The elements in my data could be different from each other, for example:

<Element>
  <Field key="Type" value="A">
  <Field key="StartDate" value="01/01/2007">
  <Field key="ReviewDate" value="21/11/2008">
</Element>
<Element>
  <Field key="Type" value="B">
  <Field key="Text" value="Lorem ipsum dolor sit amet, consectetuer adipiscing elit.">
</Element>
<Element>
  <Field key="Type" value="C">
  <Field key="Image" value="E:\data\graphics\graph22.jpg.">
  <Field key="Height" value="240">
  <Field key="Width" value="400">
</Element>

Each element corresponds to a class. The keys represent properties of the class. Class A,B and C will have different properties.

I need to read in the XML and create an instance of the relevant class, and assign the XML data, like this:

MyClassA Apples = new MyClassA();
Apples.StartDate = [XML Data]; // 01/01/2007
Apples.ReviewDate = [XML Data]; // 21/11/2008

MyClassB Bananas= new MyClassB();
Bananas.Text = [XML Data]; // Lorem ipsum dolor...

Please help!!
Comment
Watch Question

CERTIFIED EXPERT

Commented:
public class MyClassA
      {
            public MyClassA()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }
            private string _type;
            private DateTime _startdate;
            private DateTime _reviewdate;
      
   
            public MyClassA(string Type, DateTime StartDate, DatTime ReviewDate)
            {
                  _type=Type;
                  _startdate=StartDate;
                  _reviewdate=ReviewDate;
            }

            public int Type
            {
                  get { return _type; }
                  set { _type = value; }
            }
            public string StartDate
            {
                  get { return _startdate; }
                  set { _startdate = value; }
            }
            public int ReviewDate
            {
                  get { return _reviewdate; }
                  set { _reviewdate = value; }
            }
            
            public override string ToString()
            {
                  return _type;
            }
      }
CERTIFIED EXPERT

Commented:
public MyClassA()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }
            private string _type;
            private DateTime _startdate;
            private DateTime _reviewdate;
            private string _text;
            private string _image;
            private int _height;
            private int _width;
   
            public MyClassA(string Type, DateTime StartDate, DatTime ReviewDate)
            {
                  _type=Type;
                  _startdate=StartDate;
                  _reviewdate=ReviewDate;
            }

            public int Type
            {
                  get { return _type; }
                  set { _type = value; }
            }
            public string StartDate
            {
                  get { return _startdate; }
                  set { _startdate = value; }
            }
            public int ReviewDate
            {
                  get { return _reviewdate; }
                  set { _reviewdate = value; }
            }
            
            public override string ToString()
            {
                  return _type;
            }
      }

      public class MyClassB
      {
            public MyClassB()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }
            public MyClassB(string Type, string Text)
            {
                  _type=Type;
                  _text=Text;
            }

            public int Type
            {
                  get { return _type; }
                  set { _type = value; }
            }
            public string Text
            {
                  get { return _text; }
                  set { _text = value; }
            }
            
            public override string ToString()
            {
                  return _type;
            }
      }

      public class MyClassC
      {
            public MyClassC()
            {
                  //
                  // TODO: Add constructor logic here
                  //
            }
            public MyClassC(string Type, string Img, int Height, int Width)
            {
                  _type=Type;
                  _image=Img;
                  _height=Height;
                  _width=Width;
            }

            public int Type
            {
                  get { return _type; }
                  set { _type = value; }
            }
            public string Img
            {
                  get { return _image; }
                  set { _image = value; }
            }
            public string Height
            {
                  get { return _height; }
                  set { _height = value; }
            }
            public string Width
            {
                  get { return _width; }
                  set { _width = value; }
            }
            
            public override string ToString()
            {
                  return _type;
            }
      }

Author

Commented:
The question was "Read/Write/Parse XML custom settings file" - The classes exist already!
I need help with reading & writing the XML!
IMHO that is a very bad XML schema; the tags and attributes don't actually mean anything, you have to understand the attribute values to understand what the element means. If you are able, use a schema like:

<task StartDate="01/01/2007"  ReviewDate="21/11/2008"/>
<description>Lorem ipsum dolor...</description>
<image src="E:\data\graphics\graph22.jpg." Height="240" Width"400" />

XML is supposed to be human-readable. Use tags that actually mean something to a person reading it. That is how XML is designed to be used.

You can use .Net XML classes for any schema. Which classes to use depends on what you want to do; do you need random access to the XML data? Will you be reading all the data in one pass and assigning instances as you go? How big will the XML files you use be? Kilobytes? Megabytes? Do you need to change the XML file as you use it?

Author

Commented:
I have answered my own question.

This link has some nice GetValue, SetValue and removeElement examples:
http://www.codeproject.com/csharp/xmlconfig.asp

Thanks YZlat. I appreciate your help, but I already have the classes in use (currently hard-coding the values). I may post a followup question to this. As I said, this is my first xml experience and so this is unknow territory.

Author

Commented:
Thanks photowhiz. I was about to close of this question, but Im glad I didnt.

The file will only have about 10 or so different elements (there are about 10 corresponding classes)
I want to read in the entire data when a project is loaded into the application, and assign the data values to the class properties there and then.
Likewise, there needs to be a 'save project' button that the user can click to run through all instances of the different classes and save the settings to XML in one go.
Random I/O access in not required.

Also thanks for the suggestion on the schema. In your example, is that one element? not sure how that would be nested - bearing in mind, not all elements share the same fields. However there could be 3 or 4 elements of the same  type.

[points still up for grabs]
Those were examples of three different elements based on your first example. You could make them into an XML file by putting them in a root element:

<?xml version="1.0"?>
<settings>
    <task StartDate="01/01/2007"  ReviewDate="21/11/2008"/>
    <description>Lorem ipsum dolor...</description>
    <image src="E:\data\graphics\graph22.jpg." Height="240" Width"400" />
</settings>

The point I am trying to make is that you should define your own tags and attributes to make the XML self-documenting. Tags like "Element" and "Field" don't mean anything.

If there are only going to be 10 or so elements, you might as well load the whole file into memory and pull out the elements and attributes you're interested in. You can do that with the System.Xml.XmlDocument class. You could even use the XML document directly and not bother with creating your own classes. There is a Microsoft support document giving an example of this at http://support.microsoft.com/kb/301233

Author

Commented:
Many thanks photowhiz.
Thanks for the example link. However, this is what I was talking about in my initial question. all the nodes are the same (all of type 'book'). Using this analogy, my xml file would have 1 book, 2 notepads, 1 diary and maybe 7 magazines. Also the child nodes of book are all the same (author,title,genre, price, etc).
so each node is not neccasserily follow the same format as the previous or next one.

Although this is 'not' a web application, it needs to be more along the lines of a web.config file. How would I read in that kind of structure ?
Here is a pretty good sample using the book analagy: 3 books, 1 mag, 4 diaries.

<book>
    <Code ISBN10="0101010101" ISBN13="0101010101-222"/>
    <Pages src="111"/>
    <Cover>Paperback</Cover>
</book>
<book>
    <Code ISBN10="2323232323" ISBN13="2323232323-333"/>
    <Pages src="222"/>
    <Cover>Hardback</Cover>
</book>
<book>
    <Code ISBN10="4545454545" ISBN13="4545454545-444"/>
    <Pages src="333"/>
    <Cover>Hardback</Cover>
</book>
<Magazine>
    <Title>My Magazine<Title/>
    <Date Printed="01/01/2007" Published="21/11/2008"/>
    <description>consectetuer adipiscing elit.</description>
    <Date Printed="01/01/2007" Published="21/11/2008"/>
    <Price>3.95</Price>
</Magazine>
<Diary>
    <year>2007</year>
</Diary>
<Diary>
    <year>2008</year>
</Diary>
<Diary>
    <year>2009</year>
</Diary>
<Diary>
    <year>2010</year>
</Diary>

Author

Commented:
OK, you have a good sample of the kind of data I need to store. Is this a valid format? or should I group similar elements togethe? I want to be able to parse the entire doucument in one go, assigning the values to classes on the fly. Please advise - thanks
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
Thanks, but dont forget! Im not storing data on books. I used books just as an analagy to the different types of objects I need to create.
All I am actually looking for is an example or a description of the techniques required, for reading the above book data into my classes using C#.
In other words, I need to put the following code (from my original post) into some kind of loop.
MyClassA Apples = new MyClassA();
Apples.StartDate = [XML Data]; // 01/01/2007
Apples.ReviewDate = [XML Data]; // 21/11/2008

My problem is, that I need to understand the best way to read the different element types in. If all the elements were of the same type, then it would be easy, but I have "Books" and "Magazines", etc. This is my problem.

So, do I need a loop for each different type of element (books, magazines, diaries). ..???

I appreciate your help very much, but maybe you could read my initial question again, as I feel this discussion has deviated from what I originally asked for.


Author

Commented:
I've got it!
As I know the types of elements I am storing, I can run a function for each type. Below I have a GetDiaries function.  I wsimply need to have similar funtion for GetBooks() and GetMagazines().
These functions can instantiate the relative objects as it loops, while giving me a count.

private void GetDiaries()
{
      XmlDocument document = new XmlDocument();
      document.Load("App2.xml");

      string s = null;
      int cnt = 0;

      XmlNodeList list = null;
      list = document.GetElementsByTagName("Diary");
      foreach (XmlNode n in list)
      {
          Year = n["year"].InnerText;
          // Create new class here and set properties with 'Year' value.
          cnt++;
      }
      Debug.WriteLine("There are " + cnt + " Diaries");
}

photowhiz, Thanks for your help, This is exactly what I need, but please let me know if there is any reason why this method is bad in any way.
The only thing bad about XmlDocument is that it loads the entire data set into memory before returning. This makes it bad for large (multi-megabyte) files, and streams. If you are loading a small local file, it it fine.

A benefit of XmlDocument is that you can access, change, and store data directly without making classes. In your instance, you could define a subclass DiaryNode of XmlNode and just use it instead of making up a new class.

Author

Commented:
Luckily the XML file is only about 2KB. The subclass sounds useful, I will have to experiment with that.
Thanks again for your advice.

Gain unlimited access to on-demand training courses with an Experts Exchange subscription.

Get Access
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Empower Your Career
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.