Skip to content

Instantly share code, notes, and snippets.

@fantactuka
Created October 11, 2013 18:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fantactuka/6939900 to your computer and use it in GitHub Desktop.
Save fantactuka/6939900 to your computer and use it in GitHub Desktop.
WADL parser
<!doctype html>
<html>
<head>
<title>WADL parser</title>
<link rel="stylesheet" href="application.css"/>
<style type="text/css">
ul#output {
list-style: none outside;
margin: 0 0 20px;
padding: 0;
}
ul#output > li {
border-top: 1px solid #ddd;
cursor: pointer;
padding: 10px;
}
ul#output > li:nth-child(odd) {
background: #eee;
}
ul#output > li:hover {
background: #e7f3ff;
}
.resource-type,
.resource-param-type {
display: inline-block;
min-width: 50px;
text-align: center;
font-weight: normal;
padding-left: 5px;
padding-right: 5px;
margin-right: 15px;
text-transform: uppercase;
font-size: 0.75em;
}
.resource-type-get {
background: #8da67c;
}
.resource-type-post {
background: #6376a6;
}
.resource-type-put {
background: #b691c8;
}
.resource-type-delete {
background: #a63446;
}
.resource-path,
.resource-param-name {
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
}
.collapsed div.params {
display: none;
}
</style>
<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="lib/underscore.js"></script>
<script type="text/javascript">
function xml2json(xml, tab) {
var X = {
toObj: function(xml) {
var o = {};
if (xml.nodeType == 1) { // element node ..
if (xml.attributes.length) // element with attributes ..
for (var i = 0; i < xml.attributes.length; i++)
o["@" + xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue || "").toString();
if (xml.firstChild) { // element has child nodes ..
var textChild = 0, cdataChild = 0, hasElementChild = false;
for (var n = xml.firstChild; n; n = n.nextSibling) {
if (n.nodeType == 1) hasElementChild = true;
else if (n.nodeType == 3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++; // non-whitespace text
else if (n.nodeType == 4) cdataChild++; // cdata section node
}
if (hasElementChild) {
if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..
X.removeWhite(xml);
for (var n = xml.firstChild; n; n = n.nextSibling) {
if (n.nodeType == 3) // text node
o["#text"] = X.escape(n.nodeValue);
else if (n.nodeType == 4) // cdata node
o["#cdata"] = X.escape(n.nodeValue);
else if (o[n.nodeName]) { // multiple occurence of element ..
if (o[n.nodeName] instanceof Array)
o[n.nodeName][o[n.nodeName].length] = X.toObj(n);
else
o[n.nodeName] = [o[n.nodeName], X.toObj(n)];
}
else // first occurence of element..
o[n.nodeName] = X.toObj(n);
}
}
else { // mixed content
if (!xml.attributes.length)
o = X.escape(X.innerXml(xml));
else
o["#text"] = X.escape(X.innerXml(xml));
}
}
else if (textChild) { // pure text
if (!xml.attributes.length)
o = X.escape(X.innerXml(xml));
else
o["#text"] = X.escape(X.innerXml(xml));
}
else if (cdataChild) { // cdata
if (cdataChild > 1)
o = X.escape(X.innerXml(xml));
else
for (var n = xml.firstChild; n; n = n.nextSibling)
o["#cdata"] = X.escape(n.nodeValue);
}
}
if (!xml.attributes.length && !xml.firstChild) o = null;
}
else if (xml.nodeType == 9) { // document.node
o = X.toObj(xml.documentElement);
}
else
alert("unhandled node type: " + xml.nodeType);
return o;
},
toJson: function(o, name, ind) {
var json = name ? ("\"" + name + "\"") : "";
if (o instanceof Array) {
for (var i = 0, n = o.length; i < n; i++)
o[i] = X.toJson(o[i], "", ind + "\t");
json += (name ? ":[" : "[") + (o.length > 1 ? ("\n" + ind + "\t" + o.join(",\n" + ind + "\t") + "\n" + ind) : o.join("")) + "]";
}
else if (o == null)
json += (name && ":") + "null";
else if (typeof(o) == "object") {
var arr = [];
for (var m in o)
arr[arr.length] = X.toJson(o[m], m, ind + "\t");
json += (name ? ":{" : "{") + (arr.length > 1 ? ("\n" + ind + "\t" + arr.join(",\n" + ind + "\t") + "\n" + ind) : arr.join("")) + "}";
}
else if (typeof(o) == "string")
json += (name && ":") + "\"" + o.toString() + "\"";
else
json += (name && ":") + o.toString();
return json;
},
innerXml: function(node) {
var s = ""
if ("innerHTML" in node)
s = node.innerHTML;
else {
var asXml = function(n) {
var s = "";
if (n.nodeType == 1) {
s += "<" + n.nodeName;
for (var i = 0; i < n.attributes.length; i++)
s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue || "").toString() + "\"";
if (n.firstChild) {
s += ">";
for (var c = n.firstChild; c; c = c.nextSibling)
s += asXml(c);
s += "</" + n.nodeName + ">";
}
else
s += "/>";
}
else if (n.nodeType == 3)
s += n.nodeValue;
else if (n.nodeType == 4)
s += "<![CDATA[" + n.nodeValue + "]]>";
return s;
};
for (var c = node.firstChild; c; c = c.nextSibling)
s += asXml(c);
}
return s;
},
escape: function(txt) {
return txt.replace(/[\\]/g, "\\\\")
.replace(/[\"]/g, '\\"')
.replace(/[\n]/g, '\\n')
.replace(/[\r]/g, '\\r');
},
removeWhite: function(e) {
e.normalize();
for (var n = e.firstChild; n;) {
if (n.nodeType == 3) { // text node
if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node
var nxt = n.nextSibling;
e.removeChild(n);
n = nxt;
}
else
n = n.nextSibling;
}
else if (n.nodeType == 1) { // element node
X.removeWhite(n);
n = n.nextSibling;
}
else // any other node
n = n.nextSibling;
}
return e;
}
};
if (xml.nodeType == 9) // document node
xml = xml.documentElement;
var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
return "{\n" + tab + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "\n}";
}
$(function() {
var $form = $('#url-form'),
$url = $('#url-input'),
$output = $('#output'),
$toggle = $('#toggle-params'),
$resourceTpl = _.template($('#resource-template').html()),
collapsedClass = 'collapsed';
$toggle.click(function() {
$output.find('> li')[$output.find('.' + collapsedClass).length ? 'removeClass' : 'addClass'](collapsedClass);
return false;
});
$output.on('click', '> li', function(e) {
$(e.currentTarget).toggleClass(collapsedClass);
});
$form.on('submit',function() {
var url = $url.val();
$.ajax(url, {
success: function(xml) {
var json = xml2json(xml, ''),
data = JSON.parse(json);
try {
render(data.application.resources);
} catch(e) {
renderError();
throw e;
}
},
error: renderError
});
return false;
});
function renderError() {
$output.html('<li class="alert-error">Unable to parse WADL</li>');
}
function render(resources) {
var html = _.map(parseData(resources),function(resource) {
return $resourceTpl({ resource: resource });
}).join('');
$output.html(html);
}
function parseData(resources) {
return _.chain(resources.resource).map(function(resource) {
return parseResource(resource);
}).flatten().value();
}
function parseResource(resource, base) {
var path = (base || '') + resource['@path'],
results = [];
if (resource.method) {
var request = resource.method.request || {},
queryParams = parseParams(request.param),
type = resource.method['@name'],
queryString = _.isEmpty(queryParams) ? '' : '?' + $.param(queryParams),
pathHtml = (path + decodeURIComponent(queryString)).replace(/\{([^}]*)\}/g, '<code>$1</code>');
results.push({
path: path,
pathHtml: pathHtml,
type: type,
typeCss: 'resource-type-' + type.toLowerCase(),
queryParams: queryParams,
pathParams: parseParams(resource.param)
});
}
if (resource.resource) {
_.chain([resource.resource]).flatten().each(function(childResource) {
results.push(parseResource(childResource, path))
});
}
return results;
}
function parseParams() {
var params = _.chain(arguments).flatten().compact().value(),
result = [];
_.each(params, function(param) {
result.push({
name: param['@name'],
type: param['@type'] ? param['@type'].replace('xs:', '') : 'custom',
value: '{' + param['@name'] + '}'
});
});
return result;
}
});
</script>
</head>
<body>
<div class="container text-left" style="width: 90%">
<h2>WADL parser</h2>
<form action="#" id="url-form">
<div class="input-prepend input-append">
<span class="add-on"><small>WADL URL</small></span>
<input class="span5" type="text" value="" id="url-input">
<input class="btn" type="submit" value="Go!"/>
</div>
</form>
<p class="text-right">
<a href="#toggle" id="toggle-params" class="btn btn-small">Expand / collapse</a>
</p>
<ul id="output"></ul>
<script type="text/x-template" id="resource-template">
<li>
<span class="label resource-type <%= resource.typeCss %>"><%= resource.type %></span>
<span class="resource-path"><%= resource.pathHtml %></span>
<div class="params">
<% if (resource.pathParams.length) { %>
<h5>Path params</h5>
<ul class="params">
<% for(var i = 0; i < resource.pathParams.length; i ++) { %>
<li>
<span class="label resource-param-type"><%= resource.pathParams[i].type %></span>
<span class="resource-param-name"><%= resource.pathParams[i].name %></span>
</li>
<% } %>
</ul>
<% } %>
<% if (resource.queryParams.length) { %>
<h5>Query params</h5>
<ul class="params">
<% for(var i = 0; i < resource.queryParams.length; i ++) { %>
<li>
<span class="label resource-param-type"><%= resource.queryParams[i].type %></span>
<span class="resource-param-name"><%= resource.queryParams[i].name %></span>
</li>
<% } %>
</ul>
<% } %>
</div>
</li>
</script>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment