浏览器有个实用的功能,但是可能用的频率不高,就是书签/收藏的导入和导出,因为现在一般浏览器都有云同步功能,所以这个功能存在感不强。

浏览器书签是可以跨不同的浏览器导入的,所以意味着导出的文件肯定是有一个规范的,我简单搜了一下没有搜到,可能是各家约定俗成的规范,并没有一个正式的标准。

通用的数据交换格式有很多,比如xml、json、yaml,json应该是使用最广泛的,因为易于解析和存储,尺寸也不大,所以很适合浏览器书签的导出,但是,实际上现代浏览器导出的书签文件是html文件。原因不详,也没有搜到相关信息,我猜测原因可能是html文件相对于json来说,普通用户更为熟悉,其次,html文件可以直接使用浏览器打开,当然,json文件也可以使用浏览器打开,但是可能直接点击的时候默认是用文本编辑器打开的,另外它们在浏览器的呈现方式也不一样,html显示的是一个普通的带有一堆超链接的页面,就是一个有点丑的网页,而json打开有点类似源码,不太友好,因为一般用户导出书签就是为了在另一个浏览器导入,所以屏蔽细节并没有什么问题。

html和xml是类似的,所以解析和传输也很简单,接下来看一下实例:


基本结构如上,每个文件夹下都有个书签,导出的书签源码如下:




简单分析一下:

1.标签字母都是大写

2.DOCTYPE声明和普通HTML页面不同

3.使用DL和DT来组织书签,DL代表一个文件夹的内容列表,DT代表一个内容,可能是书签也可能是文件夹,文件夹的话会有一个H3标签来表示书签的名字,书签的话就是直接跟一个A标签,DL标签后都跟了一个小写的p标签,有部分标签没有闭合

4.H1标签之前的都和书签内容没有什么关系

5.文件夹名称H3标签和超链接A标签都有ADD_DATELAST_MODIFIED来保存时间信息,该属性不存在也不影响

6.文件夹名称H3标签的属性PERSONAL_TOOLBAR_FOLDER来表示该文件夹下的内容是否显示到浏览器的工具栏,否则会默认放到浏览器的其他文件夹里,但也不一定,有的浏览器会有自己的行为

7.网页的标题icon会转换为base64格式放到ICON属性上,这个属性不存在也不影响

