Rozhraní SAX, SAX vs. SAX2 Jaroslav Ciml
Použití SAX - připomenutí Vytvoření instance parseru XMLReader xmlReader = XMLReaderFactory.createXMLReader(); Registrace handleru xmlReader.setContentHandler( contentHandler); Parsování xmlReader.parse(inputSource); Třída InputSouce zapouzdřuje různé způsoby předání XML dokumentu (InputStream, Reader, systemId)
Atributy Zpracování atrubutů zajišťuje ContentHandler jako reakci na událost startElement void startElement(String uri, String localName, String qName, Attributes atts) Rozhraní Attributes reprezentuje množinu všech atributů uvedených v otevíracím tagu elementu 3 možnosti přístupu k jednotlivým atributům pomocí indexu pomocí jména atributu (raw name) pomocí namespace a lokálního jména atributu
Atributy - příklad Atribut bez namespace Atribut s namespace <lastname lang="EN">Smith</lastname> kvalifikované jméno lang (raw, prefixed, qualified name) namespace (uri) prázdný řetězec lokální jméno (local name) lang Atribut s namespace <rootElem xmlns:ns=“http://www.mff.cuni.cz/namespace“> … <lastname ns:lang="EN">Smith</lastname> </rootElem> kvalifikované jméno ns:lang namespace (uri) http://www.mff.cuni.cz/namespace lokální jméno lang
Metody rozhraní Attributes Přístup přes index int getLength() String getQName(int index) String getURI(int index) String getLocalName(int index) String getValue(int index) Přístup přes jméno atributu String getValue(String qName) Přístup přes namespace a lokální jméno String getValue(String uri, String localName)
Atributy - dodatky Pokud nemá parser zapnutou podporu namespaces, je k dispozici pouze kvalifikované jméno Přístup přes kvalifikované jméno nemusí fungovat správně, pokud nemá parser nastavenou vlastnost xmlReader.setFeature( “http://xml.org/sax/features/namespace-prefixes“, true); Rozhraní Attributes existuje až od SAX 2.0, v SAX 1.0 rozhraní AttributeList – bez podpory namespaces (pouze raw names)
Handlery U parseru lze zaregistrovat 4 handlery – třídy implementující následující rozhraní ContentHandler ErrorHandler DTDHandler EntityResolver Všechna rozhraní implementuje třída DefaultHandler (těla všech metod jsou prázdná)
ContentHandler startDocument, endDocument, startElement, endElement characters, ignorableWhitespace Mapování prefixu na namespace void startPrefixMapping(String prefix, String uri) void endPrefixMapping(String prefix) Příklad <rootElem xmlns:ns=“http://www.mff.cuni.cz/namespace“> při vstup do elementu (ještě před událostí startElement) zavolá parser metodu startPrefixMapping( “ns“, “http://www.mff.cuni.cz/namespace“)
ContentHandler Pro deklarace <?target data?> se volá void processingInstruction( String target, String data) metoda se nezavolá pro deklaraci xml <?xml version=“1.0“?> Lokátor Parser ještě před událostí startDocument zavolá metodu void setDocumentLocator(Locator locator) Klientský kód si může instanci typu Locator uložit Během parsování dokumentu (mezi událostmi startDocument a endDocument) se lze dotazovat na pozici int getLineNumber() int getColumnNumber()
ErrorHandler void fatalError( SAXParseException exception) nezotavitelná chyba (typicky: dokument není dobře formovaný) void error( zotavitelná chyba (typicky: dokument není validní) void warning( Po zpracování události error nebo warning pokračuje parsování dokumentu. Klientský kód může parsování dokumentu ukončit vyhozením výjimky SAXException.
DTDHandler, EntityResolver DTDHandler umožňuje reagovat pouze na neparsované entity a notace <!DOCTYPE document [ … <!NOTATION WAV SYSTEM "/usr/local/bin/wave_player"> <!ENTITY music SYSTEM "drop.wav" NDATA WAV> ]> <document> <sound what="music"/> </document> EntityResolver zpracovává externí entity (např. odkaz na externí DTD)
Handlery – SAX 1.0 V SAX 1.0 opět chybí podpora namespaces Rozhraní DocumentHandler (místo ContentHandler) používá pouze raw names chybí metody startPrefixMapping, endPrefixMapping Defaultní implementace handlerů – třída HandlerBase (místo DefaultHandler)
Parsery Vytvoření instance parseru Registrace handleru Parsování XMLReader xmlReader = XMLReaderFactory.createXMLReader(); Registrace handleru xmlReader.setContentHandler(contentHandler); xmlReader.setErrorHandler(errorHandler); xmlReader.setDTDHandler(dtdHandler); xmlReader.setEntityResolver(entityResolver); Parsování xmlReader.parse(inputSource);
Parsery – features, properties void setProperty(String name, Object value) nastavuje vlastnosti parseru formou dvojic jméno-hodnota př.: nastavení validace podle XML Schema xmlReader.setProperty( “http://java.sun.com/xml/jaxp/properties/schemaLanguage“, “http://www.w3.org/2001/XMLSchema“); void setFeature(String name, boolean value) zapíná / vypíná vlastnosti parseru př.: zapnutí validace některých časově náročných podmínek (například omezení unique) “http://apache.org/xml/features/validation/“ + “schema-full-checking“, true);
Parsery – SAX 1.0 Vytvoření instance parseru Parser parser = ParserFactory.makeParser(); Rozhraní Parser nepodporuje namespaces, nepodporuje properties ani features, ke všem setter metodám chybí getter metody Z instance typu Parser lze vytvořit objekt chovající se jako XMLReader a naopak XMLReader xmlReader = new ParserAdapter(parser); Parser parser = new XMLReaderAdapter(xmlReader);
Parsery – alternativní přístup Vytvoření továrny SAXParserFactory factory = SAXParserFactory.newInstance(); Na továrně lze nastavit setFeature(String name, boolean value) void setValidating(boolean validating) void setNamespaceAware(boolean awareness) … Vytvoření parseru SAXParser saxParser = factory.newParser(); Vzniklý parser v sobě obsahuje instanci typu Parser i instanci typu XMLReader (dostupné pomocí metod getParser, getXMLReader)
Parsery – alternativní přístup Na parseru lze nastavit properties void setProperty(String name, Object value) Spousta variant přetížené metody parse, všechny mají parametry XML dokument (InputStream, InputSource, URI, File) Implementace handlerů (DefaultHandler, HandlerBase)
Filtry Filtry umožňují změnit události, které se dostávají k obslužným metodám handlerů (např. lze pro každou událost startElement vygenerovat atribut id) Filtry jsou objekty implementující rozhraní XMLFilter interface XMLFilter extends XMLReader Třída XMLFilterImpl je defaultní implementací XMLFilter. Nový filtr se typicky vytvoří zděděním této třídy.
Přidání filtru „Obyčejné“ použití parseru vytvoření instance parseru nastavení handlerů volání metody parse Použití parseru s filtrem přidání filtru XMLReader filteringXMLReader = new XMLFilterImpl( xmlReader); nastavení handlerů (na objektu filteringXMLReader) volání metody parse (na filteringXMLReader)
Jak funguje XMLFilterImpl XMLFilterImpl si zapamatuje skutečný parser předaný jako parametr konstruktoru XMLFilterImpl si zapamatuje všechny nastavené handlery jako své atributy (dostupné přes metody getContentHandler,...) Při volání metody parse nejprve XMLFilterImpl zaregistruje u parseru sebe (implementuje všechny handler rozhraní). Poté deleguje na parser volání parse. Metody startElement,... definované třídou XMLFilterImpl pouze delegují volání na uložené handlery. Předpokládá se, že potomci předefinují toto chování.
Zdroje http://xml.apache.org/xerces-j http://www.saxproject.org http://www.cafeconleche.org/books/xmljava