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 }