基于ast思维的html字符串编辑

广告位招租
扫码页面底部二维码联系

在一个项目中,我需要获取当前页面的htm【原创不易,请尊重版权】本文版权归作者所有,未经授权不得转载。l字符串,然后发送到worker中,对h【本文首发于唐霜的博客】【未经授权禁止转载】tml进行编辑、对比等。和在DOM环境下【访问 www.tangshuang.net 获取更多精彩内容】【作者:唐霜】可以方便的编辑DOM不同,如果只有字符串【本文首发于唐霜的博客】【版权所有,侵权必究】,想要编辑,而且还要对两个html进行d著作权归作者所有,禁止商业用途转载。【本文受版权保护】iff操作,其实还是有点难度。在virt【原创不易,请尊重版权】【原创内容,转载请注明出处】ual dom中,我们可以通过node的原创内容,盗版必究。【本文首发于唐霜的博客】type来知道这个节点是否是同一个,但是著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。如果只有纯字符串,这个确认动作就会比较麻【原创不易,请尊重版权】【转载请注明来源】烦。我想,我已经对ast有一定了解了,能【访问 www.tangshuang.net 获取更多精彩内容】【未经授权禁止转载】不能把html抽象为ast,然后对ast【转载请注明来源】【原创不易,请尊重版权】对象进行编辑,再由ast还原为html呢本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。?于是,我开动脑筋,写了一个叫做abs-【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】html的库,用于对html转化为基于H【版权所有,侵权必究】【版权所有,侵权必究】yperJSON的ast对象,并且提供了原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】两个对象的diff和patch方法,以及【本文受版权保护】【转载请注明来源】重新生成html字符串的rebuild方著作权归作者所有,禁止商业用途转载。本文版权归作者所有,未经授权不得转载。法。

本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。【版权所有,侵权必究】【本文受版权保护】原创内容,盗版必究。

生成HTML的AST原创内容,盗版必究。

【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net【版权所有,侵权必究】【版权所有,侵权必究】

【版权所有】唐霜 www.tangshuang.netRobust第25期本文版权归作者所有,未经授权不得转载。中,我详细阐述了简单的编译原理,基于这一【原创不易,请尊重版权】本文作者:唐霜,转载请注明出处。原理,我可以将html字符串转化为一个t【原创不易,请尊重版权】【作者:唐霜】oken序列,并拼成一个ast。由于我并著作权归作者所有,禁止商业用途转载。原创内容,盗版必究。不需要一个完整的编译逻辑,我的目标是一个【原创内容,转载请注明出处】【版权所有】唐霜 www.tangshuang.net编译的子集。而且html是xml的子集,【本文受版权保护】【关注微信公众号:wwwtangshuangnet】天然具有非常强的数据结构特征,因此,遍历【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net过程中可以很快生成ast,不需要分多步。

【未经授权禁止转载】【转载请注明来源】原创内容,盗版必究。本文作者:唐霜,转载请注明出处。著作权归作者所有,禁止商业用途转载。

今年年初我发布了【版权所有】唐霜 www.tangshuang.netHyperJSON协议【版权所有,侵权必究】,它是一个基于hyperscript衍生未经授权,禁止复制转载。【转载请注明来源】的布局描述协议,具有极小的体积,和完备的【本文受版权保护】【访问 www.tangshuang.net 获取更多精彩内容】布局特性描述数据。而用HyperJSON本文版权归作者所有,未经授权不得转载。【作者:唐霜】来描述html具有非常大的优势:体积可以著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】变的特别小,阅读也很方便。因此,我生成的本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。ast是一个基于该协议的对象。

【原创不易,请尊重版权】原创内容,盗版必究。【转载请注明来源】

你可以通过下面的代码快速尝试一下这个效果本文作者:唐霜,转载请注明出处。未经授权,禁止复制转载。

著作权归作者所有,禁止商业用途转载。【原创内容,转载请注明出处】【未经授权禁止转载】【原创不易,请尊重版权】转载请注明出处:www.tangshuang.net
<script type="module">
  import { parseHTMLToHyperJSON } from 'https://unpkg.com/abs-html/src/index.js'
  const json = parseHTMLToHyperJSON(`
    <!DOCTYPE html>
    <main>
      <article>
        <h1>Title</h1>
        <p>content</p>
      </article>
    </main>
  `)
  console.log(json)
</script>

得到的对象会是一个阅读起来非常容易的对象【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net。你甚至可以在不同线程,或者客户端与服务【版权所有】唐霜 www.tangshuang.net本文作者:唐霜,转载请注明出处。端之间,随意的传输这个对象(当然,不推荐【版权所有】唐霜 www.tangshuang.net未经授权,禁止复制转载。,因为字符串性能会更好)。

