XmlTextReader () identify node end and duplicate tags

1

1 - How to identify equal tags with different nodes? ex: Categoria within Dados and Formato

2 - How to identify that one product ended and another one started?

I have the (fictitious) XML:

<produtos>
  <produto>
    <id>1</id>
    <dados>
       <categoria>teste</categoria>
    </dados>
    <formato>
    <categoria>teste2</categoria>
    </formato>
  </produto>
  <produto>
    <id>2</id>
     ...
  </produto>
</produtos>

NO C #

var produtos = new List<produto>();
var produto = new produto();
using (var reader = new XmlTextReader("aquivo.XML"))
{
    while (reader.Read())
    {
        if (reader.IsStartElement())
        {
            if (reader.Name == "ID")
            {
                produto.ID = reader.ReadString();
            }
            else if (reader.Name == "categoria") //?? 
            {
                produto.Dados.categoria = reader.ReadString();
            }
            else if (reader.Name == "categoria") //??
            {
                produto.Formato.categoria = reader.ReadString();
            }
        }
    //Final de produto
    produtos.Add(produto);
    }
}

He is reading the data correctly, but I do not know how to identify the end of a product and understand what tag, father it is.

NOTE: I did not want to do it in XMLDocument or another format, since I already have enough of the code already working. change would only be in the latter case.

    
asked by anonymous 14.01.2016 / 19:19

2 answers

1

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; }
}
    
14.01.2016 / 21:24
2

This is the hard way to deserialize an XML product.

It can be done as follows:

[XmlRoot("produtos")]
public class ListaProdutos
{
    [XmlElement("produto")]
    public List<Produto> Produtos { get; set; }
}

public class Produto
{
    [XmlElement("id")]
    public int Id { get; set; }
    [XmlElement("dados")]
    public Dados Dados { get; set; }
    [XmlElement("formato")]
    public Formato Formato { get; set; }
}

public class Dados
{
    [XmlElement("categoria")]
    public String Categoria { get; set; }
}

public class Formato
{
    [XmlElement("categoria")]
    public String Categoria { get; set; }
}

Usage:

XmlSerializer serializer = new XmlSerializer(typeof(ListaProdutos));
using (TextReader reader = new StringReader(stringComXml))
{
    var resultado = (ListaProdutos) serializer.Deserialize(reader);
}
    
14.01.2016 / 21:23