如何在JavaScript或jQuery中规范化HTML?

85

标签可以有多个属性。属性在代码中出现的顺序并不重要。例如:

<a href="#" title="#">
<a title="#" href="#">
如何在JavaScript中“标准化”HTML,使得属性的顺序总是相同?我不关心选择哪种顺序,只要始终如一即可。
更新:我的初始目标是使JavaScript更容易地对比两个具有轻微差异的HTML页面。因为用户可能使用不同的软件编辑代码,所以属性的顺序可能会改变。这会使差异过于冗长。
答案:首先感谢所有回答。是的,这是可能的。以下是我如何完成它的方式。这是一个概念验证,肯定可以进行优化:
function sort_attributes(a, b) {
  if( a.name == b.name) {
    return 0;
  }

  return (a.name < b.name) ? -1 : 1;
}

$("#original").find('*').each(function() {
  if (this.attributes.length > 1) {
    var attributes = this.attributes;
    var list = [];

    for(var i =0; i < attributes.length; i++) {
      list.push(attributes[i]);
    }

    list.sort(sort_attributes);

    for(var i = 0; i < list.length; i++) {
      this.removeAttribute(list[i].name, list[i].value);
    }

    for(var i = 0; i < list.length; i++) {
      this.setAttribute(list[i].name, list[i].value);
    }
  }
});

对于差异的第二个元素$('#different')同样适用。现在,$('#original').html()$('#different').html()以相同顺序显示带有属性的HTML代码。


59
需要这个的原因是什么? - rahul
40
实际上,这个需求非常有趣:它可以大大提高你的网页gzip压缩率。 - haylem
11
啊,在JavaScript中... 压缩这么多也没用,不知道还有什么必要。 - haylem
13
当 JavaScript 代码运行时,页面已经被发送到客户端。我不认为它能帮助进行压缩。 - casablanca
22
实际上,尝试做 OP 所要求的事情是有合理用途的。 使用所见即所得编辑器来驱动维基百科。 我正在开展的项目正是如此,而每次编辑维基时,编辑器会颠倒属性的顺序,导致不必要的差异。 我最终在后端按字母顺序对提交的 HTML 中的属性进行排序以避免差异;同样也可以在提交之前使用 JavaScript 进行排序。 - Frank Farmer
显示剩余15条评论
8个回答

68

JavaScript实际上并不将网页视为基于文本的HTML形式,而是将其视为称为DOM(Document Object Model)的树结构。 HTML元素属性在DOM中的顺序未定义(事实上,正如Svend所指出的那样,它们甚至不是DOM的一部分),因此在JavaScript运行时对它们进行排序的想法是无关紧要的。

我只能猜测你试图实现什么目标。如果你正在尝试这样做以改善JavaScript/页面性能,那么大多数HTML文档渲染器已经做了很多工作来优化属性访问,因此在这方面几乎没有什么可获得的。

如果你试图对属性进行排序以使页面在发送到网络时更有效地进行gzip压缩,请注意JavaScript是在此之后运行的。相反,你可能需要寻找运行在服务器端的东西,但这可能会带来更多的麻烦而得不偿失。


8
JavaScript 可以在服务器端运行。 - Matt Kantor
属性不被视为文档树的一部分(文档树自然使用排序)。因此,虽然Attr继承了Node接口,但DOM Core 2将这些字段指定为属性的null值。http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-637646024 - Svend

35

将HTML解析为DOM结构,然后将DOM结构写回HTML。在写入时,使用任何稳定排序对属性进行排序。现在,就属性而言,您的HTML已归一化。

这是一种通用的归一化方法。(解析非规范化数据,然后以规范化形式将其写回)。

我不确定为什么要规范化HTML,但就是这样。数据就是数据。;-)


1
你有代码示例吗?我尝试过类似的事情,但没有成功。 - Julien

12

这是一个概念验证,它肯定可以进行优化:

function sort_attributes(a, b) {
  if( a.name == b.name) {
    return 0;
  }

  return (a.name < b.name) ? -1 : 1;
 }

$("#original").find('*').each(function() {
  if (this.attributes.length > 1) {
    var attributes = this.attributes;
    var list = [];

    for(var i =0; i < attributes.length; i++) {
      list.push(attributes[i]);
    }

     list.sort(sort_attributes);

    for(var i = 0; i < list.length; i++) {
      this.removeAttribute(list[i].name, list[i].value);
    }

     for(var i = 0; i < list.length; i++) {
       this.setAttribute(list[i].name, list[i].value);
    }
  }
 });

对于差异的第二个元素$('#different'),情况也是类似的。现在,$('#original').html()和$('#different').html()中显示的HTML代码具有相同顺序的属性。


我认为如果您使用XML生成HTML内容,然后使用XSLT进行呈现,一定会得到更好的输出。 - Nasaralla

8

你可以在Firebug中尝试打开HTML选项卡,属性始终以相同的顺序显示。


4
这个本身并没有太大用处。这是因为它是从DOM重新创建HTML,而无论如何这都有一个特定的属性迭代顺序(或者Firebug手动排序)。Julien可以利用这一点,并使用同样的方法编写HTML。 - Matt Kantor

5

实际上,我可以想到几个很好的原因。其中一个是用于身份匹配比较以及与“diff”类型工具一起使用时,语义上等效的行可能会被标记为“不同”,这非常令人恼火。

真正的问题是,“为什么要在Javascript中”?

这个问题听起来像是“我有一个问题,我认为我有一个答案...但是我的答案也有问题。”

如果OP能解释一下他们为什么想要这样做,他们得到一个好答案的机会就会大大提高。


2

问题是“为什么需要这样做?” 答案:这会使代码更易读和理解。

为什么大部分用户界面难用... 许多程序员没有意识到简化用户工作的必要性。在这种情况下,用户的工作是阅读和理解代码。 一个排序后的属性列表让需要调试和维护代码的人更容易工作。对于程序熟悉的列表而言,他可以更快地找到属性或者发现缺失的属性,并更快速地更改属性值。


我觉得你还没有足够长的时间思考这个问题;即使对于这里所说的内容是正确的,一个可行的解决方案也无法解决这个问题。 - issa marie tseng
你认为为什么OP想要使用Javascript来做这件事呢?可能是考虑到服务器端(构建时间?)的Javascript解决方案,但有经验的人不太可能在Stackoverflow帖子中没有提到它。另外,OP正在实现一个浏览器内HTML编辑器也是有可能的,但这也似乎不太可能。 - Pointy

0

我认为这是可能的,如果将HTML内容作为XML传递并通过XSLT呈现...因此,您原始的XML内容可以按任何顺序排列。


0

这只有在有人阅读源代码时才会有影响,所以对我来说,语义属性是首要的,不太语义化的属性其次...

当然也有例外情况,例如如果您有连续的<li>,每个都有一个属性,而其他一些则只有一些属性,您可能希望确保共享的属性都在开头,然后是各自的属性,例如:

<li a="x">A</li>
<li a="y" b="t">B</li>
<li a="z">C</li>

(即使“b”属性比“a”更具语义化)

你明白了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接