You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
2.3 KiB

2 years ago
/**
* Module dependencies.
*/
/**
* Expose `parse`.
*/
/**
* Parse the given string of `xml`.
*
* @param {String} xml
* @return {Object}
* @api public
*/
function parse(xml) {
xml = xml.trim(); // strip comments
xml = xml.replace(/<!--[\s\S]*?-->/g, '');
return document();
/**
* XML document.
*/
function document() {
return {
declaration: declaration(),
root: tag()
};
}
/**
* Declaration.
*/
function declaration() {
const m = match(/^<\?xml\s*/);
if (!m) return; // tag
const node = {
attributes: {}
}; // attributes
while (!(eos() || is('?>'))) {
const attr = attribute();
if (!attr) return node;
node.attributes[attr.name] = attr.value;
}
match(/\?>\s*/);
return node;
}
/**
* Tag.
*/
function tag() {
const m = match(/^<([\w-:.]+)\s*/);
if (!m) return; // name
const node = {
name: m[1],
attributes: {},
children: []
}; // attributes
while (!(eos() || is('>') || is('?>') || is('/>'))) {
const attr = attribute();
if (!attr) return node;
node.attributes[attr.name] = attr.value;
} // self closing tag
if (match(/^\s*\/>\s*/)) {
return node;
}
match(/\??>\s*/); // content
node.content = content(); // children
let child;
while (child = tag()) {
node.children.push(child);
} // closing
match(/^<\/[\w-:.]+>\s*/);
return node;
}
/**
* Text content.
*/
function content() {
const m = match(/^([^<]*)/);
if (m) return m[1];
return '';
}
/**
* Attribute.
*/
function attribute() {
const m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/);
if (!m) return;
return {
name: m[1],
value: strip(m[2])
};
}
/**
* Strip quotes from `val`.
*/
function strip(val) {
return val.replace(/^['"]|['"]$/g, '');
}
/**
* Match `re` and advance the string.
*/
function match(re) {
const m = xml.match(re);
if (!m) return;
xml = xml.slice(m[0].length);
return m;
}
/**
* End-of-source.
*/
function eos() {
return xml.length == 0;
}
/**
* Check for `prefix`.
*/
function is(prefix) {
return xml.indexOf(prefix) == 0;
}
}
module.exports = parse;