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