Last active
May 9, 2018 18:54
-
-
Save yesasha/3283a14f4a065aa2d3425b22f8cb8b41 to your computer and use it in GitHub Desktop.
Convert node to plain object and back. Development version.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (function (w, defaultNamespaceURI) { | |
| "use strict"; | |
| var namespaceURI = defaultNamespaceURI; | |
| function toObj (node) { | |
| if (node == null) { | |
| return null; | |
| } | |
| var obj = {}; | |
| var nodeType = determineNodeType(node); | |
| var tagName = node.tagName; | |
| var nodeName = node.nodeName; | |
| var nodeValue = node.nodeValue; | |
| switch (nodeType) { | |
| case Node.ELEMENT_NODE: | |
| if ('tagName' in node) { | |
| tagName = ('' + tagName).toLowerCase(); | |
| } else if ('nodeName' in node) { | |
| tagName = ('' + nodeName).toLowerCase(); | |
| } else { | |
| throw new TypeError('TagName or nodeName property is required.'); | |
| } | |
| // obj.nodeType = Node.ELEMENT_NODE; | |
| obj.tagName = tagName; | |
| // obj.nodeName = tagName; | |
| if ('namespaceURI' in node && node.namespaceURI !== defaultNamespaceURI) { | |
| obj.namespaceURI = node.namespaceURI; | |
| } | |
| var attributes = node.attributes || []; | |
| for (var i = 0; i < attributes.length; i++) { | |
| var attr = attributes[i]; | |
| if (attr) { | |
| if ('name' in attr && 'value' in attr) { | |
| obj.attributes || (obj.attributes = []); | |
| obj.attributes.push({name: attr.name, value: attr.value}); | |
| } else { | |
| throw new TypeError('Name and value are required in attribute.'); | |
| } | |
| } | |
| } | |
| break; | |
| case Node.TEXT_NODE: | |
| if (!('nodeValue' in node)) { | |
| throw new TypeError('NodeValue property is required.'); | |
| } | |
| // obj.nodeType = Node.TEXT_NODE; | |
| obj.nodeName = '#text'; | |
| obj.nodeValue = nodeValue; | |
| return obj; | |
| case Node.PROCESSING_INSTRUCTION_NODE: | |
| if (!('nodeName' in node) || !('nodeValue' in node)) { | |
| throw new TypeError('NodeName and nodeValue properties are required.'); | |
| } | |
| // obj.nodeType = Node.PROCESSING_INSTRUCTION_NODE; | |
| obj.nodeName = nodeName; | |
| obj.nodeValue = nodeValue; | |
| return obj; | |
| case Node.COMMENT_NODE: | |
| if (!('nodeValue' in node)) { | |
| throw new TypeError('NodeValue property is required.'); | |
| } | |
| // obj.nodeType = Node.COMMENT_NODE; | |
| obj.nodeName = '#comment'; | |
| obj.nodeValue = nodeValue; | |
| return obj; | |
| case Node.DOCUMENT_NODE: | |
| // obj.nodeType = Node.DOCUMENT_NODE; | |
| obj.nodeName = '#document'; | |
| break; | |
| case Node.DOCUMENT_FRAGMENT_NODE: | |
| // obj.nodeType = Node.DOCUMENT_FRAGMENT_NODE; | |
| obj.nodeName = '#document-fragment'; | |
| break; | |
| case Node.DOCUMENT_TYPE_NODE: | |
| // obj.nodeType = Node.DOCUMENT_TYPE_NODE; | |
| if ('name' in node) { | |
| obj.name = node.name; | |
| } else if ('nodeName' in node) { | |
| obj.name = nodeName; | |
| } else { | |
| throw new TypeError('Name or nodeName property is required.'); | |
| } | |
| var publicId = node.publicId; | |
| var systemId = node.systemId; | |
| if ('publicId' in node && publicId !== '') { | |
| obj.publicId = publicId; | |
| } | |
| if ('systemId' in node && systemId !== '') { | |
| obj.systemId = systemId; | |
| } | |
| return obj; | |
| default: | |
| return null; | |
| } | |
| var childNodes = node.childNodes || []; | |
| for (var i = 0; i < childNodes.length; i++) { | |
| var childNode = childNodes[i]; | |
| childNode = toObj(childNode); // May also throw | |
| if (childNode) { | |
| obj.childNodes || (obj.childNodes = []); | |
| obj.childNodes.push(childNode); | |
| } | |
| } | |
| return obj; | |
| } | |
| function toObjAll (node) { | |
| if (node == null) { | |
| return null; | |
| } | |
| var obj = {}; | |
| var nodeType = determineNodeType(node); | |
| var tagName = node.tagName; | |
| var nodeName = node.nodeName; | |
| var nodeValue = node.nodeValue; | |
| switch (nodeType) { | |
| case Node.ELEMENT_NODE: | |
| if ('tagName' in node) { | |
| tagName = ('' + tagName).toLowerCase(); | |
| } else if ('nodeName' in node) { | |
| tagName = ('' + nodeName).toLowerCase(); | |
| } else { | |
| throw new TypeError('TagName or nodeName property is required.'); | |
| } | |
| obj.nodeType = Node.ELEMENT_NODE; | |
| obj.tagName = tagName; | |
| obj.nodeName = tagName; | |
| if ('namespaceURI' in node && node.namespaceURI !== defaultNamespaceURI) { | |
| obj.namespaceURI = node.namespaceURI; | |
| } | |
| var attributes = node.attributes || []; | |
| for (var i = 0; i < attributes.length; i++) { | |
| var attr = attributes[i]; | |
| if (attr) { | |
| if ('name' in attr && 'value' in attr) { | |
| obj.attributes || (obj.attributes = []); | |
| obj.attributes.push({name: attr.name, value: attr.value}); | |
| } else { | |
| throw new TypeError('Name and value are required in attribute.'); | |
| } | |
| } | |
| } | |
| break; | |
| case Node.TEXT_NODE: | |
| if (!('nodeValue' in node)) { | |
| throw new TypeError('NodeValue property is required.'); | |
| } | |
| obj.nodeType = Node.TEXT_NODE; | |
| obj.nodeName = '#text'; | |
| obj.nodeValue = nodeValue; | |
| return obj; | |
| case Node.PROCESSING_INSTRUCTION_NODE: | |
| if (!('nodeName' in node) || !('nodeValue' in node)) { | |
| throw new TypeError('NodeName and nodeValue properties are required.'); | |
| } | |
| obj.nodeType = Node.PROCESSING_INSTRUCTION_NODE; | |
| obj.nodeName = nodeName; | |
| obj.nodeValue = nodeValue; | |
| return obj; | |
| case Node.COMMENT_NODE: | |
| if (!('nodeValue' in node)) { | |
| throw new TypeError('NodeValue property is required.'); | |
| } | |
| obj.nodeType = Node.COMMENT_NODE; | |
| obj.nodeName = '#comment'; | |
| obj.nodeValue = nodeValue; | |
| return obj; | |
| case Node.DOCUMENT_NODE: | |
| obj.nodeType = Node.DOCUMENT_NODE; | |
| obj.nodeName = '#document'; | |
| break; | |
| case Node.DOCUMENT_FRAGMENT_NODE: | |
| obj.nodeType = Node.DOCUMENT_FRAGMENT_NODE; | |
| obj.nodeName = '#document-fragment'; | |
| break; | |
| case Node.DOCUMENT_TYPE_NODE: | |
| obj.nodeType = Node.DOCUMENT_TYPE_NODE; | |
| if ('name' in node) { | |
| obj.name = node.name; | |
| } else if ('nodeName' in node) { | |
| obj.name = nodeName; | |
| } else { | |
| throw new TypeError('Name or nodeName property is required.'); | |
| } | |
| var publicId = node.publicId; | |
| var systemId = node.systemId; | |
| if ('publicId' in node && publicId !== '') { | |
| obj.publicId = publicId; | |
| } | |
| if ('systemId' in node && systemId !== '') { | |
| obj.systemId = systemId; | |
| } | |
| return obj; | |
| default: | |
| return null; | |
| } | |
| var childNodes = node.childNodes || []; | |
| for (var i = 0; i < childNodes.length; i++) { | |
| var childNode = childNodes[i]; | |
| childNode = toObjAll(childNode); // May also throw | |
| if (childNode) { | |
| obj.childNodes || (obj.childNodes = []); | |
| obj.childNodes.push(childNode); | |
| } | |
| } | |
| return obj; | |
| } | |
| function toDOM (obj) { | |
| if (obj == null) { | |
| return null; | |
| } | |
| var node; | |
| var name; | |
| var nodeType = determineNodeType(obj); | |
| var nodeName = obj.nodeName; | |
| var nodeValue = obj.nodeValue; | |
| var publicId; | |
| var systemId; | |
| switch (nodeType) { | |
| case Node.ELEMENT_NODE: | |
| if ('tagName' in obj) { | |
| nodeName = obj.tagName; | |
| } else if ('nodeName' in obj) { | |
| nodeName = obj.nodeName; | |
| } else { | |
| throw new TypeError('TagName or nodeName property is required to create an ELEMENT_NODE.'); | |
| } | |
| if ('namespaceURI' in obj) { | |
| namespaceURI = obj.namespaceURI; | |
| } else { | |
| namespaceURI = defaultNamespaceURI; | |
| } | |
| node = document.createElementNS(namespaceURI, nodeName); | |
| setAttributes(node, obj.attributes); | |
| break; | |
| case Node.TEXT_NODE: | |
| if ('nodeValue' in obj) { | |
| return document.createTextNode(nodeValue); | |
| } | |
| throw new TypeError('nodeValue property is required to create a TEXT_NODE.'); | |
| case Node.PROCESSING_INSTRUCTION_NODE: | |
| if ('nodeName' in obj && 'nodeValue' in obj) { | |
| return document.createProcessingInstruction(nodeName, nodeValue); | |
| } | |
| throw new TypeError('NodeName and nodeValue properties are required to create a PROCESSING_INSTRUCTION_NODE.'); | |
| case Node.COMMENT_NODE: | |
| if ('nodeValue' in obj) { | |
| return document.createComment(nodeValue); | |
| } | |
| throw new TypeError('NodeValue property is required to create a COMMENT_NODE.'); | |
| case Node.DOCUMENT_NODE: | |
| var doctype = null; | |
| var otherChildNodes = []; | |
| var documentElement; | |
| nodeName = null; | |
| // Find DOCUMENT_TYPE_NODE and ELEMENT_NODE | |
| var childNodes = obj.childNodes || []; | |
| for (var i = 0; i < childNodes.length; i++) { | |
| var childNode = childNodes[i]; | |
| nodeType = determineNodeType(childNode); | |
| if (nodeType === Node.DOCUMENT_TYPE_NODE) { | |
| doctype = toDOM(childNode); | |
| } else if (nodeType === Node.ELEMENT_NODE) { | |
| documentElement = childNode; | |
| if ('namespaceURI' in childNode) { | |
| namespaceURI = childNode.namespaceURI; | |
| } else { | |
| namespaceURI = defaultNamespaceURI; | |
| } | |
| if ('tagName' in childNode) { | |
| nodeName = childNode.tagName; | |
| } else if ('nodeName' in childNode) { | |
| nodeName = childNode.nodeName; | |
| } else { | |
| throw new TypeError('TagName or nodeName property is required in ELEMENT_NODE.'); | |
| } | |
| } else { | |
| otherChildNodes.push(childNode); | |
| } | |
| } | |
| node = document.implementation.createDocument(namespaceURI, nodeName, doctype); | |
| if (node.documentElement) { | |
| setAttributes(node.documentElement, documentElement.attributes); | |
| appendChildNodes(node.documentElement, documentElement.childNodes); | |
| } | |
| appendChildNodes(node, otherChildNodes); | |
| return node; | |
| case Node.DOCUMENT_TYPE_NODE: | |
| if ('name' in obj) { | |
| name = obj.name; | |
| } else if ('nodeName' in obj) { | |
| name = obj.nodeName; | |
| } else { | |
| throw new TypeError('Name or nodeName property is required to create a DOCUMENT_TYPE_NODE.'); | |
| } | |
| publicId = obj.publicId; | |
| systemId = obj.systemId; | |
| if (!('publicId' in obj)) { | |
| publicId = ''; | |
| } | |
| if (!('systemId' in obj)) { | |
| systemId = ''; | |
| } | |
| return document.implementation.createDocumentType(name, publicId, systemId); | |
| case Node.DOCUMENT_FRAGMENT_NODE: | |
| node = document.createDocumentFragment(); | |
| break; | |
| default: | |
| return null; | |
| } | |
| appendChildNodes(node, obj.childNodes); | |
| return node; | |
| } | |
| function toDOMPreserveNodes (obj) { | |
| if (obj == null) { | |
| return null; | |
| } | |
| var type = Object.prototype.toString.call(obj).slice(8, -1); | |
| if ( | |
| type.match(/HTML.+Element/) !== null || | |
| type === 'Text' || | |
| type === 'ProcessingInstruction' || | |
| type === 'Comment' || | |
| type === 'HTMLDocument' || | |
| type === 'DocumentType' || | |
| type === 'DocumentFragment' | |
| ) { | |
| return obj; | |
| } | |
| var node; | |
| var name; | |
| var nodeType = determineNodeType(obj); | |
| var nodeName = obj.nodeName; | |
| var nodeValue = obj.nodeValue; | |
| var publicId; | |
| var systemId; | |
| switch (nodeType) { | |
| case Node.ELEMENT_NODE: | |
| if ('tagName' in obj) { | |
| nodeName = obj.tagName; | |
| } else if ('nodeName' in obj) { | |
| nodeName = obj.nodeName; | |
| } else { | |
| throw new TypeError('TagName or nodeName property is required to create an ELEMENT_NODE.'); | |
| } | |
| if ('namespaceURI' in obj) { | |
| namespaceURI = obj.namespaceURI; | |
| } else { | |
| namespaceURI = defaultNamespaceURI; | |
| } | |
| node = document.createElementNS(namespaceURI, nodeName); | |
| setAttributes(node, obj.attributes); | |
| break; | |
| case Node.TEXT_NODE: | |
| if ('nodeValue' in obj) { | |
| return document.createTextNode(nodeValue); | |
| } | |
| throw new TypeError('nodeValue property is required to create a TEXT_NODE.'); | |
| case Node.PROCESSING_INSTRUCTION_NODE: | |
| if ('nodeName' in obj && 'nodeValue' in obj) { | |
| return document.createProcessingInstruction(nodeName, nodeValue); | |
| } | |
| throw new TypeError('NodeName and nodeValue properties are required to create a PROCESSING_INSTRUCTION_NODE.'); | |
| case Node.COMMENT_NODE: | |
| if ('nodeValue' in obj) { | |
| return document.createComment(nodeValue); | |
| } | |
| throw new TypeError('NodeValue property is required to create a COMMENT_NODE.'); | |
| case Node.DOCUMENT_NODE: | |
| var doctype = null; | |
| var otherChildNodes = []; | |
| var documentElement; | |
| nodeName = null; | |
| // Find DOCUMENT_TYPE_NODE and ELEMENT_NODE | |
| var childNodes = obj.childNodes || []; | |
| for (var i = 0; i < childNodes.length; i++) { | |
| var childNode = childNodes[i]; | |
| nodeType = determineNodeType(childNode); | |
| if (nodeType === Node.DOCUMENT_TYPE_NODE) { | |
| doctype = toDOMPreserveNodes(childNode); | |
| } else if (nodeType === Node.ELEMENT_NODE) { | |
| documentElement = childNode; | |
| if ('namespaceURI' in childNode) { | |
| namespaceURI = childNode.namespaceURI; | |
| } else { | |
| namespaceURI = defaultNamespaceURI; | |
| } | |
| if ('tagName' in childNode) { | |
| nodeName = childNode.tagName; | |
| } else if ('nodeName' in childNode) { | |
| nodeName = childNode.nodeName; | |
| } else { | |
| throw new TypeError('TagName or nodeName property is required in ELEMENT_NODE.'); | |
| } | |
| } else { | |
| otherChildNodes.push(childNode); | |
| } | |
| } | |
| node = document.implementation.createDocument(namespaceURI, nodeName, doctype); | |
| if (node.documentElement) { | |
| setAttributes(node.documentElement, documentElement.attributes); | |
| appendChildNodesPreserve(node.documentElement, documentElement.childNodes); | |
| } | |
| appendChildNodesPreserve(node, otherChildNodes); | |
| return node; | |
| case Node.DOCUMENT_TYPE_NODE: | |
| if ('name' in obj) { | |
| name = obj.name; | |
| } else if ('nodeName' in obj) { | |
| name = obj.nodeName; | |
| } else { | |
| throw new TypeError('Name or nodeName property is required to create a DOCUMENT_TYPE_NODE.'); | |
| } | |
| publicId = obj.publicId; | |
| systemId = obj.systemId; | |
| if (!('publicId' in obj)) { | |
| publicId = ''; | |
| } | |
| if (!('systemId' in obj)) { | |
| systemId = ''; | |
| } | |
| return document.implementation.createDocumentType(name, publicId, systemId); | |
| case Node.DOCUMENT_FRAGMENT_NODE: | |
| node = document.createDocumentFragment(); | |
| break; | |
| default: | |
| return null; | |
| } | |
| appendChildNodesPreserve(node, obj.childNodes); | |
| return node; | |
| } | |
| function setAttributes (dstElement, attributes) { | |
| attributes = attributes || []; | |
| for (var i = 0; i < attributes.length; i++) { | |
| var attr = attributes[i]; | |
| if ('name' in attr && 'value' in attr) { | |
| dstElement.setAttributeNS(namespaceURI, attr.name, attr.value); | |
| } else { | |
| throw new TypeError('Name and value are required in attribute.'); | |
| } | |
| } | |
| } | |
| function appendChildNodes (dstElement, childNodes) { | |
| childNodes = childNodes || []; | |
| for (var i = 0; i < childNodes.length; i++) { | |
| var childNode = toDOM(childNodes[i]); | |
| if (childNode) { | |
| dstElement.appendChild(childNode); | |
| } | |
| } | |
| } | |
| function appendChildNodesPreserve (dstElement, childNodes) { | |
| childNodes = childNodes || []; | |
| for (var i = 0; i < childNodes.length; i++) { | |
| var childNode = toDOMPreserveNodes(childNodes[i]); | |
| if (childNode) { | |
| dstElement.appendChild(childNode); | |
| } | |
| } | |
| } | |
| function determineNodeType (node) { | |
| if (node == null) { | |
| return node; | |
| } | |
| var nodeType; | |
| var nodeName = node.nodeName; | |
| if (('nodeType' in node)) { | |
| nodeType = +node.nodeType; | |
| } else if (nodeName == '#text') { | |
| nodeType = Node.TEXT_NODE; | |
| } else if (nodeName == '#comment') { | |
| nodeType = Node.COMMENT_NODE; | |
| } else if (nodeName == '#document') { | |
| nodeType = Node.DOCUMENT_NODE; | |
| } else if (nodeName == '#document-fragment') { | |
| nodeType = Node.DOCUMENT_FRAGMENT_NODE; | |
| } else if ('tagName' in node) { | |
| nodeType = Node.ELEMENT_NODE; | |
| } else if ('name' in node) { | |
| nodeType = Node.DOCUMENT_TYPE_NODE; | |
| } else if ('nodeName' in node && 'nodeValue' in node) { | |
| nodeType = Node.PROCESSING_INSTRUCTION_NODE; | |
| } else if ('nodeName' in node) { | |
| nodeType = Node.ELEMENT_NODE; | |
| } else if ('nodeValue' in node) { | |
| nodeType = Node.TEXT_NODE; // Sugar | |
| } else { | |
| throw new TypeError('Can not determine node type.'); | |
| } | |
| return nodeType; | |
| } | |
| w['toObj'] = toObj; | |
| w['toObjAll'] = toObjAll; | |
| w['toDOM'] = toDOM; | |
| w['toDOMPreserveNodes'] = toDOMPreserveNodes; | |
| })(window, document.documentElement.namespaceURI); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment