XML

XML é uma linguagem de marcação que serve para definir linguagens de marcação. Sendo assim, cada aplicativo pode fazer sua própria linguagem de marcação e interpretá-la da maneira que achar mais conveniente. Nesta página será explicado como ler arquivos XML além de citar outros recursos relacionados a esta linguagem bem difundida.

SAX e DOM

As duas APIs mais famosas para ler XML são SAX e DOM.

SAX

A API SAX é baseada em eventos. Ela lê sequencialmente o XML e quando acha um evento dispara uma função de callback definida pelo usuário. Em termos mais simples a API SAX lê o arquivo XML encontrando e reconhecendo algumas coisas no XML como quando ela está diante do conteúdo de texto de uma TAG, ou quando uma Tag XMl é aberta, ou quando ela é fechada, dentre outras. Tais coisas são chamadas eventos e para cada evento ela (a API SAX) chama uma função que o usuário especificou para ser chamada quando encontrado tal evento.

DOM

A API DOM (Document Object Model) é uma especificação mantida pela W3C, a mesma organização responsável pela manutenção do padrão XML. Basicamente ele especifica que a marcação XML é primeiramente lida, sendo construído como um resultado do processo uma árvore. Para navegar e manipular o conteúdo dessa árvore há uma série de funções que tornam essas duas tarefas fáceis.

Conclusão

Das duas APIs a DOM é bastante utilizada por vários navegadores de internet, podendo ser utilizada em diversos softwares, contudo como ela mantém uma árvore que representa a marcação XML inteira a principal desvantagem dela é a memória consumida. Como vantagem tem a fácil manipulação e navegação do conteúdo da árvore que está acessível a qualquer momento para o programador.
Com relação a SAX, por ela fazer uma leitura sequencial e não preservar nada por si só do que foi lido no XML, seu consumo de memória é baixo, principal ponto positivo dela. No entanto é por conta do programador armazenar o que realmente lhe interessa. Desta forma se há necessidade de consultas/operações constantes em relação ao XML por si ou se há alguma necessidade de manter o conteúdo, o programador terá fazer isso a mão. Para esses caso APIs que fazem uso do DOM seriam uma melhor escolha.

Linguagens + XML

Para testar as APIs relacionadas a XML o seguinte trecho de XML será usado (Arquivo teste.xml)

<teste>
    <file>hhhh</file>
</teste>

C/C++

libxml2

(TODO)

expat

(TODO)

IrrXML

O arquivo sendo analisado é

<teste>
    <arq>C:\teste</arq>
    <num_arq>10</num_arq>
</teste>
#include "../xml/irrXML.h"
#include <cstdlib>
#include <cstring>

using namespace irr;
using namespace irr::io;

void testParse();
void parseTesteTag(IrrXMLReader*);
bool advanceTag( IrrXMLReader* );
char * parseText( IrrXMLReader* );

int main( int argc, char** argv )

    testParse();

    return 0;
}

// função principal
void testParse(){
    IrrXMLReader* xmlReader = createIrrXMLReader("outros/teste.xml");

    if( !xmlReader ) {
        puts("Não foi possível criar o parser");
        exit(EXIT_FAILURE);
    }

    parseTesteTag(xmlReader);
}

