Countdown

Final Countdown

Faltam dias. Ou segundos.

segunda-feira, 25 de maio de 2015

#22) Arquivos XML em Java

Boa noite!

Hoje apresento a vocês o formato de arquivo .xml (eXtensible Markup Language), o qual é muito utilizado para o armazenamento das principais configurações de software e informações diversas, desde variáveis do programa até informações sobre os diretórios de arquivos utilizados no projeto, como por exemplo, o diretório de um arquivo de imagens.

Seu emprego se deve à sua simplicidade e universalidade (possui infraestrutura única que pode ser usada por diversas linguagens de programação). É muito usada par ao compartilhamento de informações através da internet e tem forte semelhança com a estrutura da linguagem HTML.


Exemplo de arquivo .xml.

Seu conteúdo pode ser editado como um documento de texto simples, igual ao formato .html, tornando-o ainda mais interessante. Além disso, até os comentários seguem o mesmo padrão de HTML: (<!--comentário-->).

Arquivo .xml gerado pelo projeto Bizuca.

---//---


Vamos agora trabalhar em um pequeno exemplo de como implementar uma classe geradora e leitora de arquivos .xml para gerenciar as informações de nosso programa.


--- [Estrutura da Classe] ---

Os principais métodos da classe que manipulam o arquivo .xml são os seguintes:

---> loadXML()
Método que verifica a existência do arquivo XML. Caso exista, lê o arquivo. Caso contrário, o cria usando valores default.Em Game.java também há invocações diretas para gerar o arquivo .xml, salvando alterações das configurações do jogo.

------> lerXml(); 
Faz o mapeamento das configurações descritas no arquivo .xml e as variáveis do objeto da classe Config.java. Em outras palavras, carrega as configurações do arquivo e as atribui devidamente.

------> gerarXml();
Cria um documento com as informações do programa (variáveis da classe Config.java) e chama o conversor do documento para .xml. Depois de realizada a operação, chama o método para salvar o arquivo final.

---------> converter();
A partir do documento recebido como parâmetro, faz a conversão ao formato .xml.

---------> salvarArquivo();
Salva o arquivo .xml gerado.

--- [Implementação] ---


Primeiramente, vamos importar as bibliotecas necessárias. Vamos usar as API's nativas do JDK para isso, de modo que não é necessário adicionar bibliotecas externas:

import org.w3c.dom.*;
import org.xml.sax.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;


Como queremos um objeto da classe de configurações global, vamos implementá-lo segundo as técnicas aprendidas no post passado. Logo em seguida, já podemos declarar as variáveis do arquivo de configurações, bem como definir sua inicialização padrão (caso não seja possível carregar o arquivo .xml):

public class Config 
{
    private static Config instance;
    public static Config getInstance(){
        if (instance == null) instance = new Config();
        return instance;
    }
    
    // Variáveis diversas
   
    public String title = "Web Bizuca";
    public int HTela = 1280, VTela = 720;
    
    //...

---[ loadXML() ]---

Então, agora vamos criar um método intermediário entre a classe de configurações e a classe que faz uso destas configurações, que deverá ser invocado no escopo da classe que faz uso destas configurações:

    private static File file = new File("src\\config.xml");

