XML in own applications Patryk Czarnik Institute of Informatics University of Warsaw

XML and Modern Techniques of Content Management – 2010/11

Introduction XML in own applications

Models Generyczne drzewo dokumentu (DOM) XML binding (JAXB) Model zdarzeniowy (SAX) Model strumieniowy (StAX) Porównanie

Obsługa standardów około-XML-owych Walidacja Transformacje

XML in own applications — what for? I

To access data in XML format

I

To use XML as data carrier (storage and transmission)

I

To support XML applications (Web, content management, . . . )

I

To make use of XML-related standards (XML Schema, XInclude, XSLT, XQuery, . . . )

I

To make use of XML-based software technology (Web Services etc.)

XML in own applications — how? Bad way I

Treat XML as plain text files and write low-level XML support from scratch

Better approach I

Use existing libraries and tools

Even better I

Use standardised interfaces independent from particular suppliers

XML in Java Java — motivation for us I

One of the most popular programming languages

I

Very good XML support

Standards Both included in Java Standard Edition from 6.0 I Java API for XML Processing (JAXP) I

I I

I

many interfaces and few classes, "factories" and pluggability layer support for XML parsing and serialisation (DOM, SAX, StAX) support for XInclude, XML Schema, XPath, XSLT

Java API for XML Binding (JAXB) I

binding between Java objects and XML documents

Classification of XML access models I

Document read into memory I

I

I

generic interface example: DOM interface depending on document type (schema) example: JAXB

Document processed node by node I

I

event model (push parsing) example: SAX streaming model (pull parsing) example: StAX

Document object model I I

Whole document in memory, as tree of objects W3C Recommendations I I

DOM Level 1 — 1998 DOM Level 3 — 2004

I

Many (specification) modules

I

Dom Core — the most important DOM module for XML

DOM — important interfaces NodeList

Node

Element Document

Processing Instruction

DocumentFragment

DocumentType

Attr

NamedNodeMap

Entity

CharacterData

Comment

Entity Reference

Text

CDATASection

Interfejs Node – wybrane metody Content access I

getAttributes()

I

getChildNodes()

I

getFirstChild()

I

getLastChild()

I

getNextSibling()

I

getPreviousSibling()

I

getNodeName()

I

getNodeValue()

I

getNodeType()

I

getOwnerDocument()

I

getParentNode()

I

hasChildNodes()

Content modification I

appendChild(Node)

I

insertBefore(Node, Node)

I

removeChild(Node)

I

replaceChild(Node, Node)

I

setNodeValue(String)

I

setNodeName(String)

Copying I

cloneNode(boolean)

Example — introduction Example document 52 25 521 912

Problem Count sum of element l values from important groups.