void parseTesteTag(IrrXMLReader* xmlReader){

    bool advanced = advanceTag( xmlReader );

    if( !advanced ){
        puts( "ERRO. Não conseguiu avançar");
        exit(-1);
    }

    if( (xmlReader->getNodeType() != EXN_ELEMENT)
            || (strcmp( xmlReader->getNodeName(), "teste" ) != 0) )
    {
        puts("Erro no parse. Tag não é teste");
        exit(-1);
    }

    advanced = advanceTag( xmlReader );

    if( !advanced ){
        puts( "ERRO. Não conseguiu avançar");
        exit(-1);
    }

    if( (xmlReader->getNodeType() == EXN_ELEMENT)
            && (strcmp( xmlReader->getNodeName(), "arq" ) != 0) )
    {
        puts("Erro no parse. Tag não é arq");
    }

    //char contents[256];
    //
    char *arq = parseText( xmlReader );
    printf("Arq = %s\n", arq);

    if( (xmlReader->getNodeType() == EXN_ELEMENT_END)
            && (strcmp( xmlReader->getNodeName(), "arq" ) != 0) )
    {
        puts("Erro no parse. Tag não é a tag de fechamento de arq");
        exit(-1);
    }

    advanced = advanceTag( xmlReader );

    if( !advanced ){
        puts( "ERRO. Não conseguiu avançar");
        exit(-1);
    }

    if( (xmlReader->getNodeType() == EXN_ELEMENT)
            && (strcmp( xmlReader->getNodeName(), "num_arq" ) != 0) )
    {
        puts("Erro no parse. Tag não é num_arq");
        exit(-1);
    }

    //char contents[256];
    //
    char *num_arq = parseText( xmlReader );
    printf("Num Arq = %s\n", num_arq);

    if( (xmlReader->getNodeType() == EXN_ELEMENT_END)
            && (strcmp( xmlReader->getNodeName(), "num_arq" ) != 0) )
    {
        puts("Erro no parse. Tag não é a tag de fechamento de num_arq");
        exit(-1);
    }

    // faz o parse de texto (incluindo espaço em branco) que não interessa
    char *lixo = parseText( xmlReader );

    if( (xmlReader->getNodeType() == EXN_ELEMENT_END)
            && (strcmp( xmlReader->getNodeName(), "teste" ) != 0) )
    {
        puts("Erro no parse. Tag não é a tag de fechamento de teste");
        exit(-1);
    }

    puts( "Sucesso na leitura" );
}

// posiciona na próxima tag de início ou retorna false para declarar
// que não consegue mais ler nada
bool advanceTag( IrrXMLReader* reader ){
    bool hasMore = true;

    while( (hasMore = reader->read()) ){

        if( (reader->getNodeType() == EXN_ELEMENT) ){
            return true;
        }
    }

    return false;
}

// faz o parse do elmeento texto
char * parseText( IrrXMLReader* reader ){
    //int tamanho = 0;
    char* contents = new char[1024];
    memset( contents, 0, 1024);

    bool hasMore = true;

    while( (hasMore = reader->read()) && reader->getNodeType() == EXN_TEXT ){
        const char *temp = reader->getNodeData();
        strcat( contents, temp );
    }

    return contents;
}

Xerces

(TODO)

Java

SAX

O arquivo de teste a ser usado com código Java é o seguinte

<?xml version="1.0" encoding="utf-8" ?>
<bookstore>
  <book>
    <title>The Autobiography of Benjamin Franklin</title>
    <author>
      <first-name>Benjamin</first-name>
      <last-name>Franklin</last-name>
    </author>
    <price>8.99</price>
  </book>
 
  <book>
    <title>The Confidence Man</title>
    <author>
      <first-name>Herman</first-name>
      <last-name>Melville</last-name>
    </author>
    <price>11.99</price>
  </book>
 
  <book>
    <title>The Gorgias</title>
    <author>
      <name>Plato</name>
    </author>
    <price>9.99</price>
  </book>
</bookstore>

O Código em Java é o seguinte:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
 
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
 
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
 
public class SaxReader extends DefaultHandler {
 
    public SaxReader(InputStream stream) throws ParserConfigurationException, SAXException, IOException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser();
        parser.parse(stream, this);
    }
 
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        System.out.print( qName + ": " );
    }
 
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        char substring[] = new char[length];
 
        for (int i = 0; i < length; i++) {
            substring[i] = ch[i + start];
        }
 
        String text = new String( substring ).trim();
 
        if( text.length() > 0 ) System.out.println( text );
    }
 
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
    }
 
    public static void main(String[] args) {
        try {
            FileInputStream inputStream = new FileInputStream( "Simple.xml" );
            SaxReader reader = new SaxReader(inputStream);
        } catch (ParserConfigurationException | SAXException | IOException e) {
            System.out.println( "Não foi possível ler o arquivo Simple.xml" );
            e.printStackTrace();
        }
    }
 
}

JAXP

O arquivo de teste a ser usado com código Java é o seguinte

<?xml version="1.0"?>
<company>
    <employee>
        <firstname>Tom</firstname>
        <lastname>Cruise</lastname>
    </employee>
    <employee>
        <firstname>Paul</firstname>
        <lastname>Enderson</lastname>
    </employee>
    <employee>
        <firstname>George</firstname>
        <lastname>Bush</lastname>
    </employee>
</company>

Uma implementação que faz o parse do arquivo acima usando DOM é a seguinte:

