1 #// Usage: jjs -scripting jsadapter_dom.js 2 3 /* 4 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * - Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * - Neither the name of Oracle nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 // Simple example that demonstrates reading XML Rss feed 35 // to generate a HTML file from script and show it by browser 36 // Uses XML DOM parser and DOM element wrapped by script 37 // "proxy" (JSAdapter constructor) 38 39 // Java classes used 40 var DocBuilderFac = Java.type("javax.xml.parsers.DocumentBuilderFactory"); 41 var Node = Java.type("org.w3c.dom.Node"); 42 var File = Java.type("java.io.File"); 43 var FileWriter = Java.type("java.io.FileWriter"); 44 var PrintWriter = Java.type("java.io.PrintWriter"); 45 46 // constants from Node class 47 var ELEMENT_NODE = Node.ELEMENT_NODE; 48 var TEXT_NODE = Node.TEXT_NODE; 49 50 // parse XML from uri and return Document 51 function 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 57 function 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 73 function 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__. 91 function 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 127 function 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> 140 Published on ${rss.channel.pubDate} 141 </p> 142 143 HEAD 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 154 LIST 155 } 156 str += <<END 157 158 </body> 159 </html> 160 161 END 162 return str; 163 } 164 165 // write the string to the given file 166 function 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 176 var str = getBooksHtml(); 177 178 // write to file. __DIR__ is directory where 179 // this script is stored. 180 var file = new File(__DIR__ + "books.html"); 181 writeTo(file, str); 182 183 // show it by desktop browser 184 try { 185 var Desktop = Java.type("java.awt.Desktop"); 186 Desktop.desktop.browse(file.toURI()); 187 } catch (e) { 188 print(e); 189 }