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.
Table of Contents
|
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