tags:

views:

2744

answers:

6

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?

+2  A: 

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

Fredrik Leijon
+7  A: 

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.

Marc Gravell
Thanks a lot. Im not famliar with LINQ-XML. But it works very well. One more thing, I updated the question above. how can I only get the child nodes' name under <BookStore> element.
Smallville
If you mean under "Book" (as per updated question) - something like: doc.Root.Element("Book").DescendantNodes()...
Marc Gravell
Yes, that's what I mean. And the code is working, thank u again!
Smallville
+1  A: 

You can try doing it using XPATH.

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

XmlNodeList list = doc.SelectNodes("//BookStore/Book");
Kirtan
+2  A: 

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();
Winston Smith
There is no such thing as C# 3.5; that uses C# 3.0 and .NET 3.5, though.
Marc Gravell
I know... Adam edited my answer. I've fixed it again.
Winston Smith
+2  A: 

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.

Adam Robinson
A: 

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]);
        }
    }
}
chickenSandwich