XML is a multilevel structure, and you are trying to read "flat". What you are doing is basically deserializing XML to your C # objects, and the best way to do this is to use a serialization class (for example, XmlSerializer or DataContractSerializer ).
Now, if you really want to do the work "on hand" (and I do not advise, since the chance of you having errors in your implementation is not negligible) you need to store the context from where the nodes appear. One possibility is to store all the antecedents of the nodes, and use this information, as in the example below:
class Program
{
const string XML = @"<produtos>
<produto>
<id>1</id>
<dados>
<categoria>cat dados 1</categoria>
</dados>
<formato>
<categoria>cat formato 1</categoria>
</formato>
</produto>
<produto>
<id>2</id>
<dados>
<categoria>cat dados 2</categoria>
</dados>
<formato>
<categoria>cat formato 2</categoria>
</formato>
</produto>
</produtos>";
static void Main()
{
Stack<string> pilha = new Stack<string>();
var produtos = new List<Produto>();
var produto = new Produto { Dados = new Dados(), Formato = new Formato() };
using (var reader = new XmlTextReader(new StringReader(XML)))
{
while (reader.Read())
{
if (reader.IsStartElement())
{
if (reader.Name == "ID")
{
produto.ID = reader.ReadString();
}
else if (reader.Name == "categoria")
{
var topoDaPilha = pilha.Peek();
if (topoDaPilha == "dados")
{
produto.Dados.Categoria = reader.ReadString();
}
else if (topoDaPilha == "formato")
{
produto.Formato.Categoria = reader.ReadString();
}
}
else if (!reader.IsEmptyElement)
{
pilha.Push(reader.Name);
}
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
pilha.Pop();
if (reader.Name == "produto")
{
produtos.Add(produto);
produto = new Produto { Dados = new Dados(), Formato = new Formato() };
}
}
}
}
Console.WriteLine("Produtos:");
foreach (var prod in produtos)
{
Console.WriteLine("- {0}", prod);
}
}
}
class Produto
{
public string ID { get; set; }
public Dados Dados { get; set; }
public Formato Formato { get; set; }
public override string ToString()
{
return string.Format("Produto[ID={0}, Dados/Cat={1}, Formato/Cat={2}]", ID, Dados.Categoria, Formato.Categoria);
}
}
class Dados
{
public string Categoria { get; set; }
}
class Formato
{
public string Categoria { get; set; }
}
Another possibility is to accept XML recursion, and use functions to read each part of your document:
class Program
{
const string XML = @"<produtos>
<produto>
<id>1</id>
<dados>
<categoria>cat dados 1</categoria>
</dados>
<formato>
<categoria>cat formato 1</categoria>
</formato>
</produto>
<produto>
<id>2</id>
<dados>
<categoria>cat dados 2</categoria>
</dados>
<formato>
<categoria>cat formato 2</categoria>
</formato>
</produto>
</produtos>";
static void Main(string[] args)
{
var produtos = new List<Produto>();
using (var reader = new XmlTextReader(new StringReader(XML)))
{
reader.ReadToDescendant("produto");
while (reader.IsStartElement("produto"))
{
produtos.Add(ReadProduto(reader));
}
}
Console.WriteLine("Produtos:");
foreach (var produto in produtos)
{
Console.WriteLine("- {0}", produto);
}
}
static Produto ReadProduto(XmlReader reader)
{
Debug.Assert(reader.LocalName == "produto");
Produto produto = new Produto();
if (reader.IsEmptyElement)
{
// Vazio, não tem filhos. Avança pro próximo nó e retorna
ReadToNextElementOrEndElement(reader);
return produto;
}
ReadToNextElementOrEndElement(reader);
do
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name == "id")
{
produto.ID = reader.ReadString();
if (reader.NodeType == XmlNodeType.EndElement) ReadToNextElementOrEndElement(reader);
}
else if (reader.Name == "dados")
{
produto.Dados = ReadDados(reader);
}
else if (reader.Name == "formato")
{
produto.Formato = ReadFormato(reader);
}
else
{
throw new ArgumentException("No do XML nao reconhecido");
}
}
else
{
ReadToNextElementOrEndElement(reader);
}
} while (reader.NodeType != XmlNodeType.EndElement);
Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
ReadToNextElementOrEndElement(reader); // avança pro próximo produto ou fim
return produto;
}
static Dados ReadDados(XmlReader reader)
{
Debug.Assert(reader.NodeType == XmlNodeType.Element);
Debug.Assert(reader.LocalName == "dados");
Dados dados = new Dados();
if (reader.IsEmptyElement)
{
// Vazio, não tem filhos. Avança pro próximo nó e retorna
ReadToNextElementOrEndElement(reader);
return dados;
}
do
{
ReadToNextElementOrEndElement(reader);
if (reader.NodeType == XmlNodeType.Element && reader.Name == "categoria")
{
dados.Categoria = reader.ReadString();
if (reader.NodeType == XmlNodeType.EndElement) reader.Read();
}
} while (reader.NodeType != XmlNodeType.EndElement || reader.Name != "dados");
Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
ReadToNextElementOrEndElement(reader); // avança pro próximo produto ou fim
return dados;
}
static Formato ReadFormato(XmlReader reader)
{
Debug.Assert(reader.NodeType == XmlNodeType.Element);
Debug.Assert(reader.LocalName == "formato");
Formato formato = new Formato();
if (reader.IsEmptyElement)
{
// Vazio, não tem filhos. Avança pro próximo nó e retorna
ReadToNextElementOrEndElement(reader);
return formato;
}
do
{
ReadToNextElementOrEndElement(reader);
if (reader.NodeType == XmlNodeType.Element && reader.Name == "categoria")
{
formato.Categoria = reader.ReadString();
if (reader.NodeType == XmlNodeType.EndElement) reader.Read();
}
} while (reader.NodeType != XmlNodeType.EndElement || reader.Name != "formato");
Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
ReadToNextElementOrEndElement(reader); // avança pro próximo produto ou fim
return formato;
}
static bool ReadToNextElementOrEndElement(XmlReader reader)
{
do
{
if (!reader.Read()) return false;
} while (reader.NodeType != XmlNodeType.Element && reader.NodeType != XmlNodeType.EndElement);
return true;
}
}
class Produto
{
public string ID { get; set; }
public Dados Dados { get; set; }
public Formato Formato { get; set; }
public override string ToString()
{
return string.Format("Produto[ID={0}, Dados/Cat={1}, Formato/Cat={2}]", ID, Dados.Categoria, Formato.Categoria);
}
}
class Dados
{
public string Categoria { get; set; }
}
class Formato
{
public string Categoria { get; set; }
}