Skip to content

Instantly share code, notes, and snippets.

@tomhodgins
Last active March 20, 2020 04:18
Show Gist options
  • Save tomhodgins/c0b541ee923ffe9bdb3c3953aa467831 to your computer and use it in GitHub Desktop.
Save tomhodgins/c0b541ee923ffe9bdb3c3953aa467831 to your computer and use it in GitHub Desktop.
function object2microxml(object) {
function consume(object) {
// Null
if (object === null) {
return ['null', {}, ['null']]
}
// Array
if (object instanceof Array) {
return ['array', {}, object.map(function(child) { return consume(child) })]
}
// Object
if (typeof object === 'object') {
var properties = []
for (var prop in object) {
properties.push(['property', {}, [
['key', {}, [prop]],
['value', {}, [consume(object[prop])]]
]])
}
return ['object', {}, properties]
}
// Boolean
if (typeof object === 'boolean') {
return ['boolean', {}, [object.toString()]]
}
// Number
if (typeof object === 'number') {
return ['number', {}, [object.toString()]]
}
// String
if (typeof object === 'string') {
return ['string', {} , [object]]
}
// For all other types, return []
return []
}
return 0 < arguments.length
? consume(object)
: []
}
function microxml2dom(tree) {
function isMicroXML(tree) {
return Array.isArray(tree)
&& tree.length === 3
&& typeof tree[0] === 'string'
&& tree[1] instanceof Object
&& Array.isArray(tree[2])
}
function consume(element) {
element = element || ['div', {}, ['']]
var tagName = element[0]
var attributes = element[1]
var content = element[2]
var doc = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'xml', null)
var node = doc.createElement(tagName)
for (var attr in attributes) {
node.setAttribute(attr, attributes[attr])
}
populate(node, content)
return node
}
function populate(node, content) {
content = content || []
return content.forEach(function(child) {
return Array.isArray(child)
? node.appendChild(consume(child))
: node.textContent += child
})
}
return 0 < arguments.length && isMicroXML(tree)
? consume(tree)
: []
}
function dom2object(tree) {
function consume(node) {
var types = {
'null': function(node) { return null },
'number': function(node) { return Number(node.textContent) },
'boolean': function(node) {
return node.textContent === String(Boolean(node.textContent))
},
'string': function(node) { return String(node.textContent) },
'array': function(node) {
return Array.prototype.slice.call(node.children).map(function(tag) { return consume(tag) })
},
'key': function(node) { return String(node.textContent) },
'value': function(node) { return consume(node.children[0]) },
'property': function(node) {
return [node.children[0].textContent, consume(node.children[1])]
},
'object': function(node) {
var obj = {}
Array.prototype.slice.call(node.children).forEach(function(child) {
obj[child.children[0].textContent] = consume(child.children[1])
})
return obj
}
}
return types[node.tagName.toLowerCase()](node)
}
return 0 < arguments.length && tree.tagName
? consume(tree)
: []
}
function cssPath(object, path) {
object = object || []
path = path || '*'
var doc = microxml2dom(object2microxml(object))
return doc.tagName
? Array.prototype.slice.call(
doc.querySelectorAll(path)
).map(function(object) {
return dom2object(object)
})
: []
}
function esPath(object, path) {
object = object || []
path = path || '//*'
var doc = microxml2dom(object2microxml(object))
if (
arguments.length
&& doc.tagName
) {
var nodeArray = []
var xpath = document.evaluate(
path,
doc,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
)
for (var i=0; i < xpath.snapshotLength; i++) {
nodeArray.push(xpath.snapshotItem(i))
}
return nodeArray.map(function(object) { return dom2object(object) })
} else {
return []
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment