File: lib/parsers/xml.js
/*
* niViz -- snow profiles visualization
* Copyright (C) 2015 WSL/SLF - Fluelastrasse 11 - 7260 Davos Dorf - Switzerland.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function (niviz, DOMParser, document, Element) {
'use strict';
// --- Module Dependencies ---
var Parser = niviz.Parser;
var literal = niviz.util.literal;
/** @module niviz */
/**
* An XML parser.
*
* @class XMLParser
* @constructor
*
* @extends Parser
*
* @param {Array|String} data The data to parse.
*/
function XMLParser(data) {
Parser.call(this, data);
}
Parser.implement(XMLParser, 'xml');
/**
* This method needs to be implemented by all children of class Parser.
* Parse the complete document and return the result.
*
* @method _parse
* @protected
* @return
*/
XMLParser.prototype._parse = function () {
try {
var parser = new DOMParser();
var xml = parser.parseFromString(this.data, 'application/xml');
if (xml.documentElement.nodeName === 'parseerror')
throw new Error('failed to parse XML');
this.document = xml.documentElement;
this.parse_xml();
} catch (error) {
return this.emit('error', error);
}
this.end(); // emit the end event
return this.result;
};
/**
* @method parse_xml
* @abstract
*/
XMLParser.prototype.parse_xml = function () {
throw new Error('not implemented');
};
/**
* @method text
* @param {Element|String} query
* @param {Element} node
* @return {String} The text content the node
*/
XMLParser.prototype.text = function (query, node) {
if (!node && typeof query !== 'string')
node = query;
else
node = this.$(query, node);
return literal(node && node.textContent || '');
};
/**
* Get the node with a certain tag.
*
* @method $
* @param {String} query
* @param {Element} [node] Where to start query
* @return {Element}
*/
XMLParser.prototype.$ = function (query, node) {
return scoped$query('querySelector', query, node || this.document);
};
/**
* Get all the nodes with a certain tag.
*
* @method $
* @param {String} query
* @param {Element} [node] Where to start query
* @return {Element}
*/
XMLParser.prototype.$$ = function (query, node) {
return scoped$query('querySelectorAll', query, node || this.document);
};
// --- Compatibility ---
var scoped$query = (function () {
try {
document
.createElement('div')
.querySelectorAll(':scope *');
return function scope$native(method, query, node) {
return node[method](query);
};
} catch (error) {
var SCOPE = /^:scope/i;
return function scope$shim(method, query, node) {
if (!SCOPE.test(query))
return node[method](query);
// We could create a temporary container here
// but we don't need support this case!
if (!node.parentNode)
throw new Error(':scope selector on root node');
// Must set both, in order for # selector to work in XML!
if (!node.id) {
node.id = 'id_' + (+new Date());
node.setAttribute('id', node.id);
node.setAttribute('kapustka', node.id);
}
return node.querySelector(query.replace(SCOPE, 'Layer[kapustka]'));
};
}
}());
}(niviz, DOMParser, document, Element));