[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

XML Parsing in C#

Posted on 2009-04-17
12
Medium Priority
?
540 Views
Last Modified: 2013-12-17
Hi,
I have an XML with following content:

<GSMThreshold>
<BasicMetrics>
<MetricCategory>
 GSM Pilot
<MetricName>
 GSM Dominant Pilot EcIo
<Rec1>
 <Threshold>-11</Threshold>
 <Color>16711935</Color>
 </Rec1>
<Rec2>
 <Threshold>-9</Threshold>
 <Color>16711935</Color>
 </Rec2>
 </MetricName>
<MetricName>
 GSM Pilot Scan Ec
<Rec1>
 <Threshold>-80</Threshold>
 <Color>16711935</Color>
 </Rec1>
<Rec2>
 <Threshold>-75</Threshold>
 <Color>16711935</Color>
 </Rec2>
 </MetricName>
 </MetricCategory>
<MetricCategory>
 GSM Power
<MetricName>
 GSM Best Neighbor Rx Level
<Rec1>
 <Threshold>-120</Threshold>
 <Color>16711935</Color>
 </Rec1>
<Rec2>
 <Threshold>-105</Threshold>
 <Color>16744703</Color>
 </Rec2>
 </MetricName>
<MetricName>
 GSM Serving Cell Rx Level Full
<Rec1>
 <Threshold>-120</Threshold>
 <Color>16711935</Color>
 </Rec1>
<Rec2>
 <Threshold>-105</Threshold>
 <Color>16744703</Color>
 </Rec2>
 </MetricName>
<MetricName>
 GSM Serving Cell Rx Level Sub
<Rec1>
 <Threshold>-120</Threshold>
 <Color>16711935</Color>
 </Rec1>
<Rec2>
 <Threshold>-105</Threshold>
 <Color>16744703</Color>
 </Rec2>
 </MetricName>
 </MetricCategory>
 </BasicMetrics>
 </GSMThreshold>

The hierarchy is
BasicMetrics->MetricCategory->MetricName->RecX->
                                                               Threshold
                                                                Color

I want to display each hierarchy level in a separate listbox; so that:
1.When I select  BasicMetrics -> It should display all metric category
2. When I select Metric Category -> it should list all metricname
3. When MetricName selected -> list all records

Please provide me a sample program.

Thanks,
Shan
0
Comment
Question by:shanvidhya
12 Comments
 
LVL 5

Expert Comment

by:Aanvik
ID: 24172076
http://support.microsoft.com/kb/307548

this should help you step by step.
0
 
LVL 39

Expert Comment

by:abel
ID: 24172341
> 1..2..3...
Please provide me a sample program.

sorry, we usually don't do your work for you, we only provide you with pointers or snippets that should give you enough to go on to get further. If you have any specific questions regarding that link, we'll be happy to help further. If you already have some code, show what you got so we can take it from there.
0
 
LVL 3

Expert Comment

by:coagantus
ID: 24173862
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:shanvidhya
ID: 24179382
The following is the code which I wrote to get the MetricsCategory;
private void btnAccept_Click(object sender, EventArgs e)
        {
            XmlTextReader reader = new XmlTextReader("C:\\Test1.xml");
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element: // The node is an element.

                        if (reader.Name =="MetricCategory")  
                        {
                            reader.Read();
                            listBox1.Items.Add (reader.Value);  
                        }

                        break;
                    case XmlNodeType.EndElement: //Display the end of the element.
                         break;
                }
            }
            Console.ReadLine();
        }

If I select "GSM Pilot" how do I navigate to get MetricName for GSM Pilot? AM I in the right direction? Please advice.

Thanks,
Shan
0
 
LVL 39

Expert Comment

by:abel
ID: 24179799
That looks quite good already. Since you are using the XmlTextReader, you can only do forward-only reads, meaning that you must do something on the moment that a certain element passes by and you cannot "read backwards".

Taking your original code and changing it slightly to make it easier to work with, I come up with the following solution to fill all three listboxes, and they react on a selection event to fill the next listbox (see screenshot)

The code I used to achieve that I pasted in the code section below. All you need to do to use it is to put three listboxes on a form and add an eventhandler for each of them (SelectedIndexChanged).


// loading XML data and load listboxes based on selection in other listbox 
 
private void btnAccept_Click(object sender, EventArgs e)
{
    XmlTextReader reader = new XmlTextReader("Data/Q24333151.xml");
    while (reader.Read())
    {
        reader.ReadToFollowing("MetricCategory");
        listBox1.Items.Add(reader.ReadString().Trim());
    }
}
 
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    listBox2.Items.Clear();
 
    string metricCat = (string) listBox1.SelectedItem;
    XmlTextReader reader = new XmlTextReader("Data/Q24333151.xml");
    while (reader.Read())
    {
        reader.ReadToFollowing("MetricCategory");
        if (metricCat == reader.ReadString().Trim())
        {
            while (reader.ReadToFollowing("MetricName"))
            {
                listBox2.Items.Add(reader.ReadString().Trim());
            }
            return;
        }
    }
}
 
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
    listBox3.Items.Clear();
 
    string metricName = (string)listBox2.SelectedItem;
    XmlTextReader reader = new XmlTextReader("Data/Q24333151.xml");
    while (reader.Read())
    {
        reader.ReadToFollowing("MetricName");
        if (metricName == reader.ReadString().Trim())
        {
            while (reader.ReadToFollowing("Threshold"))
            {
                string thresHold = reader.ReadString().Trim();
                reader.ReadToFollowing("Color");
                string color = reader.ReadString();
                listBox3.Items.Add(thresHold + " (" + color + ")");
            }
            return;
        }
    }
}