DOM – example (1) Program int r e s u l t = 0; DocumentBuilderFactory f a c t o r y = DocumentBuilderFactory . newInstance ( ) ; f a c t o r y . s e t V a l i d a t i n g ( true ) ; DocumentBuilder b u i l d e r = f a c t o r y . newDocumentBuilder ( ) ; Document doc = b u i l d e r . p a r s e ( a r g s [ 0 ] ) ; Node c u r = doc . g e t F i r s t C h i l d ( ) ; w h i l e ( c u r . getNodeType ( ) ! = Node . ELEMENT_NODE) { cur = cur . getNextSibling ( ) ; } cur = cur . g e t F i r s t C h i l d ( ) ; while ( cur != n u l l ) { i f ( c u r . getNodeType ( ) == Node . ELEMENT_NODE) { String attVal = cur . g e t A t t r i b u t e s ( ) . getNamedItem ( " i m p o r t a n t " ) . g e t N o d e V a l u e ( ) ; i f ( " yes " . equals ( a t t V a l ) { r e s u l t += p r o c e s s G r o u p ( c u r ) ; } } cur = cur . getNextSibling ( ) ; }

DOM – example (2) Method processGroup p r i v a t e s t a t i c i n t p r o c e s s G r o u p ( Node g r o u p ) { int r e s u l t = 0; Node c u r = g r o u p . g e t F i r s t C h i l d ( ) ; while ( cur != n u l l ) { i f ( c u r . getNodeType ( ) == Node . ELEMENT_NODE && c u r . getNodeName ( ) . e q u a l s ( " l " ) ) { S t r i n g B u f f e r b u f = new S t r i n g B u f f e r ( ) ; Node c h i l d = c u r . g e t F i r s t C h i l d ( ) ; while ( c h i l d != n u l l ) { i f ( c h i l d . getNodeType ( ) == Node . TEXT_NODE) buf . append ( c h i l d . getNodeValue ( ) ) ; child = child . getNextSibling ( ) ; } r e s u l t += I n t e g e r . p a r s e I n t ( b u f . t o S t r i n g ( ) ) ; ; } cur = cur . getNextSibling ( ) ; } return r e s u l t ; }

XML binding — idea I

XML documents and objects (e.g. Java): I I

I

schema (type) corresponds to class, document/node corresponds to object.

Implementations: I

JAXB (Sun), Castor (Exolab), Dynamic XML (Object Space).

Java API for XML Binding (JAXB) I

Inspired by Sun, supported by java.net

I

Current version: 2.0

I

Motivated by Web Services Components

I

I I I

generic API fragment two-way translation specification customisation and annotations

JAXB — usage scenarios Schema to Java

Java to Schema

1. Schema preparation 2. Schema to Java compilation (XJC) I

I

1. Model classes preparation 2. Adding annotations classes 3. Making use of generic JAXB API to perform marchalling, unmarchalling etc.

result: annotated classes basing on schema types transalation customisable

3. Developing application making use of I I

4. (Optional) Generating schema basing on classes

generic part of JAXB API generated classes

JAXB — example(1) Schema and generated classes

Schema

Generated classes I



Numbers I

List getGroup()

Corresponding classes I

JAXBElement I I I I

QName getName() BigInteger getValue() void setValue(BigInteger) ...

JAXB — example (2) Schema and generated classes

Schema

Generated classes I



Group I

I I

List getLOrS() String getImportant() void setImportant(String)

JAXB — example(3) Program int r e s u l t = 0; JAXBContext j c = JAXBContext . n e w I n s t a n c e ( " j a x b _ g e n e r a t e d " ) ; Unmarshaller u = jc . createUnmarshaller ( ) ; L i c z b y doc = ( L i c z b y ) u . u n m a r s h a l ( new F i l e I n p u t S t r e a m ( a r g s [ 0 ] ) ) ; L i s t g r o u p s = doc . g e t G r o u p ( ) ; f o r ( Group g r o u p : g r o u p s ) { i f ( " tak " . equals ( grupa . g e tI m p o r ta nt ( ) ) ) { r e s u l t += p r o c e s s G r o u p ( g r o u p ) ; } }

JAXB — example (4) Method processGroup p r i v a t e s t a t i c i n t p r o c e s s G r o u p ( Group g r o u p ) { int r e s u l t = 0; L i s t > e l e m s = g r o u p . getLOrS ( ) ; f o r ( JAXBElement < B i g I n t e g e r > elem : e l e m s ) { i f ( " l " . e q u a l s ( elem . getName ( ) . g e t L o c a l P a r t ( ) ) ) { B i g I n t e g e r v a l = elem . g e t V a l u e ( ) ; r e s u l t += v a l . i n t V a l u e ( ) ; } } return r e s u l t ; }

Model zdarzeniowy – idea I

Umoz˙ liwienie programi´scie podania dowolnego kodu, wykonywanego podczas czytania dokumentu: I

I

I

I

Po stronie parsera: I I I

I

dokument XML jako ciag ˛ zdarze´n (np. “poczatek ˛ elementu”, “w˛ezeł tekstowy”, “koniec dokumentu”, . . . ), procedury podane przez programist˛e wykonywane w odpowiedzi na zdarzenia róz˙ nego typu, tre´sc´ dokumentu przekazywana w parametrach. analiza leksykalna, kontrola poprawno´sci składniowej, opcjonalnie walidacja.

Moz˙ liwe realizacje w zalez˙ no´sci od j˛ezyka programowania: I

I

obiekt (“handler”) zawierajacy ˛ zestaw metod wykonywanych przy okazji róz˙ nych zdarze´n (j˛ezyki obiektowe), funkcje (j˛ezyki funkcyjne), wska´zniki do funkcji (C).

Simple API for XML (SAX) I

Standard odpowiedni dla j˛ezyków obiektowych. I

wzorcowe interfejsy zapisane w Javie

SAX – jak uz˙ ywa´c ? (1) Kroki implementacji 1. Klasa implementujaca ˛ interfejs ContentHandler. 2. Opcjonalnie klasa implementujaca ˛ interfejsy ErrorHandler, DTDHandler, EntityResolver. I jedna klasa moz ˙ e implementowa´c wszystkie te interfejsy, I moz ˙ emy w tym celu rozszerzy´c klas˛e DefaultHandler, która zawiera puste implementacje wszystkich wymaganych metod.

SAX – jak uz˙ ywa´c ? (2) Schemat typowej aplikacji 1. Pobranie obiektu XMLReader z fabryki. 2. Stworzenie obiektu "handlera". 3. Rejestracja handlera w parserze (XMLReader) metodami setContentHandler, setErrorHandler itp. 4. Wywołanie metody parse. 5. Wykonanie (przez parser) naszego kodu z handlera. 6. Wykorzystanie danych zebranych przez handler.

SAX – przykład (1) Implementacja ContentHandler-a p r i v a t e s t a t i c c l a s s N u m be r s H a n d l e r e x t e n d s D e f a u l t H a n d l e r { enum S t a t e {OUT, GROUP, L } ; private int r e s u l t = 0; p r i v a t e S t a t e s t a t e = S t a t e . OUT; private S t r i n g B u f f e r buf ; public i n t g e t R e s u l t ( ) { return r e s u l t ; } p u b l i c v o i d s t a r t E l e m e n t ( S t r i n g u r i , S t r i n g localName , S t r i n g qName , A t t r i b u t e s a t t r i b u t e s ) throws SAXException { i f ( " g r o u p " . e q u a l s ( qName ) ) { String a t t r V a l = a t t r i b u t e s . getValue ( " important " ) ; i f ( " yes " . equals ( a t t r V a l ) ) s t a t e = S t a t e . GROUP; } e l s e i f ( " l " . e q u a l s ( qName ) ) { i f ( s t a n == S t a t e . GROUP) { s t a t e = Stan . L; b u f = new S t r i n g B u f f e r ( ) ; } } }

SAX – przykład (2) Ciag ˛ dalszy LiczbyHandler p u b l i c v o i d c h a r a c t e r s ( char [ ] ch , i n t s t a r t , i n t l e n g t h ) throws SAXException { i f ( s t a n == S t a n . L ) b u f . a p p e n d ( ch , s t a r t , l e n g t h ) ; } p u b l i c v o i d e n d E l e m e n t ( S t r i n g u r i , S t r i n g localName , S t r i n g qName ) throws SAXException { i f ( " g r o u p " . e q u a l s ( qName ) ) { i f ( s t a t e == S t a t e . GRUPA) { s t a t e = S t a t e .ZEWN; } } e l s e i f ( " l " . e q u a l s ( qName ) ) { i f ( s t a t e == S t a t e . LICZBA ) { s t a t e = S t a t e . GRUPA; r e s u l t += I n t e g e r . p a r s e I n t ( b u f . t o S t r i n g ( ) ) ; } } } } / ∗ NumbersHandler ∗ /

SAX – przykład (3) Program SAXParserFactory f a c t o r y = SAXParserFactory . newInstance ( ) ; f a c t o r y . s e t V a l i d a t i n g ( true ) ; SAXParser p a r s e r = f a c t o r y . newSAXParser ( ) ; L i c z b y H a n d l e r h a n d l e r = new N u m b e r s H a n d l e r ( ) ; parser . parse ( args [0] , handler ) ; System . o u t . p r i n t l n ( "Sum : " + h a n d l e r . g e t R e s u l t ( ) ) ;

Filtry SAX I

Implementuja˛ interfejs XMLFilter, a takz˙ e (po´srednio) XMLReader I

I

I

Domy´slna implementacja: XMLFilterImpl: I I

I

zachowuja˛ si˛e jak parser, ale ich z´ ródłem danych jest inny XMLReader (parser lub filtr). moz˙ na je łaczy´ ˛ c w ła´ncuchy. przepuszcza wszystkie zdarzenia, implementuje interfejsy ContentHandler, ErrorHandler itp.

Filtry pozwalaja˛ na: I I

I

filtrowanie zdarze´n, zmian˛e danych (a nawet struktury) dokumentu przed wysłaniem zdarzenia dalej, przetwarzanie dokumentu przez wiele modułów podczas jednego parsowania.

Filtr SAX – przykład public c l a s s L i c z b y F i l t r extends XMLFilterImpl { p r i v a t e boolean czyPrzepuszczac = true ; p u b l i c v o i d c h a r a c t e r s ( char [ ] aCh , i n t a S t a r t , i n t a L e n g t h ) throws SAXException { i f ( czyPrzepuszczac ) s u p e r . c h a r a c t e r s ( aCh , a S t a r t , a L e n g t h ) ; } p u b l i c v o i d e n d E l e m e n t ( S t r i n g a U r i , S t r i n g aLocalName , S t r i n g aName ) throws SAXException { i f ( czyPrzepuszczac ) s u p e r . e n d E l e m e n t ( a U r i , aLocalName , aName ) ; i f ( " g r u p a " . e q u a l s ( aName ) ) czyPrzepuszczac = true ; } p u b l i c v o i d s t a r t E l e m e n t ( S t r i n g a U r i , S t r i n g aLocalName , S t r i n g aName , A t t r i b u t e s a t t s ) throws SAXException { i f ( " g r u p a " . e q u a l s ( aName ) && " n i e " . e q u a l s ( a t t s . g e t V a l u e ( " wazne " ) ) ) czyPrzepuszczac = false ; i f ( czyPrzepuszczac ) s u p e r . s t a r t E l e m e n t ( a U r i , aLocalName , aName , a t t s ) ; } }

Model strumieniowy (pull parsing) I

Alternatywa dla modelu zdarzeniowego: I I I

I

Zachowane cechy modelu SAX: I I

I

aplikacja "wyciaga" ˛ kolejne zdarzenia z parsera, przetwarzanie kontrolowane przez aplikacj˛e, a nie parser, parser działa podobnie jak iterator, kursor lub strumie´n danych, duz˙ a wydajno´sc´ , moz˙ liwo´sc´ przetwarzania dowolnie duz˙ ych dokumentów.

Standaryzacja: I I

Common XmlPull API, Java Community Process, JSR 173: Streaming API for XML.

Pull parsing – korzy´sci I

Jeszcze wi˛eksza wydajno´sc´ niz˙ w (i tak juz˙ wydajnym) modelu SAX, dzi˛eki: I

I I

I I

moz˙ liwo´sci przerwania przetwarzania przed ko´ncem pliku, gdy potrzebujemy z niego tylko cz˛es´c´ danych, moz˙ liwo´sci zmniejszenia liczby kopiowa´n obiektów typu String, szybszemu filtrowaniu zdarze´n.

Moz˙ liwo´sc´ prostej obróbki wielu dokumentów jednocze´snie. Bardziej „proceduralny” styl programowania, co daje: I I I

mniej stanów do pami˛etania, moz˙ liwo´sc´ uz˙ ycia rekursji, zwi˛ekszone powtórne uz˙ ycie kodu.

´ Zródło: M. Plechawski, "Nie pozwól si˛e popycha´c", Software 2.0, 6/2003

StAX (dawniej Sun Java Streaming XML Parser) I I

Standard parserów strumieniowych dla Javy (Sun). Realizacja załoz˙ e´n dokumentu JSR 173, zawarty w JSE 6.0.

Najwaz˙ niejsze interfejsy I

XMLStreamReader: I I

I

XMLEventReader: I

I

hasNext(), int next(), int getEventType(), getName(), getValue(), getAttributeValue(), . . . XMLEvent next(), XMLEvent peek(),

XMLEvent: I

I

getEventType(), isStartElement(), isCharacters(), . . . podinterfejsy StartElement, Characters, . . .

I

XMLStreamWriter, XMLEventWriter,

I

XMLStreamFilter, XMLEventFilter.

StAX – przykład (1) Program p r i v a t e s t a t i c XMLStreamReader f R e a d e r ; public void run ( S t r i n g [ ] a r g s ) { int r e s u l t = 0; X ML I n p u t F a c t o r y f a c t o r y = X M L I n p u t F a c t o r y . n e w I n s t a n c e ( ) ; f R e a d e r = f a c t o r y . c r e a t e X M L S t r e a m R e a d e r ( new F i l e I n p u t S t r e a m ( a r g s [ 0 ] ) ) ; while ( fReader . hasNext ( ) ) { i n t eventType = fReader . next ( ) ; i f ( e v e n t T y p e == XMLStreamConstants . START_ELEMENT) { i f ( " group " . e q u a l s ( fReader . getLocalName ( ) ) ) { S t r i n g a t t r V a l = fReader . g e t A t t r i b u t e V a l u e ( null , " important " ) ; i f ( " yes " . equals ( a t t r V a l ) ) { r e s u l t += t h i s . p r o c e s s G r o u p ( ) ; } } } } fReader . close ( ) ; System . o u t . p r i n t l n ( " R e s u l t : " + r e s u l t ) ; }

StAX – przykład (2) Metoda processGroup p r i v a t e i n t p r o c e s s G r o u p ( ) throws XMLStreamException { int r e s u l t = 0; while ( fReader . hasNext ( ) ) { i n t eventType = fReader . next ( ) ; switch ( eventType ) { c a s e XMLStreamConstants . START_ELEMENT : i f ( " l " . e q u a l s ( fReader . getLocalName ( ) ) ) { String val = fReader . getElementText ( ) ; r e s u l t += I n t e g e r . p a r s e I n t ( v a l ) ; } break ; c a s e XMLStreamConstants . END_ELEMENT : i f ( " group " . e q u a l s ( fReader . getLocalName ( ) ) ) { return r e s u l t ; } break ; } } return r e s u l t ; }

Which model to choose? (1) I

Document tree in memory: I I I

I

Generyczny model dokumentu (np. DOM): I I

I

small documents (must fit in memory) concurrent access to many nodes creating and editing document "in place" nieznana/niedoprecyzowana struktura dokumentów, dopuszczalna niz˙ sza efektywno´sc´ .

Wiazanie ˛ XML (np. JAXB): I I

ustalona i znana struktura dokumentu (Schema/DTD), zapisywanie do XML obiektów z aplikacji (np. wymiana danych).

Which model to choose? (2) I

Processing node by node I I I

I

Model zdarzeniowy (np. SAX): I I I

I

potentially large documents relatively simple, local operations efficiency is the key factor filtrowanie zdarze´n, asynchroniczne napływanie zdarze´n, kilka rodzajów przetwarzania podczas jednego czytania dokumentu.

Przetwarzanie strumieniowe (np. StAX): I I

I

koniec przetwarzania po wystapieniu ˛ poszukiwanych danych, przetwarzanie zdarzenia zalez˙ y od kontekstu (np. od tego, czy jeste´smy wewnatrz ˛ pewnego elementu), przetwarzanie równolegle wi˛ecej niz˙ jednego pliku.

Walidacja wzgl˛edem DTD podczas parsowania

SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(true); XMLReader reader = factory.newSAXParser().getXMLReader(); reader.setContentHandler(mojConentHandler); reader.setErrorHandler(mojErrorHandler); reader.parse(args[0]);

Walidacja wzgl˛edem XML Schema

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schemat = schemaFactory.newSchema(new StreamSource(args[1])); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(false); factory.setSchema(schemat); factory.setNamespaceAware(true); XMLReader reader = factory.newSAXParser().getXMLReader(); reader.setContentHandler(mojConentHandler); reader.setErrorHandler(mojErrorHandler); reader.parse(args[0]);

Walidacja i zapis drzewa DOM

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schemat = schemaFactory.newSchema(new StreamSource(args[1])); Validator validator = schemat.newValidator(); validator.validate(new DOMSource(doc)); DOMImplementationLS lsImpl = (DOMImplementationLS)domImpl.getFeature("LS", "3.0"); LSSerializer ser = lsImpl.createLSSerializer(); LSOutput out = lsImpl.createLSOutput(); out.setByteStream(new FileOutputStream(args[0])); ser.write(doc, out);

Transformacje XSLT Przekształcenie dokumentów zapisanych w plikach TransformerFactory t r a n s _ f a c t = TransformerFactory . newInstance ( ) ; t r a n s f o r m e r = t r a n s _ f a c t . n e w T r a n s f o r m e r ( new S t r e a m S o u r c e ( a r g s [ 2 ] ) ) ; S o u r c e s r c = new S t r e a m S o u r c e ( a r g s [ 0 ] ) ; R e s u l t r e s = new S t r e a m R e s u l t ( a r g s [ 1 ] ) ; transformer . transform ( src , res ) ;

Transformacje Zastosowanie do zapisu zdarze´n SAX po przefiltrowaniu SAXParserFactory p a r s e r _ f a c t = SAXParserFactory . newInstance ( ) ; XMLReader r e a d e r = p a r s e r _ f a c t . newSAXParser ( ) . getXMLReader ( ) ; TransformerFactory t r a n s _ f a c t = TransformerFactory . newInstance ( ) ; Transformer t r a n s f o r m e r = t r a n s _ f a c t . newTransformer ( ) ; X M L F i l t e r f i l t r = new F i l t r G r u p y W a z n e ( ) ; f i l t r . setParent ( reader ); I n p u t S o u r c e doc = new I n p u t S o u r c e ( a r g s [ 0 ] ) ; S o u r c e s r c = new SAXSource ( f i l t r , doc ) ; R e s u l t r e s = new S t r e a m R e s u l t ( a r g s [ 1 ] ) ; transformer . transform ( src , res ) ;