Javascript 将HTML映射到JSON
我正在尝试将HTML映射为结构完整的JSON。有没有这样的库,或者我需要自己写?我想如果没有html2json库,我可以从xml2json库开始。毕竟,html只是xml的一种变体,对吗 更新:好的,我应该举个例子。我想做的是以下几点。解析html字符串:Javascript 将HTML映射到JSON,javascript,html,json,Javascript,Html,Json,我正在尝试将HTML映射为结构完整的JSON。有没有这样的库,或者我需要自己写?我想如果没有html2json库,我可以从xml2json库开始。毕竟,html只是xml的一种变体,对吗 更新:好的,我应该举个例子。我想做的是以下几点。解析html字符串: <div> <span>text</span>Text2 </div> 注意:如果您没有注意到标签,我正在寻找一个Javascript解决方案我在阅读ExtJS时得到了一些链接完整框架本身
<div>
<span>text</span>Text2
</div>
注意:如果您没有注意到标签,我正在寻找一个Javascript解决方案我在阅读ExtJS时得到了一些链接完整框架本身就是JSON 联机XML到JSON转换器: 更新 顺便说一句,要获得所添加的JSON,HTML中也需要像这样有类型和内容标记,或者在进行JSON转换时需要使用一些xslt转换来添加这些元素
<?xml version="1.0" encoding="UTF-8" ?>
<type>div</type>
<content>
<type>span</type>
<content>Text2</content>
</content>
<content>Text2</content>
div
跨度
文本2
文本2
我刚刚编写了这个函数,它可以满足您的需要;尝试一下,如果不适合您,请告诉我:
// Test with an element.
var initElement = document.getElementsByTagName("html")[0];
var json = mapDOM(initElement, true);
console.log(json);
// Test with a string.
initElement = "<div><span>text</span>Text2</div>";
json = mapDOM(initElement, true);
console.log(json);
function mapDOM(element, json) {
var treeObject = {};
// If string convert to document Node
if (typeof element === "string") {
if (window.DOMParser) {
parser = new DOMParser();
docNode = parser.parseFromString(element,"text/xml");
} else { // Microsoft strikes again
docNode = new ActiveXObject("Microsoft.XMLDOM");
docNode.async = false;
docNode.loadXML(element);
}
element = docNode.firstChild;
}
//Recursively loop through DOM elements and assign properties to object
function treeHTML(element, object) {
object["type"] = element.nodeName;
var nodeList = element.childNodes;
if (nodeList != null) {
if (nodeList.length) {
object["content"] = [];
for (var i = 0; i < nodeList.length; i++) {
if (nodeList[i].nodeType == 3) {
object["content"].push(nodeList[i].nodeValue);
} else {
object["content"].push({});
treeHTML(nodeList[i], object["content"][object["content"].length -1]);
}
}
}
}
if (element.attributes != null) {
if (element.attributes.length) {
object["attributes"] = {};
for (var i = 0; i < element.attributes.length; i++) {
object["attributes"][element.attributes[i].nodeName] = element.attributes[i].nodeValue;
}
}
}
}
treeHTML(element, treeObject);
return (json) ? JSON.stringify(treeObject) : treeObject;
}
//使用元素进行测试。
var initElement=document.getElementsByTagName(“html”)[0];
var json=mapDOM(initElement,true);
log(json);
//用字符串测试。
initElement=“text2”;
json=mapDOM(initElement,true);
log(json);
函数mapDOM(元素,json){
var treeObject={};
//如果字符串转换为文档节点
if(元素类型==“字符串”){
if(window.DOMParser){
parser=新的DOMParser();
docNode=parser.parseFromString(元素,“text/xml”);
}否则{//微软又罢工了
docNode=newActiveXObject(“Microsoft.XMLDOM”);
docNode.async=false;
loadXML(元素);
}
元素=docNode.firstChild;
}
//递归地循环DOM元素并为对象分配属性
函数树HTML(元素、对象){
对象[“类型”]=element.nodeName;
var nodeList=element.childNodes;
if(节点列表!=null){
if(节点列表长度){
对象[“内容”]=[];
对于(变量i=0;i
工作示例:(在Chrome中进行了测试,我不能保证完全支持浏览器-您必须对此进行测试)
它创建一个对象,该对象包含HTML页面的树结构,格式为您请求的格式,然后使用大多数现代浏览器(IE8+、Firefox 3+等)中包含的JSON.stringify()
;如果需要支持较旧的浏览器,可以包括
它可以使用DOM元素或包含有效XHTML的字符串作为参数(我相信,我不确定DOMParser()
在某些情况下是否会阻塞,因为它设置为“text/xml”
,或者它只是不提供错误处理。不幸的是“text/html”
的浏览器支持较差)
通过将不同的值传递为元素
,可以轻松更改此函数的范围。您传递的任何值都将是JSON映射的根。表示复杂的HTML文档将很困难,而且充满了各种各样的情况,但我只想与大家分享一些技巧,以展示如何启动此类程序。这个答案的不同之处在于它使用数据抽象和toJSON
方法递归地构建结果
下面,html2json
是一个很小的函数,它接受一个HTML节点作为输入,并返回一个JSON字符串作为结果。请特别注意代码是如何非常扁平的,但它仍然能够构建一个深度嵌套的树结构——所有这些几乎都是零复杂性的
//数据元素=元素节点
常数=e=>({
toJSON:()=>({
标记名:
e、 标记名,
文本内容:
e、 文本内容,
属性:
Array.from(e.attributes,({name,value})=>[name,value]),
儿童:
数组.from(e.children,Elem)
})
})
//html2json::节点->JSONString
常量html2json=e=>
stringify(Elem(e),null“”)
console.log(html2json(document.querySelector('main'))
一些标题
一些文本
谢谢你@Gorge Reith。利用@George Reith提供的解决方案,这里有一个函数可以进一步(1)分离单独的“HREF”链接(因为它们可能有用),(2)使用属性作为键(因为属性更具描述性),以及(3)通过使用“jsdom”包,它可以在Node.js中使用,而无需Chrome浏览器:
const jsdom = require('jsdom') // npm install jsdom provides in-built Window.js without needing Chrome
// Function to map HTML DOM attributes to inner text and hrefs
function mapDOM(html_string, json) {
treeObject = {}
// IMPT: use jsdom because of in-built Window.js
// DOMParser() does not provide client-side window for element access if coding in Nodejs
dom = new jsdom.JSDOM(html_string)
document = dom.window.document
element = document.firstChild
// Recursively loop through DOM elements and assign attributes to inner text object
// Why attributes instead of elements? 1. attributes more descriptive, 2. usually important and lesser
function treeHTML(element, object) {
var nodeList = element.childNodes;
if (nodeList != null) {
if (nodeList.length) {
object[element.nodeName] = [] // IMPT: empty [] array for non-text recursivable elements (see below)
for (var i = 0; i < nodeList.length; i++) {
// if final text
if (nodeList[i].nodeType == 3) {
if (element.attributes != null) {
for (var j = 0; j < element.attributes.length; j++) {
if (element.attributes[j].nodeValue !== '' &&
nodeList[i].nodeValue !== '') {
if (element.attributes[j].name === 'href') { // separate href
object[element.attributes[j].name] = element.attributes[j].nodeValue;
} else {
object[element.attributes[j].nodeValue] = nodeList[i].nodeValue;
}
}
}
}
// else if non-text then recurse on recursivable elements
} else {
object[element.nodeName].push({}); // if non-text push {} into empty [] array
treeHTML(nodeList[i], object[element.nodeName][object[element.nodeName].length -1]);
}
}
}
}
}
treeHTML(element, treeObject);
return (json) ? JSON.stringify(treeObject) : treeObject;
}
const jsdom=require('jsdom')//npm install jsdom提供内置Window.js而不需要Chrome
//函数将HTML DOM属性映射到内部文本和HREF
函数mapDOM(html_字符串,json){
treeObject={}
//IMPT:使用jsdom是因为内置了Window.js
//如果在Nodejs中编码,DOMParser()不提供元素访问的客户端窗口
dom=new jsdom.jsdom(html_字符串)
document=dom.window.document
元素=document.firstChild
const jsdom = require('jsdom') // npm install jsdom provides in-built Window.js without needing Chrome
// Function to map HTML DOM attributes to inner text and hrefs
function mapDOM(html_string, json) {
treeObject = {}
// IMPT: use jsdom because of in-built Window.js
// DOMParser() does not provide client-side window for element access if coding in Nodejs
dom = new jsdom.JSDOM(html_string)
document = dom.window.document
element = document.firstChild
// Recursively loop through DOM elements and assign attributes to inner text object
// Why attributes instead of elements? 1. attributes more descriptive, 2. usually important and lesser
function treeHTML(element, object) {
var nodeList = element.childNodes;
if (nodeList != null) {
if (nodeList.length) {
object[element.nodeName] = [] // IMPT: empty [] array for non-text recursivable elements (see below)
for (var i = 0; i < nodeList.length; i++) {
// if final text
if (nodeList[i].nodeType == 3) {
if (element.attributes != null) {
for (var j = 0; j < element.attributes.length; j++) {
if (element.attributes[j].nodeValue !== '' &&
nodeList[i].nodeValue !== '') {
if (element.attributes[j].name === 'href') { // separate href
object[element.attributes[j].name] = element.attributes[j].nodeValue;
} else {
object[element.attributes[j].nodeValue] = nodeList[i].nodeValue;
}
}
}
}
// else if non-text then recurse on recursivable elements
} else {
object[element.nodeName].push({}); // if non-text push {} into empty [] array
treeHTML(nodeList[i], object[element.nodeName][object[element.nodeName].length -1]);
}
}
}
}
}
treeHTML(element, treeObject);
return (json) ? JSON.stringify(treeObject) : treeObject;
}
[
'div',
{},
['span', {}, 'text'],
'Text2'
]
let element = document.createElement('div')
element.innerHtml = htmlString
/**
* A NodeDescriptor stands for either an (HTML) Element, or for a text node
*/
export type NodeDescriptor = ElementDescriptor | string
/**
* Array representing an HTML Element. It consists of:
*
* - The (tag) name of the element
* - An object, mapping attribute keys to attribute values
* - The (inlined) list of children nodes
*/
export type ElementDescriptor = [
string,
Record<string, string>,
...NodeDescriptor[]
]
export let htmlToJs = (element: Element, trim = true): ElementDescriptor => {
let convertElement = (element: Element): ElementDescriptor => {
let attributeObject: Record<string, string> = {}
for (let { name, value } of element.attributes) {
attributeObject[name] = value
}
let childArray: NodeDescriptor[] = []
for (let node of element.childNodes) {
let converter = htmlToJsDispatch[node.nodeType]
if (converter) {
let descriptor = converter(node as any)
let skip = false
if (trim && typeof descriptor === 'string') {
descriptor = descriptor.trim()
if (descriptor === '') skip = true
}
if (!skip) childArray.push(descriptor)
}
}
return [element.tagName.toLowerCase(), attributeObject, ...childArray]
}
let htmlToJsDispatch = {
[element.ELEMENT_NODE]: convertElement,
[element.TEXT_NODE]: (node: Text): string => node.data,
}
return convertElement(element)
}