    public void loadXML()
    {
        try{
            if (file.exists())
                lerXml();
            else gerarXml();
        } catch(Exception e){}
    }

---[ gerarXML() ]---

Se o arquivo .xml não for encontrado, o procedimento é utilizar os valores padrão de variável atribuídos no próprio escopo da classe. A partir destes dados, é gerado um novo arquivo .xml atrave´s do método gerarXml(). O mesmo método é empregado pode ser empregado na classe de utilização para guardar alterações de modificação das configurações do programa. Esse método tem a seguinte estrutura:

[ funcionamento ]

-> Deleta o arquivo .xml, caso ele exista

-> Cria um novo documento e adiciona Elementos (Tags) a ele:
Element WindowTitle = doc.createElement("Title");

-> A cada Tag, pode ser atribuído um conteúdo interno a ele:
WindowTitle.setTextContent("Web Bizuca");

-> Cada Tag filha deve ser depois adicionada a uma Tag pai ou ao próprio documento:
subTagWindowConfig.appendChild(WindowTitle);

doc.appendChild(tagConfig);

-> Depois de criado o documento, é preciso convertê-lo ao formato .xml, que é feito usando a função converter()

-> O arquivo .xml editado é salvo

[ funcionamento ]


O código exemplo ilustrativo é mostrado abaixo:

public void gerarXml() throws Exception 
    {
        if (file.exists()) file.delete();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.newDocument();
        
        Element tagConfig = doc.createElement("Config");
        
            Element subTagWindowConfig = doc.createElement("Config_Window");
        
                Element WindowTitle = doc.createElement("Title");
                Element WindowWidth = doc.createElement("Window_Width");
                Element WindowHeigth = doc.createElement("Window_Height");
                
                WindowTitle.setTextContent("Web Bizuca");
                WindowWidth.setTextContent(""+HTela);
                WindowHeigth.setTextContent(""+VTela);
    
                subTagWindowConfig.appendChild(WindowTitle);
                subTagWindowConfig.appendChild(WindowWidth);
                subTagWindowConfig.appendChild(WindowHeigth);
                 
            tagConfig.appendChild(subTagWindowConfig);

        doc.appendChild(tagConfig);
        
        String arquivo = converter(doc);
        salvarArquivo(arquivo);
    }

---[ converter() ]---

Basicamente, converte o documento que é recebido como parâmetro para o formato padrão de um arquivo .xml, cujo conteúdo é retornado em forma de string.

    private static String converter(Document document) throws TransformerException {
        Transformer transformer
                = TransformerFactory.newInstance().newTransformer();

        transformer.setOutputProperty(OutputKeys.INDENT, "yes");

        StreamResult result = new StreamResult(new StringWriter());
        DOMSource source = new DOMSource(document);
        transformer.transform(source, result);

        String xmlString = result.getWriter().toString();
        return xmlString;
    }

[ lerXml() ]

Abre o arquivo .xml e, a partir da identificação das Tags, faz a leitura dos dados do arquivo e atribui seus valores às variáveis da classe de configurações, como o exemplo abaixo:

 private static void lerXml() throws Exception, SAXException, TransformerException 
    {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(new InputSource(file.toString()));
        
        Element raiz = doc.getDocumentElement();
        
        NodeList endList = raiz.getElementsByTagName("Config_Window");
        Element endElement = (Element) endList.item(0);
        
        instance.title = getChildTagValue(endElement, "Title");
        instance.HTela = Integer.parseInt(getChildTagValue(endElement,"Window_Width"));
        instance.VTela = Integer.parseInt(getChildTagValue(endElement,"Window_Height"));
        
    }

[ getChildTagValue() ]

Faz a busca do valor de determinada Tag do arquivo .xml, retornando o seu valor:

       public static String getChildTagValue(Element elem, String tagName) throws Exception {
            NodeList children = elem.getElementsByTagName(tagName);
            String result = null;
            if (children == null)
                return result;
            Element child = (Element) children.item(0);
            if (child == null) 
                return result;
            result = child.getTextContent();
            return result;
        }

--- [Conclusão] ---


Fizemos neste post a geração e leitura manual das informações de um arquivo .xml, o que pode ser um processo um tanto penoso em um projeto grande. Poderíamos ter usado Arrays / ArrayLists para gravar estas informações, porém seria mais difícil saber a finalidade de cada uma das variáveis se não houver uma boa documentação sobre elas, de forma que por finalidades didáticas preferimos nomear uma a uma as variáveis de configuração.

Qualquer dúvida, acesse uma das referências ou consulte a classe Config.java do projeto Web Bizuca, disponibilizado no link abaixo:
https://github.com/ftuyama/Web-Bizuca


Referências:

http://pt.wikipedia.org/wiki/XML
http://www.mballem.com/post/manipulando-arquivo-xml-parte-i-api-nativa/

Nenhum comentário:

Postar um comentário