//html 简单解析器
import string.xml;
namespace string;
class html{
ctor( str ){
this = ..string.xml(str,xmlElementType,optionalTags)
};
}
namespace html;
//可选标签,用于处理可以省略闭合标签的元素
optionalTags = {
body={head=1};// body 元素开始标签可自动关闭上一个省略结束标签的 head 节点
li={li=1};//li 元素开始标签可自动关闭上一个省略结束标签的 li 节点
dt={dt=1;dd=1};
dd={dt=1;dd=1};
rt={rt=1;rp=1};
rp={rt=1;rp=1};
optgroup={optgroup=1;option=1};
option={option=1};
tbody={thead=1;tbody=1;th=1;tr=1;td=1;caption=1;colgroup=1;col=1};
tfoot={thead=1;tbody=1;tr=1;th=1;td=1;caption=1;colgroup=1;col=1};
thead={caption=1;colgroup=1;caption=1;col=1};
colgroup={colgroup=1;col=1;caption=1;};
tr={tr=1;td=1;th=1;caption=1;colgroup=1;col=1};
td={td=1;th=1};
th={td=1;th=1};
address={p=1};
article={p=1};
aside={p=1};
blockquote={p=1};
details={p=1};
div={p=1};
dl={p=1};
fieldset={p=1};
figcaption={p=1};
figure={p=1};
footer={p=1};
form={p=1};
h1={p=1};
h2={p=1};
h3={p=1};
h4={p=1};
h5={p=1};
h6={p=1};
header={p=1};
hr={p=1};
main={p=1};
nav={p=1};
ol={p=1};
p={p=1};
pre={p=1};
section={p=1};
table={p=1};
ul={p=1};
}
xmlElementType = {
//1 Void elements
area=1;base=1;br=1;col=1;embed=1;hr=1;img=1;input=1;link=1;meta=1;param=1;source=1;track=1;wbr=1;
//2 Raw text elements
script=2;style=2;textarea=2;title=2;
}
var rep = ..string.replace;
removeTag = function(html,tag,...){
var html = rep(html,"\<\!--.*?--\>" , "");
html = rep(html, "\<\s*<@@"+tag+"@>[^\>]*?\s*\>.*?\<\s*/<@@"+tag+"@>\s*>","");
html = rep(html, "\<\s*<@@"+tag+"@>!\W[^\>]*?\s*\>.+?\<\s*/","");
html = rep(html, "\<\s*<@@"+tag+"@>!\W[^\>]*?\s*\>.+","");
if(!...) return html;
return removeTag(html,...);
}
toXml = function(html){
var doc = ..string.html(html);
if(!doc) return;
var dt = doc.queryEle(tagName="!doctype")
if(dt) dt.remove();
var root = doc.queryEle(tagName="html")
if(!root){
doc.tagName = (
doc.queryEle(tagName="body") || doc.queryEle(tagName="head")
) ? "html" : "body";
root = doc;
}
return `` + root.outerXml();
}
toText = function(html){
if(!html) return;
var html = rep(html,"\<\!--.*?--\>" , "");
html = ..string.match(html,"\<\s*<@@body@>[^\>]*?\s*\>.+") : html;
html = removeTag(html,"head","style","script");
html = rep(html,
"\<\s*pre[^\>]*?\s*\>(.*?)\<\s*/pre\s*>",
function(c){
c = rep(c," "," ");
c = rep(c,'\n',"
");
return c;
}
);
html = rep(html,"\s+"," ");
html = rep(html,"\<[bB][rR]\s*/*\>",'\r\n');
html = rep(html,"\*[pP]\>",'\r\n');
html = rep(html,"\",'\r\n');
html = rep(html,"\",'\r\n');
html = rep(html,"\<.+?\>","");
return ncr(html);
}
fromText = function(v){
if(!v) return;
v = rep(v,"@&",'&');
v = rep(v,'@<',"<");
v = rep(v,'@>',">");
v = rep(v,'@"',""");
v = rep(v,"@'","'");
v = rep(v," "," ");
v = rep(v,'\r\n',"
");
v = rep(v,'\n',"
");
v = rep(v,'\r',"
");
return v;
}
escape = ..string.xml.escape;
ncrDecode = ..string.xml.ncrDecode;
ncrEncode = ..string.xml.ncrEncode;
ncr = ..string.xml.ncr;//@Deprecated
/**intellisense()
string.html = HTML 简单解析器。\n\n严格的校验 HTML 语法正确性不是本模块的设计目标,\n所以此解析器尽可能兼容错误,兼容了 HTML,SGML 的部分规则:\n1. 不要求存在根标签 \n2. 尝试自动修正不配对的标记 \n3. 在有必要的时候尝试忽略大小写\n4. 支持识别 HTML 空标签、省略闭合标签规则
string.html(__) = 创建HTML解析器,参数请指定包含HTML代码的字符串,\n调用string.xml解析HTML代码,用法与string.xml相同\n但支持识别HTML空标签、省略闭合标签规则\n\n此对象不支持 table.tostring , console.dump 函数,不能跨线程传递
string.html() = !string_xml.
string.html.escape(__) = 将字符串中的 < > " ' & 等 HTML 标记字符编码为实体字符(entity)。\n如果参数为非 null 值则返回转换后的字符串。\n参数只能是 null 或字符串、buffer
string.html.ncrEncode(.(str,pattern) = 将字符串参数 @str 中以 @pattern 指定模式串所匹配的字符进行 NCR 编码。\n参数 @pattern 可用模式匹配语法指定要编码的字符,省略则默认为 ":|."。\n返回编码后的字符串。
string.html.ncrDecode(__) = NCR 编码字符、HTML 实体字符还原为 UTF8 文本
string.html.toText(__/*HTML代码*/) = 将HTML代码转换为文本
string.html.fromText(__/*普通文本*/) = 将普通文本转换为HTML
string.html.removeTag(html,"script__") = 移除指定的html标记,支持不定个数的标记参数
string.html.toXml(__/*HTML代码*/) = 将 HTML 代码转换为 XML 文本
end intellisense**/
/**details(使用说明)
string.html 继承自 string.xml ,基本用法与 string.xml 相同。
string.html 每个 HTML 节点对象都是一个表对象(table),
这些 HTML 节点对象如果有 tagName 属性表示标记名 - 那他就是一个普通节点。
如果没有 tagName 属性而是拥有 text 或 cdata属性 - 那就说明它是一个 text 文本节点或者是 cdata 节点。
string.html 提供以下四种类型的节点:
1. 拥有标签名( tagName 属性)的普通 HTML 元素
普通 HTML 节点使用 tagName 属性表示 XML 标记名,
在 string.html 中 "tagName"属于保留的 HTML 属性,其他属性使用此属性名将会被自动忽略。
> XML 声明节点的 tagName 为"?xml"
2. 顶层根节点
string.html 总是虚拟出一个空的没有 tagName 属性的顶层根节点,
这个根节点是文档里的 XML/HTML 真实根节点的父节点。
3. 文本节点
文本节点使用 text 属性表示文本,无 tagName 属性,无其他属性。
4. CDATA节点
CDATA 节点使用 cdata 属性表示数据, 无 tagName 属性,无其他属性
注释节点被自动忽略不会存为节点对象。
end details**/