A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

  学习HTML-Beautify.js之后,我们发现使用JavaScript对HTML进行解析也并不神秘, 首先是逐字符进行分析,从中提取标记(Token),在HTML只存在两种类型的标记-标签和正文, 然后对这些Token进行语法分析,主要是缩进量是多少。
  在有这些基本概念后,今天我们就自己来实现这个小程序:
[AppleScript] 纯文本查看 复制代码
  // 优化过的HTML-Beautify

  function HtmlBeautify(source, indent_value) {

  this.source = source;

  this.indent_value = indent_value;

  this.result = "";

  this.parse();

  }

  // 分析并产生输出到this.result

  HtmlBeautify.prototype.parse = function() {

  var that = this;

  // 当前分析到哪个字符,当前标记值,标记类型,

  // 输出数组,缩进级别,当前格式化内容(去掉多余空格)

  var pos = 0, token_value = "", token_type = "",

  output = [], indent_level = 0, is_format_content = true;

  // 把这些标签作为Single Tag

  var single_token = "br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed".split(',');

  var white_space = "\r\n\t ".split("");

  // 获取下一个标记(首先获取正文,如果正文为空则获取标签)

  function nextToken() {

  var token_value_array = [], val = "", space = false;

  // "<"之前的所有内容作为正文标签

  while ((val = that.source[pos]) !== "<") {

  if (pos >= that.source.length) {

  token_type = "END";

  return;

  }

  if (is_format_content) {

  if ($.inArray(val, white_space) >= 0) {

  space = true;

  pos++;

  continue;

  }

  if (space) {

  token_value_array.push(" ");

  space = false;

  }

  }

  token_value_array.push(val);

  pos++;

  }

  token_value = token_value_array.join("").replace(/^\n+|\n$/g,"");

  if ($.trim(token_value) === "") {

  // 如果正文标记为空,则获取标签标记

  if(!is_format_content) {

  is_format_content = true;

  }

  nextTokenTag();

  } else {

  token_type = "CONTENT";

  }

  }

  // 下一个标签标记

  function nextTokenTag() {

  var token_value_array = [], val = "",

  tagName = "", space = false, is_comment = false;

  // 这是一个注释标签

  if(that.source[pos + 1] === "!" &&

  that.source[pos + 2] === "-" &&

  that.source[pos + 3] === "-") {

  is_comment = true;

  }

  // 获取标签标记,直到遇到">"

  do {

  val = that.source[pos];

  if (!is_comment) {

  // 如果此字符为空格换行制表符,则跳过此字符

  if ($.inArray(val, white_space) >= 0) {

  space = true;

  pos++;

  continue;

  }

  if (space) {

  if(token_value_array[token_value_array.length - 1] !== "=" && val !== "=") {

  token_value_array.push(" ");

  }

  space = false;

  }

  }

  if(val === "/" && that.source[pos + 1] === ">" && token_value_array[token_value_array.length - 1] !== " ") {

  token_value_array.push(" ");

  }

  token_value_array.push(val);

  pos++;

  } while (val !== ">");

  token_value = $.trim(token_value_array.join(""));

  // 当前标签的名称(小写)

  tagName = getTagName();

  if(is_comment) {

  token_type = "SINGLE_TAG";

  } else {

  if (token_value[1] === "/") {

  // token_value以" 

  token_type = "END_TAG";

  } else if ($.inArray(tagName, single_token) >= 0 || token_value[token_value.length - 2] === "/") {

  // 如果标签在single_token或者token_value以"/>"结尾,则认为是独立标签

  // 这种判断没有考虑这种情况:"

"

  token_type = "SINGLE_TAG";

  } else {

  token_type = "START_TAG";

  if (tagName === "script" || tagName === "style") {

  is_format_content = false;

  }

  }

  }

  }

  function getTagName() {

  var tagName = token_value.substr(1, token_value.length - 2);

  var spaceIndex = tagName.indexOf(" ");

  if (spaceIndex > 0) {

  tagName = tagName.substr(0, spaceIndex);

  }

  return tagName.toLowerCase();

  }

  // 输出当前标记

  function outputToken() {

  output.push(token_value);

  }

  // 输出新行

  function outputLine() {

  output.push("\n");

  }

  // 输出缩进

  function outputIndent() {

  for (var i = 0; i < indent_level; i++) {

  output.push(that.indent_value);

  }

  }

  // parse的主体函数,循环获取下一个Token

  while (true) {

  nextToken();

  // 当前Token为结束标记

  if (token_type === "END") {

  break;

  }

  switch (token_type) {

  case "START_TAG":

  // 我们对缩进的控制非常简单,开始标签后缩进一个单位

  outputLine();

  outputIndent();

  outputToken();

  indent_level++;

  break;

  case "END_TAG":

  // 结束标签前减少一个单位缩进

  indent_level--;

  outputLine();

  outputIndent();

  outputToken();

  break;

  case "SINGLE_TAG":

  outputLine();

  outputIndent();

  outputToken();

  break;

  case "CONTENT":

  outputLine();

  if(is_format_content) {

  outputIndent();

  }

  outputToken();

  break;

  }

  }

  // 去除最前面的"\n"

  this.result = output.join("").substr(1);

  };

  $(function() {

  $("#format").click(function() {

  // 实例化HtmlBeautify,传递需要解析的HTML片段和缩进字符串

  var beautify = new HtmlBeautify($("#content").val(), " ");

  $("#content").val(beautify.result);

  });

  });


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马