Home » c# » C# Trying to get XML inner text for nested node

C# Trying to get XML inner text for nested node

Posted by: admin February 21, 2020 Leave a comment

Questions:

I can succesfully load the XMl document and traverse the nodes. Once I get the node that I want, I start setting values. How do I deal with nested nodes?

Here is the xml:

<incident>
<id>1234</id>
<number>5678</number>
<name>This is a name</name>
<state>Awaiting Input</state>
<priority>Medium</priority>
<category>
    <id>99999</id>
    <name>Applications</name>
    <default_tags>applications</default_tags>
    <parent_id nil="true" />
    <default_assignee_id nil="true" />
</category>

Here is some C#:

   id = node.SelectSingleNode("id").InnerText;  //works fine
   number = node.SelectSingleNode("number").InnerText;  //works fine

   name = node.SelectSingleNode("name").InnerText;  //works fine
   descHTML = node.SelectSingleNode("description").InnerText;  //works fine
   desc = node.SelectSingleNode("description_no_html").InnerText;  //works fine
   state = node.SelectSingleNode("state").InnerText;  //works fine
   priority = node.SelectSingleNode("priority").InnerText;  //works fine

   catagoryID = node.SelectSingleNode("category/id").InnerText; // null reference error
   catagoryName = node.SelectSingleNode("category/name").InnerText; // null reference error
   catagoryTags = node.SelectSingleNode("category/default_tags").InnerText; // null reference error
How to&Answers:

If you are reading different elements that may or may not exist, use ?. after the SelectSingleNode method. This will ensure you dont get the error Object Reference Not Set to an Instance of an object.

?. in essence checks if there is a value before proceeding to evaluate the next method or proprety.

string xml = @"<incident>
<id>1234</id>
<number>5678</number>
<name>This is a name</name>
<state>Awaiting Input</state>
<priority>Medium</priority>
<category>
    <id>99999</id>
    <name>Applications</name>
    <default_tags>applications</default_tags>
    <parent_id nil=""true"" />
    <default_assignee_id nil=""true"" />
</category>
</incident>";

        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xml);
        var node = doc.DocumentElement;

        var id = node.SelectSingleNode("id")?.InnerText;  //works fine
       var number = node.SelectSingleNode("number")?.InnerText;  //works fine

       var name = node.SelectSingleNode("name")?.InnerText;  //works fine
       var descHTML = node.SelectSingleNode("description")?.InnerText;  //ERRORS because there is no description.
       var desc = node.SelectSingleNode("description_no_html")?.InnerText;  //works fine
       var state = node.SelectSingleNode("state")?.InnerText;  //works fine
       var priority = node.SelectSingleNode("priority")?.InnerText;  //works fine

       var catagoryID = node.SelectSingleNode("//category/id")?.InnerText; // null reference error
       var catagoryName = node.SelectSingleNode("//category/name")?.InnerText; // null reference error
       var catagoryTags = node.SelectSingleNode("//category/default_tags")?.InnerText; // null reference error

        Console.WriteLine($"name: {name}");
        Console.WriteLine($"descHTML: {descHTML}");
        Console.WriteLine($"desc: {desc}");
        Console.WriteLine($"state: {state}");
        Console.WriteLine($"priority: {priority}");
        Console.WriteLine($"catagoryID: {catagoryID}");
        Console.WriteLine($"catagoryName: {catagoryName}");
        Console.WriteLine($"catagoryTags: {catagoryTags}");

Output it prints out

name: This is a name
descHTML: 
desc: 
state: Awaiting Input
priority: Medium
catagoryID: 99999
catagoryName: Applications
catagoryTags: applications

Code on #dotnetfiddle

###

I suppose you use the XmlDocument class and CATEGORY NODE is the only item that will have childnodes, so I have this method to go through each element, including subnodes (I hope this helps someone).

string xml = 
@"<incident>
    <id>1234</id>
    <number>5678</number>
    <name>This is a name</name>
    <state>Awaiting Input</state>
    <priority>Medium</priority>
    <category>
        <id>99999</id>
        <name>Applications</name>
        <default_tags>applications</default_tags>
        <parent_id nil=""true"" />
        <default_assignee_id nil=""true"" />
    </category>
</incident>";

List<String> innerTextNode = new List<string>();
XmlDocument XmlDoc= new XmlDocument();
XmlDoc.LoadXml(xml);

XmlElement root = XmlDoc.DocumentElement;
XmlNodeList nodes = root.ChildNodes;
XmlNodeList childs;

foreach (XmlNode anode in nodes)
{
    // The next is for any NODE that will have childnodes
    // bool havechilds = anode.ChildNodes.OfType<XmlNode>().Any(x => x.NodeType != XmlNodeType.Text)

    if (!anode.LocalName.Equals("category", StringComparison.CurrentCulture))
    {
        // The node is only text, no has childnodes
        // So capturing InnerText
        innerTextNode.Add(anode.InnerText);
    }
    else
    {
        childs = nodo.ChildNodes;
        foreach (XmlNode childone in childs)
        {
            // So capturing InnerText
            innerTextNode.Add(childone.InnerText);
        }
    }
}