转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】原创内容,盗版必究。【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】

原本我还想封装几个查询方法,但是由于考虑本文版权归作者所有,未经授权不得转载。本文作者:唐霜,转载请注明出处。到暂时没有这个需求,所以就没有开放查找方【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net法。你可以通过HyperJSON协议,方【本文受版权保护】【原创不易,请尊重版权】便的通过路径找到一个节点对象。接下来,你未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。可以随意编辑这个对象,但是需要注意,编辑【关注微信公众号:wwwtangshuangnet】著作权归作者所有,禁止商业用途转载。后,它仍然需要符合HyperJSON协议本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.net的要求。

【未经授权禁止转载】【原创内容,转载请注明出处】本文作者:唐霜,转载请注明出处。

从AST回到HTML转载请注明出处:www.tangshuang.net

【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.net

利用HyperJSON协议对象,我们可以本文作者:唐霜,转载请注明出处。原创内容,盗版必究。非常方便的通过遍历生成新的HTML字符串【本文首发于唐霜的博客】原创内容,盗版必究。

转载请注明出处:www.tangshuang.net转载请注明出处:www.tangshuang.net【本文受版权保护】本文作者:唐霜,转载请注明出处。
import { rebuildHyperJSONToHTML } from 'abs-html'
const html = rebuildHyperJSONToHTML(json)

不过在这里还是有一些坑的,主要是html转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。中有一些强制的自关闭标签,比如<l【作者:唐霜】本文作者:唐霜,转载请注明出处。ink /> <img /&本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.netgt;等。这些标签在HyperJSON中本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net没有特意强调,但是我规定,当一个节点没有未经授权,禁止复制转载。转载请注明出处:www.tangshuang.netchildren部分时,就代表它是一个自【版权所有,侵权必究】【本文首发于唐霜的博客】关闭标签。例如:

【本文受版权保护】本文版权归作者所有,未经授权不得转载。【本文首发于唐霜的博客】
['div', null, ''] // 闭合标签,一定存在children,虽然是一个空字符串
['img'] // 自关闭标签,不存在children,可以存在props

还有一点,为了小HyperJSON的体积【作者:唐霜】本文作者:唐霜,转载请注明出处。,纯文本节点直接用字符串,而非用#tex未经授权,禁止复制转载。转载请注明出处:www.tangshuang.nett类型节点,例如:

【原创不易,请尊重版权】原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。本文作者:唐霜,转载请注明出处。
['div', 0, 'content'] // 本来应该写成 ['div', null, ['#text', null, 'content']]

我们每一个设计,都有它独特的地方,有些设【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。计是为了追求完备性,而有些设计则是在理想著作权归作者所有,禁止商业用途转载。【访问 www.tangshuang.net 获取更多精彩内容】与现实之间平衡。

【访问 www.tangshuang.net 获取更多精彩内容】【本文受版权保护】原创内容,盗版必究。【原创不易,请尊重版权】【未经授权禁止转载】

Diff两个AST【本文受版权保护】

原创内容,盗版必究。未经授权,禁止复制转载。本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。

当我拿到两个html字符串之后,通过pa【关注微信公众号:wwwtangshuangnet】【关注微信公众号:wwwtangshuangnet】rse操作得到两个ast,接下来的事,就本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。是对比这两个纯js对象。市面上有很多di转载请注明出处:www.tangshuang.net未经授权,禁止复制转载。ff库,其中我比较喜欢的一个叫deep-【本文受版权保护】【版权所有】唐霜 www.tangshuang.netdiff,原因在于它的diff结果是非常【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net易于阅读的数组形式。但是,我并没有用它来未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。diff两个ast,原因很简单,html原创内容,盗版必究。未经授权,禁止复制转载。的ast是有规律的结构化数据,而非无规律【版权所有】唐霜 www.tangshuang.net【本文首发于唐霜的博客】的js对象。把ast当作纯对象对比,会多本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。出很多无用的信息,例如:

未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。【本文受版权保护】本文版权归作者所有,未经授权不得转载。
path: [3, 4, 1, 'name']
next: 'new name'

实际上它表达的是根节点的第1个child【关注微信公众号:wwwtangshuangnet】【原创内容,转载请注明出处】的第2个child的name prop发著作权归作者所有,禁止商业用途转载。转载请注明出处:www.tangshuang.net生变化。虽然用数字作为路径确实节省了一些【原创不易,请尊重版权】未经授权,禁止复制转载。空间,但是却无法让我们很轻松的阅读,所以未经授权,禁止复制转载。著作权归作者所有,禁止商业用途转载。,我自己提供了一个diff工具,这个di著作权归作者所有,禁止商业用途转载。著作权归作者所有,禁止商业用途转载。ff工具给出的结果是:

