热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

bytejson互转_JSON和HTML之间互转实现

主要实现功能html转json,再由json恢复html可去除style和script标签将行内样式转换为jsobject将class转换为数组形式主要依赖于htmlparser2

主要实现功能html转json,再由json恢复html

可去除 style 和 script 标签

将行内样式转换为 js object

将 class 转换为数组形式

主要依赖于 htmlparser2 ; 这是一个性能优越、功能强大的 html 解析库

ff07d335f79d5e2dbcf5793ab49f633f.png

直接上代码

import { Parser } from "htmlparser2"

const numberValueRegexp = /^\d+$/

const zeroValueRegexp = /^0[^0\s].*$/

const scriptRegexp = /^script$/i

const styleRegexp = /^style$/i

const selfCloseTagRegexp = /^(meta|base|br|img|input|col|frame|link|area|param|embed|keygen|source)$/i

const TAG = 'tag'

const TEXT = 'text'

const COMMENT = 'comment'

/**

* 去除前后空格

*/

export const trim = val => {

return (val || '').replace(/^\s+/, '').replace(/\s+$/, '')

}

/**

* 首字母大写

*/

export const capitalize = word => {

return (word || '').replace(/( |^)[a-z]/, c => c.toUpperCase())

}

/**

* 驼峰命名法/小驼峰命名法, 首字母小写

*/

export const camelCase = key => {

return (key || '').split(/[_-]/).map((item, i) => i === 0 ? item : capitalize(item)).join('')

}

/**

* 大驼峰命名法,首字母大写

*/

export const pascalCase = key => {

return (key || '').split(/[_-]/).map(capitalize).join('')

}

export const isPlainObject = obj => {

return Object.prototype.toString.call(obj) === '[object Object]'

}

/**

* 行内样式转Object

*/

export const style2Object = (style) => {

if (!style || typeof style !== 'string') {

return {}

}

const styleObject = {}

const styles = style.split(/;/)

styles.forEach(item => {

const [prop, value] = item.split(/:/)

if (prop && value && trim(value)) {

const val = trim(value)

styleObject[camelCase(trim(prop))] = zeroValueRegexp.test(val) ? 0 : numberValueRegexp.test(val) ? Number(val) : val

}

})

return styleObject

}

export const toJSON = (html, options) => {

options = Object.assign({ skipStyle: false, skipScript: false, pureClass: false, pureComment: false }, options)

const json = []

let levelNodes = []

const parser = new Parser({

onopentag: (name, { style, class: classNames, ...attrs } = {}) => {

let node = {}

if ((scriptRegexp.test(name) && options.skipScript === true) ||

(styleRegexp.test(name) && options.skipStyle === true)) {

node = false

} else {

if (options.pureClass === true) {

classNames = ''

}

node = {

type: TAG,

tagName: name,

style: style2Object(style),

inlineStyle: style || '',

attrs: { ...attrs },

classNames: classNames || '',

classList: options.pureClass ? [] : (classNames || '').split(/\s+/).map(trim).filter(Boolean),

children: []

}

}

if (levelNodes[0]) {

if (node !== false) {

const parent = levelNodes[0]

parent.children.push(node)

}

levelNodes.unshift(node)

} else {

if (node !== false) {

json.push(node)

}

levelNodes.push(node)

}

},

ontext(text) {

const parent = levelNodes[0]

if (parent === false) {

return

}

const node = {

type: TEXT,

content: text

}

if (!parent) {

json.push(node)

} else {

if (!parent.children) {

parent.children = []

}

parent.children.push(node)

}

},

oncomment(comments) {

if (options.pureComment) {

return

}

const parent = levelNodes[0]

if (parent === false) {

return

}

const node = {

type: COMMENT,

content: comments

}

if (!parent) {

json.push(node)

} else {

if (!parent.children) {

parent.children = []

}

parent.children.push(node)

}

},

onclosetag() {

levelNodes.shift()

},

onend() {

levelNodes = null

}

})

parser.done(html)

return json

}

const setAttrs = (attrs, results) => {

Object.keys(attrs || {}).forEach(k => {

if (!attrs[k]) {

results.push(k)

} else {

results.push(' ', k, '=', '"', attrs[k], '"')

}

})

}

const toElement = (elementInfo, results) => {

switch (elementInfo.type) {

case TAG:

const tagName = elementInfo.tagName

results.push('

if (elementInfo.inlineStyle) {

results.push(' style="', elementInfo.inlineStyle, '"')

}

if (elementInfo.classNames) {

results.push(' class="', elementInfo.classNames, '"')

}

setAttrs(elementInfo.attrs, results)

if (selfCloseTagRegexp.test(tagName)) {

results.push(' />')

} else {

results.push('>')

if (Array.isArray(elementInfo.children)) {

elementInfo.children.forEach(item => toElement(item, results))

}

results.push('', tagName, '>')

}

break;

case TEXT:

results.push(elementInfo.content)

break;

case COMMENT:

results.push("")

break;

default:

// ignore

}

}

export const toHTML = json => {

json = json || []

if (isPlainObject(json)) {

json = [json]

}

const results = []

json.forEach(item => toElement(item, results))

return results.join('')

}

示例

const source = '

测试1
测试2
'

const htmljson = toJSON(source, { skipScript: true, skipStyle: true, pureClass: true, pureComment: true })

const jsonhtml = toHTML(htmljson)

console.log(htmljson)

console.log(jsonhtml)

参数说明

skipScript 过滤 script 标签,默认 false

skipStyle 过滤 style 标签,默认 false

pureClass 去掉 class 属性,默认 false

pureComment 去掉注释,默认 false

备注

htmlparser2 通过 npm i htmlparser2 --save 进行安装即可



推荐阅读
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • Python实现变声器功能(萝莉音御姐音)的方法及步骤
    本文介绍了使用Python实现变声器功能(萝莉音御姐音)的方法及步骤。首先登录百度AL开发平台,选择语音合成,创建应用并填写应用信息,获取Appid、API Key和Secret Key。然后安装pythonsdk,可以通过pip install baidu-aip或python setup.py install进行安装。最后,书写代码实现变声器功能,使用AipSpeech库进行语音合成,可以设置音量等参数。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 本文介绍了如何使用vue-awesome-swiper组件,包括在main.js中引入和使用swiper和swiperSlide组件,以及设置options和ref属性。同时还介绍了如何在模板中使用swiper和swiperSlide组件,并展示了如何通过循环渲染swipes数组中的数据,并使用picUrl属性显示图片。最后还介绍了如何添加分页器。 ... [详细]
  • 本文介绍了如何使用elementui分页组件进行分页功能的改写,只需一行代码即可调用。通过封装分页组件,避免在每个页面都写跳转请求的重复代码。详细的代码示例和使用方法在正文中给出。 ... [详细]
  • 先看看ElementUI里关于el-table的template数据结构:<template><el-table:datatableData><e ... [详细]
author-avatar
zhuzhuxiaozhuzhu
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有