Smallville
Smallville

Reputation: 685

C# how can I get all elements name from a xml file

I'd like to get all the element name from a xml file, for example the xml file is,

<BookStore>
  <BookStoreInfo>
    <Address />
    <Tel />
    <Fax />
  <BookStoreInfo>
  <Book>
    <BookName />
    <ISBN />
    <PublishDate />
  </Book>
  <Book>
   ....
  </Book>
</BookStore>

I would like to get the element's name of "BookName". "ISBN" and "PublishDate " and only those names, not include " BookStoreInfo" and its child node's name

I tried several ways, but doesn't work, how can I do it?

Upvotes: 24

Views: 108239

Answers (7)

Chintan Patel
Chintan Patel

Reputation: 173

If BookStore is your root element then you can try the following code:

XmlDocument doc = new XmlDocument();
doc.Load(configPath);
XmlNodeList list = doc.DocumentElement.GetElementsByTagName("Book");

if (list.Count != 0) {
    for (int i = 0; i < list[0].ChildNodes.Count; i++) {
        XmlNode child = list[0].ChildNodes[i];
    }
}

Upvotes: 2

J Mills
J Mills

Reputation: 1740

I agree with Adam, the ideal condition is to have a schema that defines the content of xml document. However, sometimes this is not possible. Here is a simple method for iterating all of the nodes of an xml document and using a dictionary to store the unique local names. I like to keep track of the depth of each local name, so I use a list of int to store the depth. Note that the XmlReader is "easy on the memory" since it does not load the entire document as the XmlDocument does. In some instances it makes little difference because the size of the xml data is small. In the following example, an 18.5MB file is read with an XmlReader. Using an XmlDocument to load this data would have been less effecient than using an XmlReader to read and sample its contents.

string documentPath = @"C:\Docs\cim_schema_2.18.1-Final-XMLAll\all_classes.xml";

Dictionary<string, List<int>> nodeTable = new Dictionary<string, List<int>>();
using (XmlReader reader = XmlReader.Create(documentPath))
{
    while (!reader.EOF)
    {
        if (reader.NodeType == XmlNodeType.Element)
        {
            if (!nodeTable.ContainsKey(reader.LocalName))
            {
                nodeTable.Add(reader.LocalName, new List<int>(new int[] { reader.Depth }));
            }
            else if (!nodeTable[reader.LocalName].Contains(reader.Depth))
            {
                nodeTable[reader.LocalName].Add(reader.Depth);
            }
        }
        reader.Read();
    }
}
Console.WriteLine("The node table has {0} items.",nodeTable.Count);
foreach (KeyValuePair<string, List<int>> kv in nodeTable)
{
    Console.WriteLine("{0} [{1}]",kv.Key, kv.Value.Count);
    for (int i = 0; i < kv.Value.Count; i++)
    {
        if (i < kv.Value.Count-1)
        {
            Console.Write("{0}, ", kv.Value[i]);
        }
        else
        {
            Console.WriteLine(kv.Value[i]);
        }
    }
}

Upvotes: 6

Winston Smith
Winston Smith

Reputation: 21892

If you're using C# 3.0, you can do the following:

var data = XElement.Load("c:/test.xml"); // change this to reflect location of your xml file

var allElementNames = 
    (from e in in data.Descendants()
    select e.Name).Distinct();

Upvotes: 3

Fredrik Leijon
Fredrik Leijon

Reputation: 2802

Using XPath

XmlDocument xdoc = new XmlDocument(); 
xdoc.Load(something);
XmlNodeList list = xdoc.SelectNodes("//BookStore");

gives you a list with all nodes in the document named BookStore

Upvotes: 9

Adam Robinson
Adam Robinson

Reputation: 185643

The purists way of doing this (and, to be fair, the right way) would be to have a schema contract definition and read it in that way. That being said, you could do something like this...

List<string> nodeNames = new List<string>();

foreach(System.Xml.XmlNode node in doc.SelectNodes("BookStore/Book"))
{
    foreach(System.Xml.XmlNode child in node.Children) 
    {
        if(!nodeNames.Contains(child.Name)) nodeNames.Add(child.Name);
    }
}

This is, admittedly, a rudimentary method for obtaining the list of distinct node names for the Book node's children, but you didn't specify much else in the way of your environment (if you have 3.5, you could use LINQ to XML to make this a little prettier, for example), but this should get the job done regardless of your environment.

Upvotes: 4

Kirtan
Kirtan

Reputation: 21695

You can try doing it using XPATH.

XmlDocument doc = new XmlDocument();
doc.LoadXml("xml string");

XmlNodeList list = doc.SelectNodes("//BookStore/Book");

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1062955

Well, with XDocument and LINQ-to-XML:

foreach(var name in doc.Root.DescendantNodes().OfType<XElement>()
        .Select(x => x.Name).Distinct())
{
    Console.WriteLine(name);
}

There are lots of similar routes, though.

Upvotes: 37

Related Questions