【未经授权禁止转载】【本文首发于唐霜的博客】【未经授权禁止转载】
path: div[1]/div[2]
type: 'attribute'
name: 'name'
next: 'new name'

它比用deep-diff对纯js对象对比【本文首发于唐霜的博客】原创内容,盗版必究。时多出一些信息,但是阅读起来却更方便。最转载请注明出处:www.tangshuang.net著作权归作者所有,禁止商业用途转载。重要的是,它为patch做准备,因为pa【作者:唐霜】转载请注明出处:www.tangshuang.nettch时,直接根据type来决定进行什么本文作者:唐霜,转载请注明出处。【作者:唐霜】操作。

【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.net著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】

相似算法【原创内容,转载请注明出处】

【未经授权禁止转载】【原创不易,请尊重版权】【关注微信公众号:wwwtangshuangnet】原创内容,盗版必究。【作者:唐霜】

在diff时,我需要确认,这个节点是新增【未经授权禁止转载】【版权所有】唐霜 www.tangshuang.net的,还是原来就有的(可能发生了一些细微变【关注微信公众号:wwwtangshuangnet】【版权所有,侵权必究】化)。我想到了一种相似算法(目前还没有在本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】abs-html中使用)。两个对象是否是【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net对同一个HTML节点的描述呢?我主要看它【转载请注明来源】原创内容,盗版必究。们的相似的,有些特征可以直接排除它们不是【原创不易,请尊重版权】【版权所有,侵权必究】同一个节点的描述,比如nodeName、【作者:唐霜】【本文首发于唐霜的博客】id、data-id不一样,那么这两个对【版权所有】唐霜 www.tangshuang.net【本文受版权保护】象不可能是对同一个节点的描述。我为不同节【本文受版权保护】【关注微信公众号:wwwtangshuangnet】点的相似度进行权重分类和分数划分,以节点【原创不易,请尊重版权】转载请注明出处:www.tangshuang.net的属性、属性值的相似度、children原创内容,盗版必究。【转载请注明来源】的相似度为维度,在每个维度上进行打分,每未经授权,禁止复制转载。【原创内容,转载请注明出处】个维度的权重不同,例如前面的nodeNa本文版权归作者所有,未经授权不得转载。【作者:唐霜】me,因为它具有巨高的权重,所以直接作为【本文首发于唐霜的博客】【作者:唐霜】特殊情况处理。当两个对象在nodeNam【原创内容,转载请注明出处】【未经授权禁止转载】e或id等一致的情况下,拥有相同的pro本文版权归作者所有,未经授权不得转载。【版权所有】唐霜 www.tangshuang.netps时,我认为它们具有较高的相似度,在p【原创不易,请尊重版权】【原创不易,请尊重版权】rops这个维度上,给出了高分,但是它们本文版权归作者所有,未经授权不得转载。【作者:唐霜】的children完全不同,那么在这个维【版权所有,侵权必究】【作者:唐霜】度上,我给出了0分。但是不同维度的权重是【作者:唐霜】【访问 www.tangshuang.net 获取更多精彩内容】不一样的,children不同,很有可能未经授权,禁止复制转载。【本文首发于唐霜的博客】是同一个DOM节点,更换了childre本文版权归作者所有,未经授权不得转载。【原创内容,转载请注明出处】n而已,因此,它的权重低很多。完成这个打本文版权归作者所有,未经授权不得转载。未经授权,禁止复制转载。分之后,我们就可以得出,一个对象描述的最未经授权,禁止复制转载。【作者:唐霜】有可能是哪一个对象描述的节点,从而在di本文作者:唐霜,转载请注明出处。【原创不易,请尊重版权】ff的时候,把它们当作一个节点,并给予相本文作者:唐霜,转载请注明出处。本文作者:唐霜,转载请注明出处。同的identifier,这样,它就不会【原创不易,请尊重版权】【版权所有】唐霜 www.tangshuang.net被移除,而只会被移动和更新。

【转载请注明来源】转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net

另外,在遍历时,我发现从尾往头遍历真的是著作权归作者所有,禁止商业用途转载。【转载请注明来源】一个很不错的方法,特别是在这种有移动或插未经授权,禁止复制转载。【原创内容,转载请注明出处】入的场景下,从末尾开始遍历可以有效的避免本文作者:唐霜,转载请注明出处。【访问 www.tangshuang.net 获取更多精彩内容】遍历过程中再去查找的逻辑,复杂度从O(n2【本文首发于唐霜的博客】)~O(n【未经授权禁止转载】3【本文受版权保护】)降到了O(n)。本文版权归作者所有,未经授权不得转载。

