Desenvolvimento - C#

Lidando com XML de vários níveis em C#

Veja neste artigo como trabalhar com arquivos XML com vários níveis de profundidade utilizando a linguagem C#.

por Rodolpho Timoteo Carvalho Portilho



Documentos XML são muito presentes na vida de qualquer um. Quando acessamos um site, entramos em algum jogo, acessamos nossas informações em um cadastro de site, documentos XML estão transitando pela rede. Eles foram feitos para guardar informações e organiza-las em uma estrutura hierárquica.

É comum vermos XML’s com uma organização que se assemelha muito ao modelo relacional de banco de dados, pois é fácil representar a imagem de um banco de dados SQL em um arquivo XML.

Listagem 1: Exemplo Comum de um XML relacional

<?xml version="1.0" encoding="UTF-8"?>
<xml>
  <Banco_de_dados>
    <Tabela1>
      <Dado1></Dado1>
      <Dado2></Dado2>
      <Dado3></Dado3>
    </Tabela1>
    <Tabela2>
      <Dado4></Dado4>
      <Dado5></Dado5>
      <Dado6></Dado6>
    </Tabela2>
    <Tabela3>
      <Dado7></Dado7>
      <Dado8></Dado8>
      <Dado9></Dado9>
    </Tabela3>
  </Banco_de_dados>
</xml>

Para nós programadores, a preocupação é poder manipular estes documentos da melhor forma o mais rápido possível. Para aqueles documentos XML que possuem estrutura parecida com a acima, temos a certeza de que o documento não fugirá do proposto, assim podemos codificar um leitor somente para este tipo de documento.

No entanto, vários documentos foram XML foram feitos com uma estrutura irregular, aonde um nó pode ter filhos, e estes filhos por sua vez, outros filhos.

Listagem 2: XML com uma estrutura variada

<?xml version="1.0" encoding="UTF-8"?>
<xml>
  <Nivel1>
    <Nivel2>
      <Nivel3>
        <Nivel4>
          <Dado>Farmácia</Dado>
        </Nivel4>
      </Nivel3>
    </Nivel2>
  </Nivel1>
</xml>

Pergunta: Mas em que situação vou construir um XML assim?

Imagine várias entidades do mesmo tipo. Você pode definir, para cada entidade, comportamentos que podem ou não acontecer. A presença ou não destes comportamentos e a qualidade deles em uma entidade é o que diferencia cada uma delas. A organização destes comportamentos, em um XML, é a especialização em níveis em cada nó (entidade).

Um bom exemplo é o tipo KML, que é um formato de arquivo usado para exibir dados geográficos em um navegador da Terra, como Google Earth.

Um sistema de organização contábil pode utilizar bem destes conceitos.

Utilizando a linguagem C#, vou mostrar, em seguir, como fazer um XML com uma estrutura de vários níveis e como buscar informações de maneira fácil em qualquer documento.

Segue um exemplo de criação de um arquivo XML de vários níveis:

Listagem 3: Exemplo da criação do XML da listagem 2

//Cria um documento XML
        XmlDocument _xmlDocument = new XmlDocument();
        //Cria um objeto de informacoes do XML
        XmlNode declaration = _xmlDocument.CreateXmlDeclaration("1.0", "UTF-8", "");
        //Adciona as informacoes de versao e codificacao
        _xmlDocument.AppendChild(declaration);
        //Cria um nó raiz
        XmlNode nodexml = _xmlDocument.CreateElement("xml");
        //adciona o no raiz ao documento
        _xmlDocument.AppendChild(nodexml);

        XmlNode nivel1 = _xmlDocument.CreateElement("nivel1");
        //Nó Xml adciona nó Nivel1
        nodexml.AppendChild(nivel1);
        XmlNode nivel2 = _xmlDocument.CreateElement("nivel2");
        //Nó nivel1 adciona nó nivel2
        nivel1.AppendChild(nivel2);
        XmlNode nivel3 = _xmlDocument.CreateElement("nivel3");
        //Nó nivel2 adciona nó nivel3
        nivel2.AppendChild(nivel3);
        XmlNode nivel4 = _xmlDocument.CreateElement("nivel4");
        //Nó nivel3 adciona nó nivel4
        nivel3.AppendChild(nivel4);
        XmlNode dado = _xmlDocument.CreateElement("dado");
        //Nó nivel4 adciona nó dado
        nivel4.AppendChild(dado);
        //Nó dado adciona texto Farmácia
        dado.AppendChild(_xmlDocument.CreateTextNode("Farmácia"));
        //Salva o XML
        _xmlDocument.Save("C:\\xmlExemplo.xml");

Em cada nível do XML podemos criar vários irmãos (nós do documento que estão no mesmo nível). Podemos também criar n níveis dependendo da necessidade.

Na busca em um documento desta forma, é interessante encararmos o XML como uma arvore. Documentos que possuem uma estrutura muito irregular dos dados acaba não compensando fazer um leitor para ele. Uma busca recursiva seria interessante.

Listagem 4: Busca em um arquivo XML de vários níveis

//Funcao Recursiva
//É capaz de nos retornar a referencia de qualquer nó no arquivo xml
//sendo descendente do no passado na funcao.
public static XmlNode BuscaXml(XmlNode node, String NodeName)
{
    //se é o que estamos procurando, o retorna
    if (node.Name == NodeName)
        return node;
    //caso este no nao possua filhos, retorne null
    if (node.ChildNodes.Count == 0)
        return null;

    XmlNode No_temp;
    //para cada filho de um determinado nó.
    foreach (XmlNode no in node.ChildNodes)
    {
        //inicia recursao
        No_temp = BuscaXml(no, NodeName);
        
        //caso nao exista, continua a iteracao
        if (No_temp == null)
            continue;
        //caso exista, retorne para continuar a busca
        else
            return No_temp;
    }
    //caso nao encontre...
    return null;
} 

Na função acima podemos passar qualquer nó na qual queremos iniciar a busca. É importante notar que estamos buscando pelo nome do nó. Se houver nós com o mesmo nome ele retornará o primeiro que encontrar. A função acima pode ser usada para encontrar dados ou até atributo de nós, basta mudar a comparação feita.

Devido ao caráter de profundidade desta busca recursiva, se um nó estiver longe do inicio da busca, o desempenho cairá pois a busca passará pela maioria dos nós do documento.

Se o XML for muito grande, é bom atentar-se a detalhes de desempenho.

Com isto finalizo este artigo, espero que tenho ajudado a expandir as ideias dos leitores acerca dos documentos XML. Qualquer sugestão ou erro por favor comente.

Um abraço.

Rodolpho Timoteo Carvalho Portilho

Rodolpho Timoteo Carvalho Portilho