Help Center » Developing Applications » The Complete Metaweb Query Language (MQL) Reference Guide » Appendix A. Additional Code

Appendix A. Additional Code

This appendix collects interesting or useful examples that are too long, or would be too much of a digression to appear in the elsewhere in this manual.

A.1. json.js

Example A.1 is the json.js module that defines the JSON.parse() and JSON.serialize() functions used in the JavaScript-based examples of Chapter 4.

Example A.1. json.js: JSON parsing and serialization in JavaScript

/**
 * json.js:
 * This file defines functions JSON.parse() and JSON.serialize()
 * for decoding and encoding JavaScript objects and arrays from and to
 * application/json format.
 * 
 * The JSON.parse() function is a safe parser: it uses eval() for
 * efficiency but first ensures that its argument contains only legal
 * JSON literals rather than unrestricted JavaScript code.
 *
 * This code is derived from the code at http://www.json.org/json.js
 * which was written and placed in the public domain by Douglas Crockford.
 **/
// This object holds our parse and serialize functions
var JSON = {}; 

// The parse function is short but the validation code is complex.
// See http://www.ietf.org/rfc/rfc4627.txt
JSON.parse = function(s) {
    try {
        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                                   s.replace(/"(\\.|[^"\\])*"/g, ''))) &&
            eval('(' + s + ')');
    }
    catch (e) {
        return false;
    }
};

// Our JSON.serialize() function requires a number of helper functions.
// They are all defined within this anonymous function so that they remain
// private and do not pollute the global namespace.
(function () {
    var m = {  // A character conversion map
            '\b': '\\b', '\t': '\\t',  '\n': '\\n', '\f': '\\f',
            '\r': '\\r', '"' : '\\"',  '\\': '\\\\'
        },
        s = { // Map type names to functions for serializing those types
            'boolean': function (x) { return String(x); },
            'null': function (x) { return "null"; },
            number: function (x) { return isFinite(x) ? String(x) : 'null'; },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            },
            array: function (x) {
                var a = ['['], b, f, i, l = x.length, v;
                for (i = 0; i < l; i += 1) {
                    v = x[i];
                    f = s[typeof v];
                    if (f) {
                        v = f(v);
                        if (typeof v == 'string') {
                            if (b) {
                                a[a.length] = ',';
                            }
                            a[a.length] = v;
                            b = true;
                        }
                    }
                }
                a[a.length] = ']';
                return a.join('');
            },
            object: function (x) {
                if (x) {
                    if (x instanceof Array) {
                        return s.array(x);
                    }
                    var a = ['{'], b, f, i, v;
                    for (i in x) {
                        v = x[i];
                        f = s[typeof v];
                        if (f) {
                            v = f(v);
                            if (typeof v == 'string') {
                                if (b) {
                                    a[a.length] = ',';
                                }
                                a.push(s.string(i), ':', v);
                                b = true;
                            }
                        }
                    }
                    a[a.length] = '}';
                    return a.join('');
                }
                return 'null';
            }
        };

    // Export our serialize function outside of this anonymous function
    JSON.serialize = function(o) { return s.object(o); };
})(); // Invoke the anonymous function once to define JSON.serialize()


A.2. Client-side MQL Queries through a Proxy

Chapter 4 includes a JavaScript Metaweb.read() utility function whose script-based implementation is shown in Example 4.8. In this section we present a proxy-based implementation of the same function.

The proxy-based implementation of Example A.2 behaves identically to the script-based implementation in Example 4.8. We could convert the test application of Example 4.7 to use this new implementation simply by changing this line:

<script src="metaweb.js"></script> <!-- defines Metaweb.read() -->

to this:

<script src="metaweb_proxy.js"></script> <!-- defines Metaweb.read() -->

This implementation of Metaweb.read() uses an XMLHttpRequest object to submit the HTTP request to the proxy service. (XMLHttpRequest allows HTTP requests to be scripted with JavaScript. The API for this object is not described here: it is a common feature of all Ajax-based web application frameworks and should be documented in any modern JavaScript reference.) It uses the JSON.serialize() function to convert the query object to a string, and uses JSON.parse() to convert the response text back into object form. The implementation of these JSON functions is in Example A.1.

Example A.2. metaweb_proxy.js: Metaweb queries through a proxy

/**
 * metaweb_proxy.js: 
 *
 * This file implements a Metaweb.read() utility function using XMLHttpRequest
 * and a server-side proxy script named mqlread.php
 * For simplicity, this code requires a native XMLHttpRequest object,
 * which means that it does not work in Internet Explorer prior to IE7.
 **/
var Metaweb = {};                    // Define our namespace
Metaweb.QUERY_PROXY = "mqlread.php"; // The relative URL of the proxy service

// Send query q to Metaweb, and pass the result to function f.
// If hasEnvelope is omitted or false, then this function wraps an
// envelope around the query.
Metaweb.read = function(q, f) {
    // Put the query in inner and outer envelopes
    envelope = {qname: {query: q}}
    // Serialize the envelope to a JSON string
    var serialized = JSON.serialize(envelope);
    // URL encode the serialized query
    var encoded = encodeURIComponent(serialized);
    // Build the query URL
    var url = Metaweb.QUERY_PROXY + "?queries=" + encoded

    // Use XMLHttpRequest to submit the request to the proxy
    var request = new XMLHttpRequest();
    // When the response arrives, call this function
    request.onreadystatechange = function() {
        // If the request is done and was successful
        if (request.readyState == 4 && request.status == 200) {
            // Parse the JSON text of response to an envelope object
            var outerEnvelope = JSON.parse(request.responseText);
            // Get inner envelope from outer envelope
            var innerEnvelope = outerEnvelope.qname;
            // Make sure the query was successful
            if (innerEnvelope.status == "/mql/status/ok") {
                // Take the result object out of the response envelope
                var result = innerEnvelope.result;
                // And pass that object to the user's function
                f(result);
            }
        }
    }
    // Now send the request to the proxy
    request.open("GET", url);
    request.send(null);
};

This Metaweb.read() implementation is not complete without the mqlread.php proxy script that it relies on. Example A.3 shows a very simple implementation of such a proxy: it is a PHP script that simply forwards the URL parameter query to the mqlread service at Metaweb and relies on the default behavior of the PHP curl_exec() function which directs the response from the forwarded query to the output stream of the script. Notice that this trivially simple script is not a fully adequate proxy. For a production web application, you would want to use a fully-fleshed out proxy.

Example A.3. mqlread.php: a trivial mqlread proxy in PHP

<?php
$q = str_replace("\\\"", "\"", $_GET["queries"]);
$url = "http://www.freebase.com/api/service/mqlread?queries=" . urlencode($q);
$request = curl_init($url);
curl_setopt($request, CURLOPT_COOKIE, "###freebase.com cookie data here###");
curl_exec($request);
curl_close($request);
?>

Recent Discussions about Appendix A. Additional Code

There are no conversations on this topic. Would you like to start one?

Start the Discussion »

Related Help Topics

empty