Open in new window

ScreenShot220.png
0
 

Author Comment

by:shanvidhya
ID: 24180589
Abel,
Thanks for the earlier comments. A small change is needed from your original snippet. When "GSM Pilot" is selected in list1; list2 is suppose to display:
GSM Dominant Pilot EcIo
GSM Pilot Scan Ec

Similarly when "GSM Power" is selected; list2 is suppose to display:

GSM Best Neighbor Rx Level
GSM Serving Cell Rx Level Full
GSM Serving Cell Rx Level Sub

Appreciate your reply with changes.

Thanks,
Shan
0
 
LVL 39

Expert Comment

by:abel
ID: 24180827
Yes, you are right, there were mistakes in my code. ReadToFollowing is apparently the equivalent to following::* in Xpath. And playing around a bit with the advance-pointer of the XmlReader does not make things easier as it can be quite unclear what is actually read and why, and advancing to something simple like the "end of the current node" or the "end of the parent node" is not possible.

Be as it may, this is not the prettiest solution I could think of and I'm not sure it is 100% stable, but it works with your XML.

-- Abel --



private void btnAccept_Click(object sender, EventArgs e)
{
    XmlTextReader reader = new XmlTextReader("Data/Q24333151.xml");
    while (reader.Read())
    {
        reader.ReadToFollowing("MetricCategory");
        listBox1.Items.Add(reader.ReadString().Trim());
    }
}
 
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    listBox2.Items.Clear();
 
    string metricCat = (string) listBox1.SelectedItem;
    XmlTextReader reader = new XmlTextReader("Data/Q24333151.xml");
    while (reader.Read())
    {
        reader.ReadToFollowing("MetricCategory");
        if (metricCat == reader.ReadString().Trim())
        {
            do
            {
                // reading the string brings us _inside_ MetricName element, at the Rec1
                listBox2.Items.Add(reader.ReadString().Trim());
                // to get out, do something that reads up to the end of the parent element
                reader.ReadToNextSibling("NotToBeFound");
                // and read to just BEFORE the next elem
                reader.ReadEndElement();
            } while (reader.ReadToNextSibling("MetricName"));
 
            return;
        }
    }
}
 
private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{
    listBox3.Items.Clear();
 
    string metricName = (string)listBox2.SelectedItem;
    XmlTextReader reader = new XmlTextReader("Data/Q24333151.xml");
    while (reader.Read())
    {
        if (!reader.ReadToFollowing("MetricName"))
            return;
 
        // work on a subnode, that makes things easier
        XmlReader subReader = reader.ReadSubtree();
        subReader.Read();  // advance to the start of the subnode...
        if (metricName == subReader.ReadString().Trim())
        {
            while (subReader.ReadToFollowing("Threshold"))
            {
                string thresHold = subReader.ReadString().Trim();
                subReader.ReadToFollowing("Color");
                string color = subReader.ReadString();
                listBox3.Items.Add(thresHold + " (" + color + ")");
            }
            return;
        }
    }
}

Open in new window

0
 
LVL 39

Expert Comment

by:abel
ID: 24180893
Here's an easier version of listBox1_SelectedIndexChanged event, which uses the same technique as listbox2 now (using reader.ReadSubtree(), which is handy to work around the reading bugs and this approach makes it more stable).

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    listBox2.Items.Clear();
 
    string metricCat = (string) listBox1.SelectedItem;
    XmlTextReader reader = new XmlTextReader("Data/Q24333151.xml");
    while (reader.Read())
    {
        reader.ReadToFollowing("MetricCategory");
        XmlReader subReader = reader.ReadSubtree();
        subReader.Read();  // advance to the start of the subnode...
        if (metricCat == subReader.ReadString().Trim())
        {
            do
            {
                listBox2.Items.Add(subReader.ReadString().Trim());
            } while (subReader.ReadToFollowing("MetricName"));
 
            return;
        }
    }
}

Open in new window

0
 

Author Comment

by:shanvidhya
ID: 24181216
Abel,

This is perfect; you are master in this xml path. This will be a good start for me.

If I update values in list3 and want to save all the entries (list1, list2 and list3) to a new xml is there a simplest way? Please advice.

Thanks,
Shan
0
 
LVL 39

Accepted Solution

by:
abel earned 500 total points
ID: 24181244
That sounds like a new question to me ;)

But here is a head start: if you want to safe these values and you want to update them in the XML file, I recommend you to use a different technique for the updating part. One method is to use XSLT to do the update. You can also reread the whole file the same way and write at the same time and use the methods laid out above for how to select certain nodes.

Reading is one thing, writing is another, and updating is yet another...
0
 

Author Closing Comment

by:shanvidhya
ID: 31571655
Thanks Abel. I am new to C# and this will be a great start for me.

Thanks,
Shan
0
 
LVL 39

Expert Comment

by:abel
ID: 24181397
> Thanks Abel. I am new to C# and this will be a great start for me.
glad to be of some help. Was quite a tricky question altogether...
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
Wouldn’t it be nice if you could test whether an element is contained in an array by using a Contains method just like the one available on List objects? Wouldn’t it be good if you could write code like this? (CODE) In .NET 3.5, this is possible…
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
When cloud platforms entered the scene, users and companies jumped on board to take advantage of the many benefits, like the ability to work and connect with company information from various locations. What many didn't foresee was the increased risk…
Suggested Courses
Course of the Month18 days, 6 hours left to enroll

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question