Post on 09-Jan-2016
description
XML et JAVA
SAX, DOM, xmlPull…
Plan
JAXP SAX DOM
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
SAX - Simple API for XML
spécifie des librairies qui permettent avant tout de lire un document XML, d'effectuer des traitements sur le contenu de ce
dernier.
SAX est un analyseur basé sur les événements. Le principe de SAX est de
parcourir le document XML, SAX génère des événements en fonction des éléments qui
le constitue.
Interprétation via SAX
SAX
L’analyseur encapsule un objet SAXReader (XMLReader). Invocation de la méthode parse() Invocation des méthodes callback implémentées par l’application. Méthodes de callback définies par les interfaces
ContentHandler : notifications reliées au contenu logique du document ErrorHandler : notifications reliées aux erreurs DTDHandler : notifications reliées à la validation EntityResolver : pour résoudre les valeurs liées à des entités externes (DB…)
Packages principaux liés à XML
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
Package principaux reliés à SAX
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
public abstract interface ContentHandler
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
La classe Echo03
import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser;
public class Echo03 extends DefaultHandler {
static private Writer out; private String indentString = " "; // Amount to indent private int indentLevel = 0;
Version SAX 1.0public static void main(String argv[]) { if (argv.length != 1) {
System.err.println("Usage: cmd filename"); System.exit(1); }
// Use an instance of ourselves as the SAX event handler DefaultHandler handler = new Echo01();
// Use the default (non-validating) parser SAXParserFactory factory = SAXParserFactory.newInstance();
try { // Set up output stream out = new OutputStreamWriter(System.out, "UTF8"); // Parse the input SAXParser saxParser = factory.newSAXParser(); saxParser.parse( new File(argv[0]), handler);
} catch (Throwable t) {
t.printStackTrace(); } System.exit(0); }
Version SAX2.0
public static void main(String argv[]) { if (argv.length != 1) {
System.err.println("Usage: cmd filename"); System.exit(1); }
// Use an instance of ourselves as the SAX event handler DefaultHandler handler = new Echo01();
try { // Set up output stream out = new OutputStreamWriter(System.out, "UTF8");
// Use the default (non-validating) parser XMLReader saxParser = XMLReaderFactory.createXMLReader();saxParser.setContentHandler(handler); saxParser.setErrorHandler(handler); // Parse the input saxParser.parse( new File(argv[0]));
} catch (Throwable t) {
t.printStackTrace(); } System.exit(0); }
Evénements de début et de fin de documents //=========================================================== // SAX DocumentHandler methods //===========================================================
public void startDocument() throws SAXException { nl(); nl(); emit("START DOCUMENT"); nl(); emit("<?xml version='1.0' encoding='UTF-8'?>"); }
public void endDocument() throws SAXException { nl(); emit("END DOCUMENT"); try { nl(); out.flush(); } catch (IOException e) { throw new SAXException("I/O error", e); } }
Début d’un élément public void startElement(String namespaceURI, String lName, // local name String qName, // qualified name Attributes attrs) throws SAXException { indentLevel++; nl(); emit("ELEMENT: "); String eName = lName; // element name if ("".equals(eName)) eName = qName; // namespaceAware = false emit("<"+eName); if (attrs != null) { for (int i = 0; i < attrs.getLength(); i++) { String aName = attrs.getLocalName(i); // Attr name if ("".equals(aName)) aName = attrs.getQName(i); nl(); emit(" ATTR: "); emit(aName); emit("\t\""); emit(attrs.getValue(i)); emit("\""); } } if (attrs.getLength() > 0) nl(); emit(">"); }
Fin d’un élément
public void endElement( String namespaceURI, String sName, // simple name String qName // qualified name ) throws SAXException { nl(); emit("END_ELM: "); emit("</"+sName+">"); indentLevel--; }
Echo des caractères
public void characters(char buf[], int offset, int len)
throws SAXException
{
nl(); emit("CHARS: ");
String s = new String(buf, offset, len);
if (!s.trim().equals("")) emit(s);
}
Tracer les appels callback
Les erreurs d’I/O sont encapsulées dans une exception SAXException avec un message qui identifie l’erreur Cette exception est renvoyée à l’analyseur SAX
static private Writer out;
private void emit(String s)throws SAXException{ try { out.write(s); out.flush(); } catch (IOException e) { throw new SAXException("I/O error", e); }}
Mise en page
// Start a new line // and indent the next line appropriately
private void nl() throws SAXException { String lineEnd = System.getProperty("line.separator"); try { out.write(lineEnd); } catch (IOException e) { throw new SAXException("I/O error", e); } }
Exemple de fichier en entrée<?xml version='1.0' encoding='utf-8'?>
<!-- A SAMPLE set of slides -->
<slideshow title="Sample Slide Show" date="Date of publication" author="Yours Truly" >
<!-- TITLE SLIDE --> <slide type="all"> <title>Wake up to WonderWidgets!</title> </slide>
<!-- OVERVIEW --> <slide type="all"> <title>Overview</title> <item>Why <em>WonderWidgets</em> are great</item> <item/> <item>Who <em>buys</em> WonderWidgets</item> </slide>
</slideshow>
Exemple de sortie
Gestion des erreurs
public static void main(String argv[]) { if (argv.length != 1) { System.err.println("Usage: cmd filename"); System.exit(1); } // Use an instance of ourselves as the SAX event handler DefaultHandler handler = new Echo07(); // Use the default (non-validating) parser SAXParserFactory factory = SAXParserFactory.newInstance(); try { // Set up output stream out = new OutputStreamWriter(System.out, "UTF8");
// Parse the input SAXParser saxParser = factory.newSAXParser(); saxParser.parse( new File(argv[0]), handler);
} catch (SAXParseException spe) { ...
} catch (SAXException sxe) { ...
} catch (ParserConfigurationException pce) { ...
} catch (IOException ioe) { ... } System.exit(0); }
Gestion des erreurspublic static void main(String argv[]) { try { } catch (SAXParseException spe) { // Error generated by the parser System.out.println("\n** Parsing error » + ", line " + spe.getLineNumber() + ", uri " + spe.getSystemId()); System.out.println(" " + spe.getMessage() );
// Use the contained exception, if any Exception x = spe; if (spe.getException() != null) x = spe.getException(); x.printStackTrace();
} catch (SAXException sxe) { // Error generated by this application (or a parser-initialization error) Exception x = sxe; if (sxe.getException() != null) x = sxe.getException(); x.printStackTrace();
} catch (ParserConfigurationException pce) { // Parser with specified options can't be built pce.printStackTrace();
} catch (IOException ioe) { // I/O error ioe.printStackTrace(); } System.exit(0); }
Gestion des erreurs
//=========================================================== // SAX ErrorHandler methods //===========================================================
// treat validation errors as fatal public void error(SAXParseException e) throws SAXParseException { throw e; }
// dump warnings too public void warning(SAXParseException err) throws SAXParseException { System.out.println("** Warning" + ", line " + err.getLineNumber() + ", uri " + err.getSystemId()); System.out.println(" " + err.getMessage()); }
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
SAX : Avantages et inconvénients Avantages
SAX est capable de traiter des fichiers XML de très grande taille, n'opère pas de représentation en mémoire de la structure XML, applique des traitements au fil de la lecture de la structure.
SAX est bien adapté à des fonctionnalités de sélection d'informations précises dans un document XML. extraire certaines parties de document effectuer des totaux sur tous les enregistrements.
L'intégration de l'API SAX dans un programme Java est vraiment très simple.
Inconvénients SAX ne permet pas de modifier un document XML
Puisque le fichier XML est traité au fur et à mesure de la lecture, on ne peut pas effectuer d'accès direct à un élément particulier.
DOM : Document Object Model Crée un arbre où chaque noeud contient une composantes
d’une structure XML
Les noeuds les plus courants sont Noeud Élément Noeud Texte
Fonctions Création et ajout d’un noeud Suppression d’un noeud Modification d’un noeud Parcours de la hiérarchie
Packages utiles org.w3c.dom javax.xml.parsers Javax.xml.transform
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
Déclarations
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException;
import java.io.File;import java.io.IOException;
import org.w3c.dom.Document;import org.w3c.dom.DOMException;
public class DomEcho01{
// Global value so it can be ref'd by the tree-adapter static Document document;
public static void main(String argv[]) { if (argv.length != 1) {
System.err.println("Usage: java DomEcho filename"); System.exit(1); }
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance(); factory.setValidating(true); factory.setNamespaceAware(true); try {
DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse( new File(argv[0]) );
} catch (SAXException sxe) { // Error generated during parsing)
Exception x = sxe; if (sxe.getException() != null) x = sxe.getException(); x.printStackTrace();
} catch (ParserConfigurationException pce) {
// Parser with specified options can't be built pce.printStackTrace();
} catch (IOException ioe) { // I/O error
ioe.printStackTrace(); }
} // main
Gestion des erreurs
builder.setErrorHandler( new org.xml.sax.ErrorHandler() { // ignore fatal errors (an exception is guaranteed) public void fatalError(SAXParseException exception) throws SAXException { }
// treat validation errors as fatal public void error(SAXParseException e) throws SAXParseException { throw e; }
// dump warnings too public void warning(SAXParseException err) throws SAXParseException { System.out.println("** Warning" + ", line " + err.getLineNumber() + ", uri " + err.getSystemId()); System.out.println(" " + err.getMessage()); } });
DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = fact.newDocumentBuilder();
Document doc = builder.parse(str);
// Get root
Node node = doc.getDocumentElement();
String root = node.getNodeName();
System.out.println("Root Node: " + root);
// Get a list of all elements in the document
NodeList list = doc.getElementsByTagName("*");
System.out.println("XML Elements: ");
for (int i=0; i<list.getLength(); i++) {
// Get element
Element element = (Element)list.item(i);
System.out.println(element.getNodeName());
}
Création d’un document XMLclass CreateDomXml { public static void main(String[] args) { try{ //Create instance of DocumentBuilderFactory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //Get the DocumentBuilder DocumentBuilder docBuilder = factory.newDocumentBuilder();
//Create blank DOM Document Document doc = docBuilder.newDocument();
//create the root element and add it to the xml tree Element root = doc.createElement("root"); doc.appendChild(root); //create a comment and add it in the root element Comment comment = doc.createComment("This is comment"); root.appendChild(comment);
//create child element and add the atribute to the child Element childElement = doc.createElement("Child"); childElement.setAttribute("attribute1","The value of Attribute 1"); root.appendChild(childElement);
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
Afficher le document XML sur la console
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
Source src = new DOMSource(doc);
Result dest = new StreamResult(System.out);
aTransformer.transform(src, dest);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
XML et les applications mobiles
XML Temps de traitement bande passante requise
CLDC Un analyseur XML avec une petite empreinte
kXML• Supporte SAX et kDOM
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
SAX vs XmlPull
SAX « Push-based »
Quand l’analyseur est démarré, les événéements sont « poussés » en continu
Les programmeurs n’ont pas de contrôle sur le flot du processus d’analyse
Par exemple, on ne peut pas arrêter l’analyse une fois que l’on a trouvé l’élément qui nous intéresse
XmlPull Donne plus de contrôle sur l’analyse
XmlPullParser next() : START_TAG, TEXT, END_TAG, END_DOCUMENT
• nextToken() : next() + COMMENT, CDSECT, DOCDECL, ENTITY_REF, PROCESSING_INSTRUCTION, IGNORABLE_WHITESPACE
Services Web de Amazon
Service web SOAP standard SOAP RPC
Service XML « littéral » La requête est encodée en paramètres
dans un URL
www.amazon.com/webservicesQuickTime™ et un
décompresseur TIFF (LZW)sont requis pour visionner cette image.
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
Identification et sécurité
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
QuickTime™ et undécompresseur TIFF (LZW)
sont requis pour visionner cette image.
http://xml.amazon.com/onca/xml? v1.0&t=webservices-20&dev-t=1Z644CSSBHC&KeywordSearch=mobile%20Java&mode=books&type=lite&page=1&f=xml
<?xml version="1.0" ?><?xml-stylesheet type="text/xsl" href="amazon.xsl"?><ProductInfo>
<Details url="http://www.amazon.com/exec/obidos/...">
<Asin>0380977427</Asin><ProductName>Quicksilver (The Baroque Cycle, Vol. 1)</ProductName><Catalog>Book</Catalog>
<Authors><Author>Neal Stephenson</Author>
</Authors><ReleaseDate>23 September, 2003</ReleaseDate><Manufacturer>William Morrow</Manufacturer>
<ImageUrlSmall>http://images.amazon…jpg</ImageUrlSmall>
<ImageUrlMedium>http://images.amazon.com/images/…jpg</ImageUrlMedium>
<ImageUrlLarge>http://images.amazon....jpg</ImageUrlLarge>
<Availability>Usually ships within 24 hours</Availability><ListPrice>$27.95</ListPrice><OurPrice>$19.01</OurPrice><UsedPrice>$16.92</UsedPrice>
</Details></ProductInfo>
public class AmazonLite extends MIDlet implements CommandListener {
Display display; Command pullCommand; Command kdomCommand; Command exitCommand; Command doneCommand; TextField textField;
static String token;
public AmazonLite () { display = Display.getDisplay(this); pullCommand = new Command("PULL", Command.SCREEN, 1); kdomCommand = new Command("kDOM", Command.SCREEN, 1); exitCommand = new Command("EXIT", Command.EXIT, 1); doneCommand = new Command("DONE", Command.CANCEL, 1);
// Get value from the JAD file token = getAppProperty("AmazonToken"); }
public void startApp() { Form form = new Form("Amazon Search"); textField = new TextField ("Keywords:", "", 80, TextField.ANY); form.append( textField ); form.addCommand(exitCommand); form.addCommand(pullCommand); form.addCommand(kdomCommand); form.setCommandListener( (CommandListener) this); display.setCurrent(form); } public void pauseApp() { } public void destroyApp(boolean unconditional) { }
public void commandAction(Command command, Displayable screen) { if (command == exitCommand) { destroyApp(false); notifyDestroyed(); } else if ( command == doneCommand ) { startApp ();
} else if ( command == pullCommand || command == kdomCommand) { // In real production system, we should put // all network and parsing tasks in a seperate // thread. I put all here for simplicity.
String keywords = textField.getString(); keywords = keywords.trim(); if ( "".equals(keywords) ) { Alert a = new Alert("Blank search string"); a.setString("Please enter one or more keywords"); a.setTimeout(Alert.FOREVER); display.setCurrent(a); return; }
Lancer la requête et analyser la réponse keywords = WSencode(keywords);
String url = "http://xml.amazon.com/onca/xml?v=1.0" + "&t=webservices-20&dev-t=" + token + "&KeywordSearch=" + keywords + "&mode=books&type=lite&page=1&f=xml";
Vector books = new Vector (); try { HttpConnection conn = (HttpConnection) Connector.open (url); conn.setRequestMethod(HttpConnection.GET); InputStream is = conn.openInputStream ();
if ( command == pullCommand ) { books = getBooksViaPull( is ); } else { books = getBooksViaDOM( is ); }
is.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); }
Afficher le résultat
Form form = new Form("Results"); for (int i = 0; i < books.size(); i++) { BookDetails bd = (BookDetails) books.elementAt(i); form.append("\"" + bd.title + "\" "); form.append("By " + bd.firstAuthor + "\n"); form.append("Amazon price " + bd.newPrice + "\n"); form.append("Used price " + bd.usedPrice + "\n"); form.append(bd.url + "\n\n"); } form.addCommand(doneCommand); form.setCommandListener( (CommandListener) this); display.setCurrent(form); } else { // Do nothing } }
Ajuster les mots-clés pour transmission http // Get rid of excessive white spaces and replace significant // white spaces with %20 String WSencode(String s) { StringBuffer buf = new StringBuffer (); int len = s.length(); boolean blank = false; for (int i = 0; i < len; i++) { if ( s.charAt(i) == ' ' ) { if ( !blank ) { buf.append("%20"); blank = true; } } else { buf.append( s.charAt(i) ); blank = false; } } return buf.toString(); }
Vector getBooksViaDOM (InputStream is) throws Exception { Vector books = new Vector ();
InputStreamReader reader = new InputStreamReader(is); KXmlParser parser = new KXmlParser(); parser.setInput(reader);
Document doc = new Document (); doc.parse (parser);
// The <ProductInfo> element Element prods = doc.getRootElement();
int numOfEntries = prods.getChildCount (); for (int i = 0; i < numOfEntries; i++) { if ( prods.isText(i) ) { // Text here are all insignificant white spaces. // We are only interested in children elements } else { // Not text, must be a <Details> element Element e = prods.getElement (i); BookDetails bd = getBookDetailsViaDOM( e ); books.addElement( bd ); } } return books; }
BookDetails getBookDetailsViaDOM (Element e) throws Exception { BookDetails bd = new BookDetails (); // get attribute value from the <Details> start tag bd.url = e.getAttributeValue(null, "url"); int numOfChildren = e.getChildCount (); for (int i = 0; i < numOfChildren; i++) { if ( e.isText(i) ) { // Ignore } else { Element c = e.getElement(i); String tagname = c.getName(); if ( tagname.equals("ProductName") ) { // First child is a text node bd.title = c.getText(0).trim(); } if ( tagname.equals("Authors") ) { // Goes down the tree: The second child is the // first <Author> element. Get the first child of // that element. bd.firstAuthor = c.getElement(1).getText(0).trim(); }
BookDetails getBookDetailsViaDOM (Element e) throws Exception {...if ( tagname.equals("OurPrice") ) { // First child is a text node bd.newPrice = c.getText(0).trim(); } if ( tagname.equals("UsedPrice") ) { // First child is a text node bd.usedPrice = c.getText(0).trim(); } } } return bd; }
Vector getBooksViaPull (InputStream is) throws Exception { Vector books = new Vector ();
InputStreamReader reader = new InputStreamReader(is); KXmlParser parser = new KXmlParser(); parser.setInput(reader);
int eventType = parser.getEventType(); while (eventType != parser.END_DOCUMENT) { // Only respond to the <Details> start tag if (eventType == parser.START_TAG) { if ( parser.getName().equals("Details") ) { BookDetails bd = getBookDetailsViaPull(parser); books.addElement( bd ); } } eventType = parser.next(); } return books; }
BookDetails getBookDetailsViaPull (XmlPullParser parser)
throws Exception {
BookDetails bd = new BookDetails ();
// get attribute value from the <Details> start tag
bd.url = parser.getAttributeValue(null, "url");
int eventType = parser.next();
while ( true ) {
// Break out the loop at </Details> end tag
if ( eventType == parser.END_TAG ) {
if ( parser.getName().equals("Details") ) {
break;
}
}
...
BookDetails getBookDetailsViaPull (XmlPullParser parser) throws Exception {... if ( eventType == parser.START_TAG ) { String tagname = parser.getName(); if ( tagname.equals("ProductName") ) { // Proceed to the enclosed Text node parser.next(); bd.title = parser.getText().trim(); } if ( tagname.equals("Authors") ) { // First <Author> start tag parser.next(); // White space between tags parser.next(); // Proceed to the enclosed Text node parser.next(); bd.firstAuthor = parser.getText().trim(); }...
BookDetails getBookDetailsViaPull (XmlPullParser parser) throws Exception {... if ( tagname.equals("OurPrice") ) { // Proceed to the enclosed Text node parser.next(); bd.newPrice = parser.getText().trim(); } if ( tagname.equals("UsedPrice") ) { // Proceed to the enclosed Text node parser.next(); bd.usedPrice = parser.getText().trim(); } } eventType = parser.next(); } return bd; }
class BookDetails {
String url; String title; String firstAuthor; String newPrice; String usedPrice;
public BookDetails () { url = "http://unknown"; title = "undefined"; firstAuthor = "unknown"; newPrice = "unknown"; usedPrice = "unknown"; }
}
Références
Working with XML
http://java.sun.com/xml/jaxp/dist/1.1/docs/tutorial/overview/1_xml.html
Part II: Serial Access with the Simple API for XML (SAX) http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/index.html http://java.sun.com/webservices/jaxp/dist/1.
1/docs/tutorial/sax/work/Echo03.java http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/2a_echo
.html
Part III: XML and the Document Object Model (DOM) http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/dom/index.html