XML API: DOM e SAX Prof. Dr. Cláudio Baptista [email protected] http://www.lsi.dsc.ufcg.edu.br 1 Processamento de docs XML Um arquivo XML é um arquivo de texto Portanto, a manipulação de XML pode ser feita através da leitura deste texto Entretanto, existem APIs que facilitam este acesso a um doc XML 2 Parser XML O parser tem a função de verificar se um doc XML está sintaticamente correto; ou bem-formado O parser deve parar o processamento caso o documento não esteja bemformado (uma exceção é lançada) 3 Parser XML Lê o doc XML Verifica se é bem-formado Opcionalmente, Valida com um DTD ou XMLSchema Fornece uma API que facilita a manipulação do doc XML via aplicação 4 Processadores XML Três tipos de API para XML parsing: SAX (Simple API to XML): baseada em eventos DOM (Document Object Model): objetos/árvore JDOM (Java Documet Object Model): Objetos/árvores 5 Processadores XML Há parsers para várias plataformas e ambientes de software Parsers baseados em SAX são mais rápidos Parsers baseados em DOM são mais versáteis, pois criam uma versão em memória do documento inteiro Validação tende a ser mais lenta do que verificação 6 DOM W3C standard recommendation Constrói árvore na memória para documentos XML Um DOM Document é uma coleção de nodes organizada numa hierarquia DOM provê uma API que permite o programador adicionar, editar, mover, ou remover nodes em qualquer ponto da árvore DOM-based parsers fazem o “parsing” destas estruturas. Existe em várias linguagens (Java, C, C++, Python, Perl, etc.) www.w3.org/DOM/ java.sun.com/webservices/docs/1.0/tutorial/doc/JAXPDOM.html 7 DOM Manipulação XML com Java Java XML Pack java.sun.com/xml/downloads/javaxmlpack.html Xerces – Apache XML Parser Antigo IBM/XML4J Suporta além de Java 1 e 2, C++, Perl dentre outros. 8 DOM Roadmap Um Parser analiza um arquivo XML para criar um DOM document que é composto de nodes que podem ser elementos, atributos, textos,ou outros tipos de node que fazem parte de um (ou mais) Namespace(s) que podem ser acessados via métodos da DOM API 9 Evolução do DOM Level 0 - Foi a primeira recomendação que permitia Web browsers identificar e manipular elementos numa página Level 1- inclui suporte a XML e HTML Level 2- permite o uso de Namespaces, provê API mais sofisticada com eventos e CSS Level 3- suporte avançado a Namespaces, eventos de User interface, DTD, XML Schema, Xpath, XSLT 10 Exemplo <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ORDERS SYSTEM "orders.dtd"> <orders> <order> <customerid limit="1000">12341</customerid> <status>pending</status> <item instock="Y" itemid="SA15"> <name>Silver Show Saddle, 16 inch</name> <price>825.00</price> <qty>1</qty> </item> <item instock="N" itemid="C49"> <name>Premium Cinch</name> <price>49.00</price> <qty>1</qty> </item> </order> <order> <customerid limit="150">251222</customerid> <status>pending</status> <item instock="Y" itemid="WB78"> <name>Winter Blanket (78 inch)</name> <price>20</price> <qty>10</qty> </item> </order> </orders> 11 Exemplo (cont) 12 DOMParser DOMParser estende XMLParser Métodos importantes void parse(InputSource source) void parse(java.lang.String systemId) Executa o parsing em source Executa o parsing sobre o arquivo identificado por systemId Document getDocument() Retorna o documento 13 Interface Node Corresponde a um nó na árvore DOM Node pode ser usado para referenciar: Elementos Atributos Texto Comentários Seções CDATA Entidades Documentos inteiros PI 14 Tipos básicos de nodes Document Element Attribute Text 15 DOM Introdução DOM tree Cada node representa um elemento, atributo, etc. <?xml version = "1.0"?> <message from = ”Ana" to = ”Marta"> <body>Oi Marta!</body> </message> Node criado para elemento message Elemento message tem element child node: elemento body Elemento body tem text child node: “Oi Marta!" Atributos from e to também têm nodes na árvore 16 Implementações de DOM DOM-based parsers Microsoft msxml Sun Microsystem JAXP Parser Descrição JAXP Sun Microsystem Java API para XML Parsing (JAXP) é livremente disponível em java.sun.com/xml. XML4J IBM XML Parser for Java (XML4J) é livremente disponível em www.alphaworks.ibm.com/tech/xml4j. Xerces Apache Xerces Java Parser é livremente disponível em xml.apache.org/xerces. msxml Microsoft XML parser (msxml) version 2.0 é embutido no Internet Explorer 5.5. Version 3.0 está livremente disponível em msdn.microsoft.com/xml. 4DOM 4DOM é um parser para linguagem Python, disponível livremente em fourthought.com/4Suite/4DOM. XML::DOM XML::DOM é um módulo Perl que permite manipular documentos XML usando Perl. Visite www4.ibm.com/software/developer/library/xm l-perl2. 17 DOM: classes e interfaces. Class/Interface Descrição Document interface Representa o top-level node do documento XML, que provê acesso a todos os demais nodes—incluindo o elemento root. Representa um XML document node. Representa uma lista de Node objects. Representa um elemento node. Deriva de Node. Representa um atributo node. Deriva de Node. Representa character data. Deriva de Node. Node interface NodeList interface Element interface Attr interface CharacterData interface Text interface Comment interface Representa um text node. Deriva de CharacterData. Representa um node comentário. Deriva de CharacterData. ProcessingInstruction Representa um processing instruction node. Deriva de Node. interface CDATASection interface Representa um CDATA section. Deriva de Text. 18 Alguns métodos de Document Método Descrição createElement createAttribute createTextNode createComment createProcessingInstruction createCDATASection getDocumentElement appendChild getChildNodes Cria um element node. Crira um attribute node. Cria um text node. Cria um comment node. Cria um processing instruction node. Cria um CDATA section node. Retorna to elemento root Concatena um child node. Retorna os child nodes. 19 Métodos Node Método Descrição appendChild cloneNode getAttributes getChildNodes getNodeName getNodeType Concatena um child node. Duplica o node. Retorna os atributos do node Retorna os nodes filhos do node. Retorna o nome do node Retorna o tipo do node (ex.. elemento, atributo, text, etc.). getNodeValue Retorna o valor do node. getParentNode Retorna o pai do node hasChildNodes Retorna true se o node tem nodes filhos removeChild Remova um node filho do node. replaceChild Troca um node filho com outro node. setNodeValue Coloca o valor do node insertBefore Concatena um node filho na frente de um node filho.. 20 Navegação de um Node 21 Manipulação de um Node 22 Alguns tipos de node Tipo de Node Descrição Node.ELEMENT_NODE Representa um element node. Node.ATTRIBUTE_NODE Representa um attribute node. Node.TEXT_NODE Representa um text node. Node.COMMENT_NODE Representa um comment node. Node.PROCESSING_INSTRUCTION_ Representa um processing instruction NODE node. Node.CDATA_SECTION_NODE Representa um CDATA section node. 23 Métodos de Element Método Descrição getAttribute getTagName removeAttribute setAttribute Retorna um valor de atributo. Retorna um nome de elemento Remove um atributo de um elemento Coloca um valor de atributo 24 Parsing um arquivo XML num documento Processo em 3 passos 1. Criar o DocumentBuilderFactory. Este objeto criará o DocumentBuilder. 2. Criar o DocumentBuilder. O DocumentBuilder fará o atual parsing criar o objeto Document. 3. Fazer o parsing do arquivo para criar o objeto Document. 25 Exemplo de aplicação básica import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import org.w3c.dom.Document; public class OrderProcessor { public static void main (String args[]) { File docFile = new File("orders.xml"); Document doc = null; try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); doc = db.parse(docFile); } catch (Exception e) { System.out.print("Problem parsing the file."); } } 26 Ex de aplicação básica import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import org.w3c.dom.Document; import org.w3c.dom.Element; public class OrderProcessor { ... System.exit(1); } //Passo 1: obtém o elemento raiz (root) Element root = doc.getDocumentElement(); System.out.println("The root element is " + root.getNodeName()); } } 27 Ex de aplicação básica Obtendo um node filho ... import org.w3c.dom.NodeList; ... //PASSO 1: obtém o elemento raiz(root) Element root = doc.getDocumentElement(); System.out.println("The root element is "+root.getNodeName()); //PASSO 2: obtém os filhos (children) NodeList children = root.getChildNodes(); System.out.println("There are "+children.getLength()+" nodes in this document."); } } 28 Usando getFirstChild() e getNextSibling() ... import org.w3c.dom.Node; ... //PASSO 3: processando os filhos (children) for (Node child = root.getFirstChild(); child != null; child = child.getNextSibling()) { System.out.println(child.getNodeName()+" = "+child.getNodeValue()); } } } ... 29 Múltiplos filhos ... public class OrderProcessor { private static void stepThrough (Node start) { System.out.println(start.getNodeName()+" = "+start.getNodeValue()); for (Node child = start.getFirstChild(); child != null;child = child.getNextSibling()) { stepThrough(child); } } public static void main (String args[]) { File docFile = new File("orders.xml"); ... System.out.println("There are "+children.getLength() +" nodes in this document."); //PASSO 4: fazendo recursividade stepThrough(root); } 30 Resultado: 31 Manipulando Atributos ... import org.w3c.dom.NamedNodeMap; ... private static void stepThroughAll (Node start) { System.out.println(start.getNodeName()+" = "+start.getNodeValue()); if (start.getNodeType() == start.ELEMENT_NODE) { NamedNodeMap startAttr = start.getAttributes(); for (int i = 0; i < startAttr.getLength(); i++) { Node attr = startAttr.item(i); System.out.println(" Attribute: "+ attr.getNodeName() +" = "+attr.getNodeValue()); } } for (Node child = start.getFirstChild(); child != null; child = child.getNextSibling()) { stepThroughAll(child); } } 32 Manipulando Atributos 33 Edição de documentos XML Existem métodos para adicionar nodes, remover nodes, mudar valores de nodes Consulte a API! 34 SAX Simple API for XML Outro método para acessar o conteúdo de documentos XML. Desenvolvido por membros da XML-DEV mailing-list (não é da W3C) Usa um modelo baseado em eventos Notificações (eventos) ocorrem à medida em que o documento é analizado (“parsed”) 35 SAX-based Parsers SAX-based parsers Disponíveis em várias LPs: e.g., Java, Python, C++, etc. Produto Descrição Sun JAXP é disponível em java.sun.com/xml. JAXP suporta SAX e DOM. Apache Xerces parser é disponível em Xerces www.apache.org. Xerces suporta SAX e DOM. MSXML 3.0 Microsoft msxml parser disponível em msdn.microsoft.com/xml e suporta SAX e DOM. JAXP 36 Eventos SAX parser Invoca certos métodos quando eventos ocorrem Programadores devem fazer overriding destes métodos para processar os dados 37 Métodos invocados pelo SAX parser Método Descrição setDocumentLocator startDocument Invocado no início do parsing. Invocado quando o parser encontra o início de um documento XML endDocument Invocado quando o parser encontra o fim de um documento XML startElement Invocado quando a tag de inicio de um elemento é encontrada endElement Invocado quando a tag de fim de um elemento é encontrada. characters Invocado quando text characters são encontrados. ignorableWhitespace Invocado quando whitespace que pode ser ignorado é encontrado. processingInstruction Invocado quando um PI é encontrada. 38 Como SAX funciona? Dado o documento XML abaixo: <?xml version="1.0"?> <samples> <server>UNIX</server> <monitor>color</monitor> </samples> SAX gera os seguintes EVENTOS: Start document Start element (samples) Characters (white space) Start element (server) Characters (UNIX) End element (server) Characters (white space) Start element (monitor) Characters (color) End element (monitor) Characters (white space) 39 End element (samples) Como SAX funciona? Processamento em SAX envolve os seguintes passos 1. Criar um event handler 2. Criar o SAX parser 3. Associar o event handler ao parser criado 4. Fazer o parsing do documento, enviando cada evento ao event handler. 40 Exemplo: Uma pesquisa de opinião <?xml version="1.0"?> <surveys> <response username="bob"> <question subject="appearance">A</question> <question subject="communication">B</question> <question subject="ship">A</question> <question subject="inside">D</question> <question subject="implant">B</question> </response> <response username="sue"> <question subject="appearance">C</question> <question subject="communication">A</question> <question subject="ship">A</question> <question subject="inside">D</question> <question subject="implant">A</question> </response> <response username="carol"> <question subject="appearance">A</question> <question subject="communication">C</question> <question subject="ship">A</question> <question subject="inside">D</question> <question subject="implant">C</question> </response> 41 </surveys> Criando um event handler import org.xml.sax.helpers.DefaultHandler; public class SurveyReader extends DefaultHandler { public SurveyReader() { System.out.println("Object Created."); } public void showEvent(String name) { System.out.println("Hello, "+name+"!"); } public static void main (String args[]) { SurveyReader reader = new SurveyReader(); reader.showEvent(”Nick"); } 42 } // Exemplo usando JAXP import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.XMLReader; Criando o SAX parser public class SurveyReader extends DefaultHandler { public SurveyReader() { } public static void main (String args[]) { XMLReader xmlReader = null; try { SAXParserFactory spfactory = SAXParserFactory.newInstance(); SAXParser saxParser = spfactory.newSAXParser(); xmlReader = saxParser.getXMLReader(); } catch (Exception e) { System.err.println(e); System.exit(1); } } } 43 Associando o event handler ao parser ... xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(new SurveyReader()); } catch (Exception e) { ... 44 Parsing os dados ... import org.xml.sax.InputSource; ... xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(new SurveyReader()); InputSource source = new InputSource("surveys.xml"); xmlReader.parse(source); } catch (Exception e) { ... Pronto! Falta apenas definir os eventos ... 45 Criando um ErrorHandler ... import org.xml.sax.SAXParseException; public class SurveyReader extends DefaultHandler { public SurveyReader() { } public void error (SAXParseException e) { System.out.println("Error parsing the file: "+e.getMessage()); } public void warning (SAXParseException e) { System.out.println("Problem parsing the file: "+e.getMessage()); } public void fatalError (SAXParseException e) { System.out.println("Error parsing the file: "+e.getMessage()); System.out.println("Cannot continue."); System.exit(1); } public static void main (String args[]) { ... 46 Associando o ErrorHandler ... xmlReader.setContentHandler(new SurveyReader()); xmlReader.setErrorHandler(new SurveyReader()); InputSource source = new InputSource("surveys.xml"); ... 47 Eventos: startDocument() ... import org.xml.sax.SAXException; public class SurveyReader extends DefaultHandler { ... public void fatalError (SAXParseException e) { System.out.println("Error parsing " + "the file: "+e.getMessage()); System.out.println("Cannot continue."); System.exit(1); } public void startDocument() throws SAXException { System.out.println("Tallying survey results..."); } public static void main (String args[]) { ... 48 Eventos: startElement() ... import org.xml.sax.Attributes; public class SurveyReader extends DefaultHandler { ... public void startDocument() throws SAXException { System.out.println("Tallying survey results..."); } public void startElement( String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { System.out.print("Start element: "); System.out.println(localName); } public static void main (String args[]) { … } 49 startElement(): pegando atributos ... public void startElement( String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { System.out.print("Start element: "); System.out.println(localName); for (int att = 0; att < atts.getLength(); att++) { String attName = atts.getLocalName(att); System.out.println(" " + attName + ": " + atts.getValue(attName)); } } ... 50 Obtendo Dados: characters() … // ch inclui o documento inteiro public void characters(char[] ch, int start, int length) throws SAXException { if (thisElement == "question") { printIndent(4); System.out.print(thisQuestion + ": "); System.out.println(new String(ch, start, length)); } } ... 51 Obtendo Dados: characters() 52 Obtendo Dados: characters() (completo) public void endElement( String namespaceURI, public void printIndent(int indentSize) { String localName, for (int s = 0; s < indentSize; s++) { String qName) System.out.print(" "); throws SAXException { } thisQuestion = ""; } thisElement = ""; String thisQuestion = ""; } String thisElement = ""; public void characters(char[] ch, public void startElement( int start, String namespaceURI, int length) String localName, throws SAXException { String qName, if (thisElement == "question") { Attributes atts) printIndent(4); throws SAXException { System.out.print(thisQuestion + ": "); if (localName == "response") { System.out.println(new String(ch, System.out.println("User: " start, length)); + atts.getValue("username")); } } else if (localName == "question") { } thisQuestion = atts.getValue("subject"); ... } thisElement = localName; 53 } ... SAX versus DOM DOM Modelo baseado em árvore armazena o documento inteiro numa hierarquia de document nodes Dados são acessados rapidamente Provê facilidades para adicionar e remover nodes SAX Invoca métodos quando markup (tag) é encontrada Maior performance do que DOM Menos overhead de memória do que DOM Tipicamente usado para ler documentos (não para modificá-los) 54 JDOM – Java DOM http://www.jdom.org Interface OO específica para Java baseada em DOM Vantagens: As mesmas de DOM Interface OO muito mais rica que DOM Desvantagens Mesmas do DOM Limitado à Java 55 Toolkits XML Java JAXP (java.sun.com/xml/jaxp/faq.html) Dom4j (www.dom4j.org) .NET (parte do .NET framework) XML Spy www.xmlspy.com 56 XSL - eXtensible Stylesheet Language 57