2009-05-11 37 views
20

Me gustaría obtener todo el nombre del elemento desde un archivo XML, por ejemplo, el archivo XML es,C# cómo puedo obtener todos los nombres de los elementos de un archivo XML

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

me gustaría obtener la el nombre del elemento de "BookName". "ISBN" y "PublishDate" y solo esos nombres, no incluyen "BookStoreInfo" y su nombre de nodo secundario

Probé de varias maneras, pero no funciona, ¿cómo puedo hacerlo?

Respuesta

27

Bueno, con XDocument y LINQ-a-XML:

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

hay un montón de rutas similares, sin embargo.

+0

muchas gracias. No soy familiar con LINQ-XML. Pero funciona muy bien. Una cosa más, actualicé la pregunta anterior. cómo solo puedo obtener el nombre de los nodos secundarios bajo el elemento . – Smallville

+0

Si quiere decir en "Libro" (según la pregunta actualizada) algo así como: doc.Root.Element ("Libro"). DescendantNodes() ... –

+1

Sí, eso es lo que quiero decir. Y el código está funcionando, gracias de nuevo! – Smallville

9

Usando XPath

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

le da una lista con todos los nodos en el documento denominado BookStore

2

Puede intentarlo usando XPATH.

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

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

Si estás usando C# 3.0, puede hacer lo siguiente:

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(); 
+0

No existe tal cosa como C# 3.5; que usa C# 3.0 y .NET 3.5, sin embargo. –

+0

Lo sé ... Adam editó mi respuesta. Lo he arreglado de nuevo. –

+0

Gran respuesta. ¿Cómo contarías la cantidad de veces que aparece cada etiqueta? – fab

4

La forma más puristas de hacer esto (y, para ser justos, la manera correcta) habría de tener una definición de contrato de esquema y léalo de esa manera. Dicho esto, se podría hacer algo como esto ...

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

Este es, sin duda, un método rudimentario para obtener la lista de nombres de nodos distintos para los niños del nodo Book, pero no se especificó mucho más en el camino de su entorno (si tiene 3.5, podría usar LINQ to XML para hacer esto un poco más atractivo, por ejemplo), pero esto debería hacer el trabajo independientemente de su entorno.

5

Estoy de acuerdo con Adam, la condición ideal es tener un esquema que defina el contenido del documento xml. Sin embargo, a veces esto no es posible. Aquí hay un método simple para iterar todos los nodos de un documento xml y usar un diccionario para almacenar los nombres locales únicos. Me gusta hacer un seguimiento de la profundidad de cada nombre local, así que utilizo una lista de int para almacenar la profundidad. Tenga en cuenta que XmlReader es "fácil de usar en la memoria" ya que no carga todo el documento como lo hace XmlDocument. En algunos casos, hace poca diferencia porque el tamaño de los datos xml es pequeño. En el siguiente ejemplo, se lee un archivo de 18.5MB con un XmlReader. Usar un XmlDocument para cargar estos datos hubiera sido menos eficiente que usar un XmlReader para leer y probar sus contenidos.

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

Si BookStore es ur elemento raíz entonces u puede tratar siguiente código

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]; 

      } 
     } 
+0

Esta es una respuesta mejor que la aceptada – Jansky

Cuestiones relacionadas