svgdom
Version:
Straightforward DOM implementation for SVG, HTML and XML
81 lines (61 loc) • 2 kB
JavaScript
import sax from 'sax'
// TODO: Its an XMLParser not HTMLParser!!
export const HTMLParser = function (str, el) {
let currentTag = el
// const namespaces = { xmlns: el.getAttribute('xmlns') }
let document = el.ownerDocument
let cdata = null
// sax expects a root element but we also missuse it to parse fragments
if (el.nodeType !== el.DOCUMENT_NODE) {
str = '<svgdom:wrapper xmlns:svgdom="svgdom:rocks">' + str + '</svgdom:wrapper>'
} else {
document = el
}
const parser = sax.parser(true, {
// lowercase: true,
xmlns: true,
strictEntities: true
})
parser.onerror = (e) => {
throw e
}
parser.ondoctype = () => {
if (currentTag !== document) {
throw new Error('Doctype can only be appended to document')
}
currentTag.appendChild(document.implementation.createDocumentType())
}
parser.ontext = (str) => currentTag.appendChild(document.createTextNode(str))
parser.oncomment = (str) => currentTag.appendChild(document.createComment(str))
// parser.onopennamespace = ns => {
// namespaces[ns.prefix] = ns.uri
// }
// parser.onclosenamespace = ns => {
// delete namespaces[ns.prefix]
// }
parser.onopentag = node => {
if (node.name === 'svgdom:wrapper') return
const attrs = node.attributes
const uri = node.uri || currentTag.lookupNamespaceURI(node.prefix || null)
const newElement = document.createElementNS(uri, node.name)
for (const [ name, node ] of Object.entries(attrs)) {
newElement.setAttributeNS(node.uri, name, node.value)
}
currentTag.appendChild(newElement)
currentTag = newElement
}
parser.onclosetag = tagName => {
if (tagName === 'svgdom:wrapper') return
currentTag = currentTag.parentNode
}
parser.onopencdata = () => {
cdata = document.createCDATASection('')
}
parser.oncdata = (str) => {
cdata.appendData(str)
}
parser.onclosecdata = () => {
currentTag.appendChild(cdata)
}
parser.write(str)
}