jsadapter_dom.js revision 802:235d22ccfd24
12116Sjkh#// Usage: jjs -scripting jsadapter_dom.js 22116Sjkh 32116Sjkh/* 42116Sjkh * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 52116Sjkh * 62116Sjkh * Redistribution and use in source and binary forms, with or without 72116Sjkh * modification, are permitted provided that the following conditions 82116Sjkh * are met: 92116Sjkh * 102116Sjkh * - Redistributions of source code must retain the above copyright 112116Sjkh * notice, this list of conditions and the following disclaimer. 122116Sjkh * 132116Sjkh * - Redistributions in binary form must reproduce the above copyright 142116Sjkh * notice, this list of conditions and the following disclaimer in the 152116Sjkh * documentation and/or other materials provided with the distribution. 162116Sjkh * 172116Sjkh * - Neither the name of Oracle nor the names of its 182116Sjkh * contributors may be used to endorse or promote products derived 192116Sjkh * from this software without specific prior written permission. 202116Sjkh * 212116Sjkh * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 222116Sjkh * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 232116Sjkh * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 242116Sjkh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 252116Sjkh * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 262116Sjkh * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 272116Sjkh * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 282116Sjkh * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 292116Sjkh * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 302116Sjkh * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 312116Sjkh * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 322116Sjkh */ 332116Sjkh 342116Sjkh// Simple example that demonstrates reading XML Rss feed 352116Sjkh// to generate a HTML file from script and show it by browser 3623577Sbde// Uses XML DOM parser and DOM element wrapped by script 372116Sjkh// "proxy" (JSAdapter constructor) 3850476Speter 392116Sjkh// Java classes used 402116Sjkhvar DocBuilderFac = Java.type("javax.xml.parsers.DocumentBuilderFactory"); 412116Sjkhvar Node = Java.type("org.w3c.dom.Node"); 422116Sjkhvar File = Java.type("java.io.File"); 4361335Sbdevar FileWriter = Java.type("java.io.FileWriter"); 442116Sjkhvar PrintWriter = Java.type("java.io.PrintWriter"); 45 46// constants from Node class 47var ELEMENT_NODE = Node.ELEMENT_NODE; 48var TEXT_NODE = Node.TEXT_NODE; 49 50// parse XML from uri and return Document 51function parseXML(uri) { 52 var docBuilder = DocBuilderFac.newInstance().newDocumentBuilder(); 53 return docBuilder["parse(java.lang.String)"](uri); 54} 55 56// get child Elements of given name of the parent element given 57function getChildElements(elem, name) { 58 var nodeList = elem.childNodes; 59 var childElems = []; 60 var len = nodeList.length; 61 for (var i = 0; i < len; i++) { 62 var node = nodeList.item(i); 63 if (node.nodeType == ELEMENT_NODE && 64 node.tagName == name) { 65 childElems.push(wrapElement(node)); 66 } 67 } 68 69 return childElems; 70} 71 72// get concatenated child text content of an Element 73function getElemText(elem) { 74 var nodeList = elem.childNodes; 75 var len = nodeList.length; 76 var text = ''; 77 for (var i = 0; i < len; i++) { 78 var node = nodeList.item(i); 79 if (node.nodeType == TEXT_NODE) { 80 text += node.nodeValue; 81 } 82 } 83 84 return text; 85} 86 87// Wrap DOM Element object as a convenient script object 88// using JSAdapter. JSAdapter is like java.lang.reflect.Proxy 89// in that it allows property access, method calls be trapped 90// by 'magic' methods like __get__, __call__. 91function wrapElement(elem) { 92 if (! elem) { 93 return elem; 94 } 95 return new JSAdapter() { 96 // getter to expose child elements and attributes by name 97 __get__: function(name) { 98 if (typeof name == 'string') { 99 if (name.startsWith('@')) { 100 var attr = elem.getAttributeNode(name.substring(1)); 101 return !attr? undefined : attr.value; 102 } 103 104 var arr = getChildElements(elem, name); 105 if (arr.length == 1) { 106 // single child element, expose as single element 107 return arr[0]; 108 } else { 109 // multiple children of given name, expose as array 110 return arr; 111 } 112 } 113 return undefined; 114 }, 115 116 __call__: function(name) { 117 // toString override to get text content of this Element 118 if (name == 'toString' || name == 'valueOf') { 119 return getElemText(elem); 120 } 121 return undefined; 122 } 123 } 124} 125 126// generate HTML using here-doc and string interpolation 127function getBooksHtml() { 128 var doc = parseXML("http://www.gutenberg.org/cache/epub/feeds/today.rss"); 129 // wrap document root Element as script convenient object 130 var rss = wrapElement(doc.documentElement); 131 print("rss file version " + rss['@version']); 132 133 var str = <<HEAD 134 135<html> 136<title>${rss.channel.title}</title> 137<body> 138<h1>${rss.channel.description}</h1> 139<p> 140Published on ${rss.channel.pubDate} 141</p> 142 143HEAD 144 145 var items = rss.channel.item; 146 for each (var i in items) { 147 str += <<LIST 148 149<dl> 150<dt><a href="${i.link}">${i.title}</a></dt> 151<dd>${i.description}</dd> 152</dl> 153 154LIST 155 } 156 str += <<END 157 158</body> 159</html> 160 161END 162 return str; 163} 164 165// write the string to the given file 166function writeTo(file, str) { 167 var w = new PrintWriter(new FileWriter(file)); 168 try { 169 w.print(str); 170 } finally { 171 w.close(); 172 } 173} 174 175// generate books HTML 176var str = getBooksHtml(); 177 178// write to file. __DIR__ is directory where 179// this script is stored. 180var file = new File(__DIR__ + "books.html"); 181writeTo(file, str); 182 183// show it by desktop browser 184try { 185 var Desktop = Java.type("java.awt.Desktop"); 186 Desktop.desktop.browse(file.toURI()); 187} catch (e) { 188 print(e); 189} 190