1

I have an Xml file where I want to loop through each module node which increments by 1. Here is a sample of my xml file:

<PersonDetails>
  <PersonTitle>Teacher</PersonTitle>
  <Keystage3>
    <Subject>
      <subjectName>maths</subjectName>
      <subjectId>qq1</subjectId>
      <subjectvalue>20</subjectvalue>
      <subjectscore />
    </Subject>
    <Subject>
      <subjectName>science</subjectName>
      <subjectId>sla1s</subjectId>
      <subjectvalue>25</subjectvalue>
      <subjectscore />
    </Subject>
  </Keystage3>
</PersonDetails>

I want to loop through the xml file and get all data of Subject for both <Subject> node and store each value inside a variable.

I have a piece of code which gets the value from a specific node and outputs it on a textfield.

here is the code I have so far:

public partial class Form1 : Form
{
    private string subName, subId, subvalue;

    public XmlDocument Doc;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {

        XmlTextReader reader = new XmlTextReader("data.xml");
        XmlNodeType type;

        while (reader.Read()) {

            type = reader.NodeType;

            if(type == XmlNodeType.Element)
            {

                    if (reader.Name == "subjectName")
                    {
                        reader.Read();
                        textBox1.Text = reader.Value;
                    }
                    if (reader.Name == "subjectId")
                    {
                        reader.Read();
                        textBox2.Text = reader.Value;
                    }
                    if (reader.Name == "subjectvalue")
                    {
                        reader.Read();
                        textBox3.Text = reader.Value;
                   }


            }
        }
        reader.Close();


    }

How can I make it so that the output recieved is something like:

{maths,qq1,20}
{science,sla1s,25}
Steven
  • 79
  • 2
  • 11
  • It is very unfortunate that the Subject nodes increment like that instead of having the number as an attribute or child element. I don't suppose you have control over how that xml is generated? – Crowcoder Dec 09 '17 at 12:12
  • I have custom made it so that each time a subject node is written the value increments by 1. How can i make it so that each subject node can have an attribute within the node to display the number? – Steven Dec 09 '17 at 12:19
  • 1
    I don't know how you are creating the XML but any XML API will have support for attributes. – Crowcoder Dec 09 '17 at 12:28

2 Answers2

1

You can perform it by using XDocument. If you want to store the nodes values as a collection you can create a class for SubjectNode like this;

        public class SubjectNode
        {
            public string SubjectName { get; set; }
            public string SubjectId { get; set; }
            public string SubjectValue { get; set; }
        }

Then you can retrieve the data like this;

        var xdoc = XDocument.Load("data.xml");
        var keystageNode = xdoc.Descendants("Keystage3").FirstOrDefault();
        var iterateNode = keystageNode.FirstNode;
        var subjectNodes = new List<SubjectNode>();
        while (iterateNode != null)
        {
            var node = (XElement)iterateNode.NextNode;
            subjectNodes.Add(new SubjectNode
            {
                SubjectName = node.Element("subjectName").Value,
                SubjectId = node.Element("subjectId").Value,
                SubjectValue = node.Element("subjectvalue").Value
            });
            iterateNode = iterateNode.NextNode;
        }
lucky
  • 12,734
  • 4
  • 24
  • 46
  • if possible could you please explain why you are doing nodeValue + 1 to node.Value. – Steven Dec 09 '17 at 12:20
  • I understood your question that you want to increase subjectvalue +1. Am I right ? – lucky Dec 09 '17 at 12:22
  • I want read all child nodes of the node which increments by 1 and store the value within a textfield and not save to the xml. – Steven Dec 09 '17 at 12:27
  • following your code I tried to run it however it only displays the last values for each element so textBox1 shows science , textBox2 shows sla1s , and textBox3 shows 25 . can This code be altered so that it displays data from the first and then show from ? sry for asking too many questions im quite new to xml nodes. – Steven Dec 09 '17 at 12:52
  • So, you want to display "Subject" nodes in turn in the textboxes. Am I right ? Actually, it is another case from the question. Because for performing it, you should invoke the textboxes separately from main thread. – lucky Dec 09 '17 at 12:59
  • Yes I want to display "Subject" nodes in turn in the textboxes. My code does not use threading. Is there another method inwhich I can display "Subject" nodes in turn in the textboxes without using threads. My goal for this code is that once i retrieve the values I will place them into variables which then will be used to replace the value of a dynamically created label. Or prehaps store all the data for the subject nodes inside an array. – Steven Dec 09 '17 at 13:07
  • I updated my answer. You can store the data in a collection as explained. – lucky Dec 09 '17 at 13:12
1

Using some LINQ-Magic you can do the folowing:

XElement root = XElement.Load("data.xml");
        var subjects = from subject in root.Descendants()
                          where subject.Name.LocalName.Contains("Subject")
                          select new
                          {
                              SubjectName = subject.Element("subjectName").Value,
                              SubjectId = subject.Element("subjectId").Value,
                              SubjectValue = subject.Element("subjectvalue").Value
                          };

foreach (var subject in subjects)
{
    Console.WriteLine(subject);

    //you can use subject like this:
    string subjectName = subject.SubjectName;
    string subjectId = subject.SubjectId;
    string subjectValue = subject.SubjectValue;
}

This will print:

{ SubjectName = maths, SubjectId = qq1, SubjectValue = 20 }
{ SubjectName = science, SubjectId = sla1s, SubjectValue = 25 }

Includes:

using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
Sir ExecLP
  • 83
  • 1
  • 5
  • @user7388968 can you provide some more information (line, type of exception, stack trace). You may need to use VS2017 and .net 4.6.1. But it definitely works for me. – Sir ExecLP Dec 09 '17 at 19:37
  • Futher following your code is there a way to output the values in a dynamically created input box? – Steven Dec 09 '17 at 20:37
  • @user7388968 you could just create some Textboxes, but managing the layout is gonna be tough. I suggest using a DataTable, you should be able to find some basic examples with a Google search. – Sir ExecLP Dec 10 '17 at 19:09