转载请注明出处:www.tangshuang.net【本文首发于唐霜的博客】【访问 www.tangshuang.net 获取更多精彩内容】本文版权归作者所有,未经授权不得转载。

Path变化【转载请注明来源】

本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】【原创不易,请尊重版权】

把diff结果存起来之后,形成了一个关于【转载请注明来源】著作权归作者所有,禁止商业用途转载。HTML变化的序列。我提供的patchH原创内容,盗版必究。【访问 www.tangshuang.net 获取更多精彩内容】yerJSON方法基于这一序列,可以重建【作者:唐霜】未经授权,禁止复制转载。HTML字符串。这样就可以做到对html【未经授权禁止转载】【访问 www.tangshuang.net 获取更多精彩内容】的回放。因为保存的是比较小的diff的结【本文首发于唐霜的博客】【版权所有】唐霜 www.tangshuang.net果,所以,占用的存储空间比保存html字【未经授权禁止转载】原创内容,盗版必究。符串小很多。

转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。【本文首发于唐霜的博客】转载请注明出处:www.tangshuang.net【转载请注明来源】

纯计算本文版权归作者所有,未经授权不得转载。

【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。【版权所有,侵权必究】

这一系列的计算都是纯js计算,因此,它可未经授权,禁止复制转载。【本文首发于唐霜的博客】以在worker中运行,我们将当前DOM【未经授权禁止转载】原创内容,盗版必究。的outerHTML发送到worker中著作权归作者所有,禁止商业用途转载。【关注微信公众号:wwwtangshuangnet】,由worker中的程序完成parse和【访问 www.tangshuang.net 获取更多精彩内容】转载请注明出处:www.tangshuang.netdiff,再将diff结果发送到服务器保【关注微信公众号:wwwtangshuangnet】本文版权归作者所有,未经授权不得转载。存。在服务器的另外一端,我们读取这些di【本文受版权保护】【原创不易,请尊重版权】ff结果,并通过其他程序,还原html的未经授权,禁止复制转载。【原创内容,转载请注明出处】变化,从而可以观看当前数据源一端的情况,【关注微信公众号:wwwtangshuangnet】【版权所有】唐霜 www.tangshuang.net这可以用在在线教育场景下,授课老师在基于本文版权归作者所有,未经授权不得转载。【关注微信公众号:wwwtangshuangnet】html的编辑器(如codemirror【原创内容,转载请注明出处】转载请注明出处:www.tangshuang.net)中撰写代码,学生可以立即在自己的电脑上【关注微信公众号:wwwtangshuangnet】本文作者:唐霜,转载请注明出处。看到老师的写作过程,并且在条件允许的情况转载请注明出处:www.tangshuang.net本文作者:唐霜,转载请注明出处。下,我们可以加入协同能力,让学生参与到写未经授权,禁止复制转载。本文作者:唐霜,转载请注明出处。作中。而由于这些计算全都在worker中【作者:唐霜】未经授权,禁止复制转载。执行,只要机器性能良好,就不会对用户当前本文版权归作者所有,未经授权不得转载。【访问 www.tangshuang.net 获取更多精彩内容】操作的页面产生任何性能上的影响。

【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。原创内容,盗版必究。【关注微信公众号:wwwtangshuangnet】

结语【未经授权禁止转载】

【未经授权禁止转载】【转载请注明来源】【版权所有,侵权必究】转载请注明出处:www.tangshuang.net【版权所有】唐霜 www.tangshuang.net

有了abs-html这个利器之后,我可以本文版权归作者所有,未经授权不得转载。转载请注明出处:www.tangshuang.net做很多事情,之前想到react-work原创内容,盗版必究。著作权归作者所有,禁止商业用途转载。er-dom这个库,我也可以实现了,我可【版权所有】唐霜 www.tangshuang.net【作者:唐霜】以在worker中使用react-rec【访问 www.tangshuang.net 获取更多精彩内容】【版权所有】唐霜 www.tangshuang.netonciler创建ast,并把diff结【关注微信公众号:wwwtangshuangnet】【关注微信公众号:wwwtangshuangnet】果发送给主线程,再利用主线程的patch【版权所有】唐霜 www.tangshuang.net本文版权归作者所有,未经授权不得转载。程序去更新对应的DOM,就可以做到一种新原创内容,盗版必究。【本文受版权保护】的类似小程序一样的架构。

本文作者:唐霜,转载请注明出处。转载请注明出处:www.tangshuang.net【未经授权禁止转载】【原创内容,转载请注明出处】

2021-06-12 3108

为价值买单,打赏一杯咖啡

本文价值31.08RMB