il problema risiede nella lettura degli attributi
codice:
<node nodeID="2"query="query 2"dbQuery="bbb">TextB</node>
in questo caso XmlNode è rappresentato da 'node' in seguito leggi la lista di attributi (nodeID, query, dbQuery)
ricorsivamente chiedi a questo 'node' se ha figli, e lui risponde di si: TextB è un suo figlio.
quindi XmlNode è rappresentato da 'TextB' in seguito leggi la lista di attributi (nodeID, query, dbQuery) però un attimo, TextB non ha attributi, pertanto:
codice:
foreach(XmlAttribute attr in cNode.Attributes)
cNode.Attributes ti da nullo di consequenza avviende l'interruzione per oggetto non impostato su un istanza di un oggetto.
quindi per farlo andare ti basta verificare che Attributes non sia nullo e se lo è fare un continue.
codice:
privatevoidProcessaSottoNodi(XmlNode node){
if(node.HasChildNodes)
{
foreach(XmlNode cNode in node.ChildNodes)
{
if(cNode.Attributes== null)
continue;
Console.WriteLine("{0}", cNode.Name);
foreach(XmlAttribute attr in cNode.Attributes)
Console.WriteLine("{0}", attr.Name+" = "+ attr.InnerText);
Console.WriteLine("-------------------------------");
ProcessaSottoNodi(cNode);
}
}
}
Questo ti risolve il problema, però devi chiederti se ha senso avere un Xml del genere, di sicuro preferisci avere un file che puoi sempre leggere in qualsiasi situazione, senza dover mettere uno, due o infiniti "se" per tappare mancanze.
Quindi per sistemare in modo definitivo il problema gli elementi TextA, B, etc o vengono messi come attributi, oppure quello che ti consiglio è cambiare totalmente la gestione.
cioè usare l'XmlSerializer
è una classe apposta creata che ti permette Reflection tra il tuo file ed un oggetto stilato apposta, legge veloce preciso, chiaramente è pignolo
questo ti impone una struttura da seguire, pretende che i dati siano corretti.
Ammettendo un Xml output o input del genere:
codice:
<node nodeID="1" query="select l from a" dbQuery="select l from f">
<node nodeID="2" query="select l from a" dbQuery="select l from f">
<text>TextA</text>
</node>
<node nodeID="3" query="select l from a" dbQuery="select l from f">
<text>TextA</text>
<node nodeID="4" query="select l from a" dbQuery="select l from f">
<text>TextA</text>
</node>
<node nodeID="5" query="select l from a" dbQuery="select l from f">
<text>TextA</text>
</node>
</node>
</node>
<node nodeID="6" query="select l from a" dbQuery="select l from f" />
<node nodeID="7" query="select l from a" dbQuery="select l from f" />
<node nodeID="8" query="select l from a" dbQuery="select l from f">
ogni nodo può avere figli nodi, può avere figli nodi ed un elemento testo o solo elemento testo.
Il tuo oggetto C# che si interfaccia alla struttura desiderata.
codice:
/// <summary>
/// Fornisce una struttura per la riflessione con un file Xml.
/// </summary>
[XmlRoot("node")]
public class Node
{
/// <summary>
/// Ottiene o setta l'id.
/// </summary>
[XmlAttribute("nodeID")]
public int NodeID { get; set; }
/// <summary>
/// Ottiene o setta la query.
/// </summary>
[XmlAttribute("query")]
public string Query { get; set; }
/// <summary>
/// Ottiene o setta la query del db.
/// </summary>
[XmlAttribute("dbQuery")]
public string DBQuery { get; set; }
/// <summary>
/// Ottiene o setta il testo.
/// </summary>
[XmlElement("text")]
public string Text { get; set; }
/// <summary>
/// Ottiene o setta i nodi figli.
/// </summary>
[XmlElement("node")]
public List<Node> Children { get; set; }
/// <summary>
/// Costruttore.
/// </summary>
public Node() { Children = new List<Node>(); }
/// <summary>
/// Returns a string that represents the current object.
/// </summary>
/// <returns>A string that represents the current object.</returns>
public override string ToString()
{
return String.Format("Node Id: {0}, Query: {1}, DBQuery: {2}, Nr. children: {3}",
NodeID, Query, DBQuery, Children.Count);
}
}
il lettore del file xml.
codice:
public static object DeserializeXml(string fullFileName, Type type)
{
XmlSerializer serializer = new XmlSerializer(type);
using (FileStream stream = new FileStream(fullFileName, FileMode.Open))
return serializer.Deserialize(stream);
}