function clfrdfparserAddFrames(clfXML, addFrameData, addTopicData, addSocialTagData) {
	function getNodeText(node) {
		if (node.text != null)
			return node.text;
		return node.textContent;
	}
	function extractRdfNode(frame) {
		function forceUniqKey(hash, key, value) {
			var i = "";
			while (hash[key + i] != null)
				i++;
			return hash[key + i] = value;
		}
		if (frame.tagName != "rdf:Description")
			return;
		var type = getAttributeEX(getElementsByTagNameEX(frame,'rdf', 'type')[0], 'rdf', 'resource');
		if (type.indexOf(dcprefix) == 0) {
			// Add Topic
			var topicName = getNodeText(getElementsByTagNameEX(frame, 'c', 'categoryName')[0]);
			if (topicName == "Other")
				return;
			var topicScore = Math.round(parseFloat(getNodeText(getElementsByTagNameEX(frame, 'c', 'score')[0]) * 100));
			addTopicData(topicName, topicScore);
		}
		if (type.indexOf(stprefix) == 0) {
			// Add SocialTags
			var stName = getNodeText(getElementsByTagNameEX(frame, 'c', 'name')[0]);
			var stScore = parseInt(getNodeText(getElementsByTagNameEX(frame, 'c', 'importance')[0]));
			addSocialTagData(stName, stScore);
		}
		if (type.indexOf(emprefix) != 0)
			return;
		var hashcode = getAttributeEX(frame, 'rdf', 'about');
		var category = type.substr(emprefix.length + 2);
		var meta = new Object();
        var about = getAttributeEX(frame, 'rdf', 'about');
        // Add all attributes
		for (var i = 0; i < frame.childNodes.length; i++) {
			var key = frame.childNodes[i].nodeName;
			if (key.indexOf('c:') == 0) {
				key = key.substr(2);
				var ref = getAttributeEX(frame.childNodes[i], 'rdf', 'resource');
				if (ref == null || ref == '') {
					forceUniqKey(meta, key, getNodeText(frame.childNodes[i]).replace(/[\s\n\t\r]+/g, ' '));
				} else {
					if (disambiguation[ref] != null)
						forceUniqKey(meta, key, disambiguation[ref]['name']);
					else
						forceUniqKey(meta, key, '%ref%' + ref);
				}
			}
		}
		// Add special attributes
		meta['_url'] = hashcode;
		if (disambiguation[about] != null)
			for (var key in disambiguation[about])
				meta[key] = disambiguation[about][key];
		meta['_isTerm'] = type.substr(emprefix.length, 1) == 'e'
		meta['_relevance'] = relevance[about];
		meta['_category'] = category;
		if (meta['_isTerm']) {
			meta['_name'] = meta['name'];
			meta['name'] = null;
		}
		rdfData[hashcode] = meta;
	}
	function extractOffsetLength(frame) {
		if (frame.tagName != "rdf:Description")
			return;
		var type = getAttributeEX(getElementsByTagNameEX(frame, 'rdf', 'type')[0], 'rdf' ,'resource');
		if (type.indexOf(instanceprefix) != 0)
			return;
		var hashcode = getAttributeEX(getElementsByTagNameEX(frame, 'c', 'subject')[0], 'rdf' ,'resource');
		var data = rdfData[hashcode];
		// fix references if exists
		for (var key in data) {
			if (typeof data[key] == "string" && data[key].indexOf('%ref%') == 0) {
				if (rdfData[data[key].substr(5)]) {
					data[key] = rdfData[data[key].substr(5)]['_name'];
				} else {
					data[key] = data[key].substr(5);
				}
			}
		}
		var offset = getNodeText(getElementsByTagNameEX(frame, 'c' ,'offset')[0]);
		var len = getNodeText(getElementsByTagNameEX(frame, 'c', 'length')[0]);
		var frameid = ++_id;
		addFrameData(frameid, data, parseInt(offset), parseInt(len));
	}
	function resolvedisambiguation(frame) {
		if (frame.tagName == "rdf:Description") {
			var type = getAttributeEX(getElementsByTagNameEX(frame, 'rdf', 'type')[0], 'rdf' ,'resource');
			// EntityResolution
			if (type.indexOf(erprefix) == 0) {
				var url = getAttributeEX(frame, 'rdf', 'about');
				var info = new Object();
				// Add all attributes
				for (var i = 0; i < frame.childNodes.length; i++) {
					var key = frame.childNodes[i].nodeName;
					if (key.indexOf('c:') == 0) {
						key = key.substr(2);
						if (key != 'subject' && key != 'docId')
							info[key] = getNodeText(frame.childNodes[i]);
					}
				}
				var refNodes = getElementsByTagNameEX(frame, 'c', 'subject');
				for (var i=0; i < refNodes.length; i++) {
					var ref = getAttributeEX(refNodes[i], 'rdf' ,'resource');
					info['_url'] = url;
					disambiguation[ref] = info;
				}
			}
			// RelevanceInfo
			if (type.indexOf(riprefix) == 0) {
				var ref = getAttributeEX(getElementsByTagNameEX(frame, 'c', 'subject')[0], 'rdf' ,'resource');
				var value = getNodeText(getElementsByTagNameEX(frame, 'c', 'relevance')[0]);
				relevance[ref] = Math.round(parseFloat(value) * 100);
			}
		}
	}
	var instanceprefix = 'http://s.opencalais.com/1/type/sys/InstanceInfo'
	var emprefix = 'http://s.opencalais.com/1/type/em/';
	var erprefix = 'http://s.opencalais.com/1/type/er/';
	var riprefix = 'http://s.opencalais.com/1/type/sys/RelevanceInfo';
	var dcprefix = 'http://s.opencalais.com/1/type/cat/DocCat';
	var stprefix = 'http://s.opencalais.com/1/type/tag/SocialTag';
	var rdfData = new Object();
	var disambiguation = new Object();
	var relevance = new Object();
	var allframes = clfXML.getXML().documentElement.childNodes;
	if (allframes == null || allframes.length == 0)
		throw new Error("CLFERROR: Unsupported RDF Document\n\t(Root element is empty)");
	var _id = 100000; // default frame id
	for (var i = 0; i < allframes.length; i++)
		resolvedisambiguation(allframes[i]);
	for (var i = 0; i < allframes.length; i++)
		extractRdfNode(allframes[i]);
	for (var i = 0; i < allframes.length; i++)
		extractOffsetLength(allframes[i]);
}

var clf_ns2url = new Object();
clf_ns2url.rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
clf_ns2url.c = "http://s.opencalais.com/1/pred/"

function getElementsByTagNameEX(e, ns, tag) {
	if (e.getElementsByTagNameNS != null)
		return e.getElementsByTagNameNS(clf_ns2url[ns], tag);
	return e.getElementsByTagName(ns + ':' + tag);
}

function getAttributeEX(e, ns, tag) {
	if (e.getAttributeNS != null)
		return e.getAttributeNS(clf_ns2url[ns], tag);
	return e.getAttribute(ns + ':' + tag);
}