html其实就是普通字符串,所以可以手动生成,常见于一些导航网站和网址收藏工具的导出功能,如五花八门导航(http://lxqnsys.com/d),有一个需要注意的地方,就是html字符串必须格式化带换行和缩进,下图这种压缩过的是不行的:


生成方式也很简单,书签是树结构,所以递归循环拼接即可。

先看一下书签数据的格式,忽略时间和icon:

let bookmarks = [    {        name: '',// 文件夹或书签名字        toolbar: true,// 是否显示到工具栏        folder: true,// 是否是文件夹        children: [            {                name: '',                folder: true,                children: []            },            {                name: '',// 书签名称                url: ''// 书签url            }        ]    }]

使用ES6的话可以直接使用模板字符串``来带换行的拼接,很方便:

function createBookmarksStr (bookmarks) {    let str = `                         HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">        Bookmarks        

Bookmarks ` let loop = (root) => { let str = '' root.forEach((item) => { if (item.folder) { str += `

${item.toolbar ? `PERSONAL_TOOLBAR_FOLDER="true"` : ''}>${item.name}

` str += loop(item.children) str += ` ` } else { str += ` HREF="${item.url}">${item.name} ` } }) return str } str += loop(bookmarks) str += ` ` return str}

ES6之前的就需要显式的拼接上换行符:

function createBookmarksStr (bookmarks) {    var str = '\n\n\nBookmarks\n

Bookmarks

\n\n\t

\n\t\t

\n\t\t\t

\u4E66\u7B7E\u680F

\n\t\t\t\n\t\t\t\t

\n\t\t\t\t\t'

var loop = function (root) { var str = '' root.forEach(function (item) { if (item.folder) { str += '\n\t\t\t\t\t\t

+ (item.toolbar ? 'PERSONAL_TOOLBAR_FOLDER="true"' : '') +'>'+item.name+'

\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t

\n\t\t\t\t\t\t\t\t'

str += loop(item.children) str += '\n\t\t\t\t\t\t

\n\t\t\t'

} else { str += '+item.url+'\">'+item.name+'\n\t\t\t\t\t\t\t\t' } }) return str } str += loop(bookmarks) str += '\n\t\t\t

\n\n

'

return str}

看完了如何生成,接下来看一下如何解析,解析和拼接类似,也是通过深度优先进行遍历,只是会有一些特征判断。字符串如何转化成一棵树,最简单的肯定是先转换为DOM元素,然后再通过操作DOM的api来进行遍历,有一些库可以用来做这件事,不过这里直接用的是iframe

function getBookmarksStrRootNode (str) {    // 创建iframe    let iframe = document.createElement('iframe')    document.body.appendChild(iframe)    iframe.style.display = 'none'    // 添加书签dom字符串    iframe.contentWindow.document.documentElement.innerHTML = str    // 获取书签树根节点    return iframe.contentWindow.document.querySelector('dl')}function analysisBookmarksStr(str) {    let root = getBookmarksStrRootNode(str)}

看一下转换的结果:

书签DOM字符串:


转换后的DOM节点:


获取到书签树的根节点,接下来递归遍历即可:

function walkBookmarksTree (root) {    let result = []    // 深度优先遍历    let walk = (node, list) => {        let els = node.children        if (els && els.length > 0) {            for (let i = 0; i < els.length; i++) {                let item = els[i]                // p标签或h3标签直接跳过                if (item.tagName === 'P' || item.tagName === 'H3') {                    continue                }                // 文件夹不用创建元素                if (item.tagName === 'DL') {                    walk(els[i], list)                } else {// DT节点                    let child = null                    // 判断是否是文件夹                    let children = item.children                    let isDir = false                    for(let j = 0; j < children.length; j++) {                        if (children[j].tagName === 'H3' || children[j].tagName === 'DL') {                            isDir = true                        }                    }                    // 文件夹                    if (isDir) {                        child = {                            name: item.tagName === 'DT' ? item.querySelector('h3') ? item.querySelector('h3').innerText : '' : '',                            folder: true,                            children: []                        }                        walk(els[i], child.children)                    } else {// 书签                        let _item = item.querySelector('a')                        child = {                            name: _item.innerText,                            url: _item.href                        }                    }                    list.push(child)                }            }        }    }    walk(root, result)    return result}function analysisBookmarksStr(str) {    let root = getBookmarksStrRootNode(str)    let result = walkBookmarksTree(root)}

最后解析的结果:


搞定收工,赶紧去试试吧。

xml显示浏览器标签_浅析浏览器书签的导入和导出相关推荐

  1. 火狐怎么导入收藏夹_火狐浏览器怎么导入及导出书签?导入及导出书签的方法说明...

    IE问题解决办法文章由小编整理发出,内容真实有效,欢迎提出您的意见IE系列文章由小编在互联网中整理并且发出,内容保障真实健康. 火狐浏览器是目前非常流行的网页浏览器,使用人数非常多,尤其是从事IT行业 ...

  2. java浏览器渲染_优化浏览器渲染

    优化浏览器渲染 资源被下载到客户端后,浏览器仍需加载,解释,并渲染HTML.CSS和Javascript代码.只需利用现有浏览器的特性简单地编排你的代码和页面,就可以提升客户端的性能. 使用高效率的C ...

  3. qq浏览器主页_安卓浏览器哪家强?这些小众好用的手机浏览器你知道吗

    前言 无论手机还是电脑,浏览器都可以说是最重要的软件之一了.最流行的 Chrome 和 Firefox,国内常见的还有 UC.QQ.360 浏览器等. 手机上可供选择的优秀浏览器还有很多,这次就推荐些 ...

  4. java判断浏览器类型_判断浏览器类型

    一.判断是否为IE 以前判断是否IE浏览器用的是window.navigator.userAgent,跟踪这个信息,发现在开发环境,识别为IE10,但访问服务器则识别为IE11,但IE11的userA ...

  5. origin图上显示数据标签_半分钟教程:果粉们用 Origin,这些问题一定要搞清。...

    科研人群中,像小编这样的果粉越来越多.同时,小编也是 Origin 的忠实用户.麻烦来了, Origin 官方至今一直没有推出 Mac 版 Origin.小编曾尝试寻找 Mac 下的 Origin 替 ...

  6. ssis导出数据性能_使用SSIS Hadoop组件导入和导出数据

    ssis导出数据性能 In the previously published article, we talked briefly about Hadoop, and we gave an overv ...

  7. 关闭浏览器网页触发事件_浅析浏览器渲染和 script 加载

    前言 前端代码离不开浏览器环境,理解 js.css 代码如何在浏览器中工作是非常重要的. 如何优化渲染过程中的回流,重绘?script 脚本在页面中是怎么个加载顺序?了解这些对前端性能优化起着非常大的 ...

  8. java返回字符串浏览器换行_解决浏览器显示页面长字符串换行问题总结

    问题产生 在web页面HTML中,容器(div,table等)中如果放入过长的字符串(英文.数字和部分标点符号组成,无空格),将会撑大容器,破坏页面外观. 出现这种情况基本有两个可能: 1. 人为的恶 ...

  9. 浏览器快捷键_用浏览器输入框代替Alfred - 介绍快速唤起浏览器输入框的方法,以及它能怎么取代 Alfred...

    在集智俱乐部注意力与知识管理群里最近讨论起了 Alfred,一位同志建议我使用它,他跟我分享了 alfred-github-workflow 说:「感觉作为入口,它做得很不错了.可以直接搜索我的收藏夹 ...

最新文章

  1. 蜗蜗 Linux内核芬妮下,Linux内核的整体架构
  2. 我用nagios-check_http check Checker
  3. MDK5.29,5.30,5.31,5.32,5.33和各种pack软件包镜像下载
  4. kdj买卖指标公式源码_翔博精选指标KDJ买卖点提示(通达信公式 副图 测试图)...
  5. ssldump编译及使用过程
  6. python ide: pycharm
  7. typedef的四个用途和两个陷阱
  8. ExtJs懒人笔记(2) ExtJs页面布局
  9. Spark DataFrame小试牛刀
  10. Evaluate the Malignancy of Pulmonary Nodules Using the 3D Deep Leaky Noisy-or Network 论文阅读
  11. 姜启源《数学模型》笔记
  12. 在谷歌云盘训练YOLOV5模型
  13. lavaral中文手册_Laravel5.3手册下载
  14. 【CSDN编程竞赛第六期】python详解
  15. 堡垒机Windows远程桌面连接服务器黑屏解决
  16. tp6+layui后台管理系统
  17. 视频号扩展链接一键转换
  18. vue 解决重复点击导航路由报错 问题
  19. 安装程序出现 NSIS ERROR的错误提示
  20. Matlab群体智能优化算法之鹈鹕优化算法(POA)

热门文章

  1. 供SAPI中TTS功能用使的Win8.1语言包安装
  2. 用Red5搭建支持WEB播放的实时监控视频
  3. java单例设计模式
  4. English trip V1 - 22. My Life Teacher:Emily Key: describe talk about past 过去式
  5. 【AT2434】JOI 公園 (JOI Park) 最短路+贪心
  6. Codeforces Hello 2018!C
  7. JAVA开发环境的搭建(配置JAVA开发环境)
  8. python模块(一)
  9. MySQL中show语法使用总结
  10. [PHP]Maximum execution time of 30 seconds exceeded