Selecting inner text of XML nodes and adding to list

1.1k views Asked by At

I have the following XML file called file.xml:

<?xml version="1.0"?>
<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config">
   <defaults>
      <serializer>pof</serializer>
   </defaults>
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>broadcast-data|position</cache-name>
            <scheme-name>broadcast</scheme-name>
        </cache-mapping>
        <cache-mapping>
            <cache-name>broadcast-data|position-audit</cache-name>
            <scheme-name>broadcast-remote</scheme-name>
        </cache-mapping>
        <cache-mapping>
            <cache-name>broadcast-data|trade</cache-name>
            <scheme-name>broadcast-remote</scheme-name>
        </cache-mapping>
    </caching-scheme-mapping>
</cache-config>

I'm trying to get the inner text of all the cache names, which exist under each cache-mapping node, and put them all in a list. I have this Model.cs class to do that.

class Model
{
    private XmlDocument cacheFile = new XmlDocument();
    private List<string> cacheNames = new List<string>();
    private int nameCount = 0;


    public Model()
    {
        this.loadNames();
    }

    public void loadNames()
    {
        try //exception handling
        {
            cacheFile.Load("../../resources/file.xml");

        }
        catch (System.IO.FileNotFoundException)
        {
            Debug.WriteLine("File not found!");
            Environment.Exit(1);
        }
        catch (System.ArgumentException)
        {
            Debug.WriteLine("Invalid path!");
            Environment.Exit(1);
        }
        catch (Exception e)
        {
            Debug.WriteLine("Exception thrown!");
            Debug.WriteLine(e);
            Environment.Exit(1);
        }

        //get cache names
        XmlNodeList nodes = cacheFile.SelectNodes("/cache-config/caching-scheme-mapping/cache-mapping");

        foreach (XmlNode node in nodes)
        {
            string name = node.FirstChild.InnerText;
            cacheNames.Add(name);
            nameCount++;

        }

    }
    //accessors
    public List<string> getCacheNames()
    {
        return cacheNames;
    }
    public int getNameCount()
    {
        return nameCount;
    }

}

However, every time I create a Model object and then check if the List was loaded up, it tells me the list is empty! It appears as though the foreach loop never actually runs, or as if the program can't find the nodes I'm specifying. Please help.

2

There are 2 answers

0
Charles Mager On BEST ANSWER

If you use LINQ to XML, this is really quite simple:

XNamespace ns = "http://xmlns.oracle.com/coherence/coherence-cache-config";            

var doc = XDocument.Load("../../resources/file.xml");

cacheNames = doc.Descendants(ns + "cache-name").Select(e => e.Value).ToList();

You don't need to keep a separate count of items, you can get this from the list:

cacheNames.Count;

As an aside, idiomatic C# uses pascal casing for methods and properties, so if you stuck to this your methods would start with a capital letter - e.g. GetCacheNames.

0
har07 On

This has been puzzling many and has been asked many times here in SO. Your XML has default namespace here :

xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"

Descendant elements inherit ancestor default namespace, unless otherwise specified (using explicit namespace prefix or having local default namespace that point to different namespace URI). Using XmlDocument you can use XmlNamespaceManager to register prefix to namespace URI mapping, and use the registered prefix properly in your XPath query, for example :

var nsMgr = new XmlNamespaceManager(new NameTable());
nsMgr.AddNamespace("d", "http://xmlns.oracle.com/coherence/coherence-cache-config");
var xpath = "/d:cache-config/d:caching-scheme-mapping/d:cache-mapping";
XmlNodeList nodes = cacheFile.SelectNodes(xpath, nsMgr);

Anyway, if you have just started this, switching to newer class XDocument would be a better option.