public static void main(String[] args) {
        try {
            File file = new File("src" + File.separatorChar +  "xmlfiles" + File.separatorChar + "simpleexample.xml");
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(file);
            doc.getDocumentElement().normalize();
            System.out.println( "Root element: " + doc.getDocumentElement().getNodeName() );
            NodeList nodeList = doc.getElementsByTagName("employee");
            System.out.println( "Information of all employees" );
 
            for (int s = 0; s < nodeList.getLength(); s++) {
                Node fstNode = nodeList.item(s);
 
                if( fstNode.getNodeType() == Node.ELEMENT_NODE ){
                    Element fstElmnt = (Element) fstNode;
                    NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("firstname");
                    Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
                    NodeList fstNm = fstNmElmnt.getChildNodes();
                    System.out.println( "First name: " + ( (Node) fstNm.item(0) ).getNodeValue() );
                    NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("lastname");
                    Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
                    NodeList lstNm = lstNmElmnt.getChildNodes();
                    System.out.println( "Last name:" + ( (Node) lstNm.item(0)).getNodeValue() );
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Nesse exemplo primeiro é recuperada uma lista de todos os empregados ("Employee"). Após ser recuperada a lista seus conteúdos são impressos.

JAXB

(TODO)

Xerces

(TODO)

.Net

Leitura usando XMLTextReader

(Exemplo retirado de: http://www.k19.com.br/artigos/leitura-e-escrita-de-arquivos-xml-em-c/)

O arquivo XML usado como exemplo é:

<?xml version="1.0" encoding="utf-8" ?>
<bookstore>
  <book>
    <title>The Autobiography of Benjamin Franklin</title>
    <author>
      <first-name>Benjamin</first-name>
      <last-name>Franklin</last-name>
    </author>
    <price>8.99</price>
  </book>
 
  <book>
    <title>The Confidence Man</title>
    <author>
      <first-name>Herman</first-name>
      <last-name>Melville</last-name>
    </author>
    <price>11.99</price>
  </book>
 
  <book>
    <title>The Gorgias</title>
    <author>
      <name>Plato</name>
    </author>
    <price>9.99</price>
  </book>
</bookstore>

O Código em C# é:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
 
namespace TesteXMLSimples
{
    class Program
    {
 
        static void Main(string[] args)
        {
            //abre um stream para a leitura do arquivo xml
            XmlTextReader leitor = new XmlTextReader("simple.xml");
 
            while (leitor.Read())
            {
                //verificacao do tipo de nó lido
                switch (leitor.NodeType)
                {
                    case XmlNodeType.Element: // The node is an element.
                        System.Console.Write(leitor.Name);
                        System.Console.Write(": ");
                        break;
                    case XmlNodeType.Text: //Display the text in each element.
                        System.Console.WriteLine(leitor.Value);
                        break;
                    case XmlNodeType.EndElement: //Display the end of the element.
                        break;
                }
            }
 
            //fechamento do arquivo XML
            leitor.Close();
 
            Console.Read();
        }
    }
}

Leitura usado XMLDocument (DOM)

O XML é o mesmo do exemplo acima (Leitura usando XMLTextReader)

O código é o seguinte

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
 
namespace TesteXMLSimples
{
    class Program
    {
 
        static void Main(string[] args)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load("simple.xml");
 
            // ignora os espaços em branco
            doc.PreserveWhitespace = false;
 
            XmlNode root = doc.DocumentElement;
            printContents(root);
 
            Console.Read();
        }
 
        private static void printContents(XmlNode node)
        {
            if (node.NodeType == XmlNodeType.Text)
            {
                Console.WriteLine(node.Value);
            }
            else if (node.NodeType == XmlNodeType.Element)
            {
                Console.Write(node.Name + ":");
 
                foreach (XmlNode child in node.ChildNodes)
                {
                    printContents(child);
                }
            }
        }
    }
}

Criando e Salvando XML usando XMLDocument (DOM)

Código retirado de http://msdn.microsoft.com/pt-br/library/bb387021.aspx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
 
namespace TesteXMLSimples
{
    class Program
    {
 
        static void Main(string[] args)
        {
            XmlDocument doc = new XmlDocument();
            XmlElement name = doc.CreateElement("Name");
            name.InnerText = "Patrick Hines";
            XmlElement phone1 = doc.CreateElement("Phone");
            phone1.SetAttribute("Type", "Home");
            phone1.InnerText = "206-555-0144";
            XmlElement phone2 = doc.CreateElement("Phone");
            phone2.SetAttribute("Type", "Work");
            phone2.InnerText = "425-555-0145";
            XmlElement street1 = doc.CreateElement("Street1");
            street1.InnerText = "123 Main St";
            XmlElement city = doc.CreateElement("City");
            city.InnerText = "Mercer Island";
            XmlElement state = doc.CreateElement("State");
            state.InnerText = "WA";
            XmlElement postal = doc.CreateElement("Postal");
            postal.InnerText = "68042";
            XmlElement address = doc.CreateElement("Address");
            address.AppendChild(street1);
            address.AppendChild(city);
            address.AppendChild(state);
            address.AppendChild(postal);
            XmlElement contact = doc.CreateElement("Contact");
            contact.AppendChild(name);
            contact.AppendChild(phone1);
            contact.AppendChild(phone2);
            contact.AppendChild(address);
            XmlElement contacts = doc.CreateElement("Contacts");
            contacts.AppendChild(contact);
            doc.AppendChild(contacts);
 
            doc.Save("contacts.xml");
 
            Console.WriteLine("Salvo contacts.xml");
            Console.Read();
        }
    }
}

Geração e gravação de XML usando LINQ To XML

Código retirado de http://msdn.microsoft.com/pt-br/library/bb387021.aspx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
 
namespace TesteXMLSimples
{
    class Program
    {
 
        static void Main(string[] args)
        {
            XElement contacts =
            new XElement("Contacts",
                new XElement("Contact",
                    new XElement("Name", "Patrick Hines"),
                    new XElement("Phone", "206-555-0144",
                        new XAttribute("Type", "Home")),
                    new XElement("phone", "425-555-0145",
                        new XAttribute("Type", "Work")),
                    new XElement("Address",
                        new XElement("Street1", "123 Main St"),
                        new XElement("City", "Mercer Island"),
                        new XElement("State", "WA"),
                        new XElement("Postal", "68042")
                    )
                )
            );
 
            contacts.Save("contacts.xml");
            Console.WriteLine("Salvo contacts.xml");
            Console.Read();
        }
    }
}

Python

Uma das maneiras de ler XMl em Python é usar o minidom que já vem em distribuições Python recentes

Retirado/adaptado de http://www.travisglines.com/web-coding/python-xml-parser-tutorial

#!/usr/bin/python
# import easy to use xml parser called minidom:
from xml.dom.minidom import parseString
 
# all these imports are standard on most modern python implementations
 
# open the xml file for reading:
file = open('teste.xml','r')
 
# convert to string:
data = file.read()
 
# close file because we dont need it anymore:
file.close()
 
# parse the xml you got from the file
dom = parseString(data)
 
# retrieve the first xml tag (<tag>data</tag>) that the parser finds with name tagName:
xmlTag = dom.getElementsByTagName('teste')[0].toxml()
 
# strip off the tag (<tag>data</tag>  --->   data):
xmlData=xmlTag.replace('<teste>','').replace('</teste>','')
 
# print out the xml tag and data in this format: <tag>data</tag>
print xmlTag
 
# just print the data
print xmlData

Haxe

(falar sobre Haxe.Xml.Fast)

import nme.display.Sprite;
import haxe.xml.Fast;

class Main extends Sprite {
    var xmlString = 
        "<user name='john' age='24'>
            <phone>
                <number>0000</number>
                <number>111</number>
            </phone>
        </user>
        ";

    public function new () {

        super ();

        // parse some xml data
        var xml = Xml.parse(xmlString);

        // wrap the xml for fast access
        var fast = new Fast( xml.firstElement() );

        // access attributes
        trace( fast.att.name );    // atribute "name"
        if( fast.has.age ) trace( fast.att.age );    // optional attribute

        // access the "phone" child, which is wrapped with haxe.xml.Fast too
        var phone = fast.node.phone;

        // iterate over numbers
        for( p in phone.nodes.number ){
            trace( p.innerData );
        }
    }
}

Links

(página da especificação do padrão XML)
(links relacionados)

http://support.microsoft.com/kb/317662/pt: Ler e Guardar XML no C# usando DOM

http://elegantcode.com/2010/08/07/dont-parse-that-xml/ Descreve como gerar classes e o parser a partir de arquivos XML. Explicando como fazer isso para .Net e Java

xml
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-Share Alike 2.5 License.