liujie
2026-09-17 c867f2b648ce3dfb5a679ca86bb38f228317fc3b
mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/common/html-parser.js
@@ -79,8 +79,10 @@
 *
 */
// Regular Expressions for parsing tags and attributes
var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
// fixed by 名导精讲 标签名允许冒号,兼容 Word 导出的 <o:p>、<v:shape> 等命名空间标签,
// 否则解析循环无法前进会抛出 Parse Error,导致页面把整段 HTML 当纯文本显示。
var startTag = /^<([-A-Za-z0-9_:]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
var endTag = /^<\/([-A-Za-z0-9_:]+)[^>]*>/;
var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5
var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5
@@ -121,6 +123,10 @@
          }
          html = html.substring(index + 3);
          chars = false;
        } else {
          // 未闭合注释:吞掉剩余内容,避免解析循环无法前进抛出 Parse Error
          html = '';
          chars = false;
        } // end tag
@@ -251,7 +257,72 @@
}
function removeDOCTYPE(html) {
  return html.replace(/<\?xml.*\?>\n/, '').replace(/<!doctype.*>\n/, '').replace(/<!DOCTYPE.*>\n/, '');
   return html
      .replace(/<\?xml[\s\S]*?\?>/gi, '')
      .replace(/<!DOCTYPE[^>]*>/gi, '');
}
// Word 导出 HTML 专用清洗:去掉小程序富文本无法处理的噪声内容。
function sanitizeWordHtml(html) {
   return removeDOCTYPE(html)
      // downlevel-revealed 条件注释(<![if !supportLists]> / <![endif]>)不是标准注释,会让解析循环卡死
      .replace(/<!\[if[\s\S]*?\]>/gi, '')
      .replace(/<!\[endif\]>/gi, '')
      // 标准注释与 downlevel-hidden 条件注释块(内含 <xml><w:WordDocument> 等大段配置)
      .replace(/<!--[\s\S]*?-->/g, '')
      .replace(/<head[\s\S]*?<\/head>/gi, '')
      .replace(/<(style|script|xml)[\s\S]*?<\/\1>/gi, '')
      // html/body 外壳 rich-text 不支持,可能连同子树一起被丢弃,只保留内部节点
      .replace(/<\/?html[^>]*>/gi, '')
      .replace(/<\/?body[^>]*>/gi, '')
      // 命名空间标签(<o:p>、<v:shape>、<st1:place> 等)只删标签本身,保留其中的文本
      .replace(/<\/?[A-Za-z][\w.-]*:[\w.-]*(?:\s[^>]*)?\/?>/g, '');
}
var namedEntities = {
   nbsp: ' ',
   ensp: ' ',
   emsp: ' ',
   quot: '"',
   apos: "'",
   amp: '&',
   lt: '<',
   gt: '>',
   ldquo: '\u201c',
   rdquo: '\u201d',
   lsquo: '\u2018',
   rsquo: '\u2019',
   mdash: '\u2014',
   ndash: '\u2013',
   hellip: '\u2026',
   middot: '\u00b7',
   bull: '\u2022',
   dagger: '\u2020',
   permil: '\u2030',
   lsaquo: '\u2039',
   rsaquo: '\u203a',
   times: '\u00d7',
   divide: '\u00f7',
   copy: '\u00a9',
   reg: '\u00ae',
   trade: '\u2122',
   deg: '\u00b0',
   minus: '\u2212',
   szlig: '\u00df'
};
// rich-text 的文本节点不会解码实体,Word 正文里的 &ldquo; 等需要在这里转成字符。
function decodeEntities(text) {
   if (text.indexOf('&') < 0) return text;
   return text.replace(/&(#[xX]?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, function (all, name) {
      if (name[0] === '#') {
         var code = name[1] === 'x' || name[1] === 'X' ? parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10);
         return isNaN(code) || code < 0 || code > 0x10ffff ? all : String.fromCodePoint(code);
      }
      // amp 最后解,避免 &amp;lt; 被二次解码
      if (name === 'amp') return '&';
      return Object.prototype.hasOwnProperty.call(namedEntities, name) ? namedEntities[name] : all;
   });
}
function parseAttrs(attrs) {
@@ -270,7 +341,7 @@
}
function parseHtml(html) {
  html = removeDOCTYPE(html);
   html = sanitizeWordHtml(html);
  var stacks = [];
  var results = {
    node: 'root',
@@ -317,7 +388,7 @@
    chars: function chars(text) {
      var node = {
        type: 'text',
        text: text
        text: decodeEntities(text)
      };
      if (stacks.length === 0) {