3

I have the following elements as part of an XML document:

<RegisterEntry>
    <EntryNumber>3</EntryNumber>
    <EntryDate>2009-01-30</EntryDate>
    <EntryType>Registered Charges</EntryType>
    <EntryText>REGISTERED CHARGE dated 30 December 2008.</EntryText>
</RegisterEntry>
<RegisterEntry>
    <EntryNumber>4</EntryNumber>
    <EntryType>Registered Charges</EntryType>
    <EntryText>REGISTERED CHARGE dated 30 December 2008.</EntryText>
</RegisterEntry>

I am using XmlReader to iterate through the document. The RegisterEntry is an XMLNodeType.Element and the four enclosed in this element are XmlNodeType.Text. How can I assign each of these Text values to a different variable as the XmlReader returns an empty string for Node.Name on a NodeType.Text. Also, the repeated elements do not always have the same number of text elements. Code below:

XmlTextReader reader = new XmlTextReader(fName);

if(reader.NodeType == XmlNodeType.Element && reader.Name =="RegisterEntry")
{
    propEntryNo = "";
    propEntryDate = "";
    propEntryType = "";
    propEntryText = "";

    while(reader.Read())
    {
        if(reader.NodeType == XmlNodeType.Text && reader.Name == "EntryNumber" && reader.HasValue)
        {
            propEntryNo = reader.Value;
        }

        if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryDate" && reader.HasValue)
        {
            propEntryDate = reader.Value;
        }

        if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryType" && reader.HasValue)
        {
            propEntryType = reader.Value;
        }

        if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryText" && reader.HasValue)
        {
            propEntryText += reader.Value + ",";
        }
        if(reader.NodeType == XmlNodeType.EndElement && reader.Name == "RegisterEntry")
        {
            add variable values to list
            break;
        }
    }
}

In each of the if statements above the NodeType returns as Text and the Name as an empty string.

  • Can you please show us some code? – Rui Jarimba Oct 25 '18 at 10:28
  • means you want to fetch all child nodes inside `RegisterEntry` whether they present or not? – er-sho Oct 25 '18 at 10:32
  • Your XML shows `RegisterEntry` has child-elements, so how can they be text-nodes? Either your XML or your explanation is incorrect. *Show the code!* – marsze Oct 25 '18 at 10:32
  • Original post edited to include code. The XML file comes from the Land Registry in the UK. – Allen Jones Oct 25 '18 at 10:42
  • A mistake in your thinking: `EntryNumber` is a node of type `Element` (with name "EntryNumber") but the text inside is a *different* node, of type `Text` (with no name). – marsze Oct 25 '18 at 10:48
  • @AllenJones, you used here `while` loop and you collect all the values in single variable so your variable hold only last iteration values of while loop. so you want only last `RegisterEntry` from xml – er-sho Oct 25 '18 at 10:48
  • @marsze - not a mistake in my thinking. If I step through the code in debug mode, Visual Studio confirms that EntryNumber etc are Node Type.Text. – Allen Jones Oct 25 '18 at 10:53
  • @ershoaib - Yes, I need to fetch all child nodes whether they are present or not. I have not included ALL of my code as it is a lengthy tome but at each iteration I append the variables to a list to be used at a later point in the process. – Allen Jones Oct 25 '18 at 10:55
  • Did you consider using `XDocument` and parse document instead of using `XmlTextReader`. Would it suit your needs? – Yeldar Kurmangaliyev Oct 25 '18 at 10:59
  • @YeldarKurmangaliyev - I will take a look at XDocument and see if that helps – Allen Jones Oct 25 '18 at 11:04
  • 2
    @AllenJones You don't actually need to use `XmlTextReader` in 99.9% of cases. Just deserialize this XML file into your objects. – Yeldar Kurmangaliyev Oct 25 '18 at 11:07

2 Answers2

1

The XML element and the text inside are different nodes!

You have to read the content of the XML element first. Simple example:

switch (reader.Name)
{
    // found a node with name = "EntryNumber" (type = Element)
    case "EntryNumber":
        // make sure it's not the closing tag
        if (reader.IsStartElement())
        {
            // read the text inside the element, which is a seperate node (type = Text)
            reader.Read();
            // get the value of the text node
            propEntryNo = reader.Value;
        }
        break;
    // ...
}

Another option would be ReadElementContentAsString

switch (reader.Name)
{
    case "EntryNumber":
        propEntryNo = reader.ReadElementContentAsString();
        break;
    // ...
}

Of course, these simple examples assume that the XML is in the expected format. You should include appropriate checks in your code.

As for the other suggested solutions:

marsze
  • 15,079
  • 5
  • 45
  • 61
0

You can use XDocument to list your RegisterEntry child node like

class Program
{
    static void Main(string[] args)
    {
        XDocument doc = XDocument.Load(@"C:\Users\xxx\source\repos\ConsoleApp4\ConsoleApp4\Files\XMLFile14.xml");

        var registerEntries = doc.Descendants("RegisterEntry");

        var result = (from e in registerEntries
                      select new
                      {
                          EntryNumber = e.Element("EntryNumber") != null ? Convert.ToInt32(e.Element("EntryNumber").Value) : 0,
                          EntryDate = e.Element("EntryDate") != null ? Convert.ToDateTime(e.Element("EntryDate").Value) : (DateTime?)null,
                          EntryType = e.Element("EntryType") != null ? e.Element("EntryType").Value : "",
                          EntryText = e.Element("EntryText") != null ? e.Element("EntryText").Value : "",
                      }).ToList();


        foreach (var entry in result)
        {
            Console.WriteLine($"EntryNumber:  {entry.EntryNumber}");
            Console.WriteLine($"EntryDate:  {entry.EntryDate}");
            Console.WriteLine($"EntryType:  {entry.EntryType}");
            Console.WriteLine($"EntryText:  {entry.EntryText}");
            Console.WriteLine();
        }

        Console.ReadLine();
    }
}

Output:

enter image description here

You can also make certain operations on your list like.

//If you want to get all `EntryText` in xml to be comma separated then you can do like
string propEntryText = string.Join(", ", result.Select(x => x.EntryText));

//Get first register entry from xml
var getFirstRegisterEntry = result.FirstOrDefault();

//Get last register entry from xml
var getLastRegisterEntry = result.LastOrDefault();

//Get register entry from xml with specific condition 
var getSpecificRegisterEntry = result.Where(x => x.EntryNumber == 3).SingleOrDefault();
er-sho
  • 9,581
  • 2
  • 13
  • 26