| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- /**
- * 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
|