博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
将HTML转成XHTML并清除一些无用的标签和属性
阅读量:6000 次
发布时间:2019-06-20

本文共 5439 字,大约阅读时间需要 18 分钟。

介绍

  这是一个能帮你从HTML生成有效XHTML的经典库。它还提供对标签以及属性过滤的支持。你可以指定允许哪些标签和属性可在出现在输出中,而其他的标签过滤掉。你也可以使用这个库清理Microsoft Word文档转化成HTML时生成的臃肿的HTML。你也在将HTML发布到博客网站前清理一下,否则像WordPress、b2evolution等博客引擎会拒绝的。

 它是如何工作的

  里面有两个类:HtmlReader和HtmlWriter

  HtmlReader拓展了著名的由Chris Clovett开发的SgmlReader。当它读取HTML时,它跳过所有有前缀的节点。其中,所有像<o:p>、<o:Document>、<st1:personname>等上百的无用标签被滤除了。这样你读取的HTML就剩下核心的HTML标签了。

  HtmlWriter拓展了常规的XmlWriter,XmlWriter生成XML。XHTML本质上是XML格式的HTML。所有你熟悉使用的标签——比如<img>、<br>和<hr>,都不是闭合的标签——在XHTML中必需是空元素形式,像<img .. />、<br/>和<hr/>。由于XHTML是常见的XML格式,你可以方便的使用XML解析器读取XHTML文档。这使得有了应用XPath搜索的机会。

 HtmlReader

  HtmlReader很简单,下面是完整的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// This class skips all nodes which has some
/// kind of prefix. This trick does the job 
/// to clean up MS Word/Outlook HTML markups.
///public class HtmlReader : Sgml.SgmlReader
{
    
public 
HtmlReader( TextReader reader ) : base( )
    
{
        
base.InputStream = reader;
        
base.DocType = 
"HTML"
;
    
}
    
public 
HtmlReader( string content ) : base( )
    
{
        
base.InputStream = 
new 
StringReader( content );
        
base.DocType = 
"HTML"
;
    
}
    
public 
override bool Read()
    
{
        
bool status = base.Read();
        
if
( status )
        
{
            
if
( base.NodeType == XmlNodeType.Element )
            
{
                
// Got a node with prefix. This must be one
                
// of those "" or something else.
                
// Skip this node entirely. We want prefix
                
// less nodes so that the resultant XML 
                
// requires not namespace.
                
if
( base.Name.IndexOf(
':'
) > 
0 
)
                    
base.Skip();
            
}
        
}
        
return 
status;
    
}
}

 HtmlWriter

  这个类是有点麻烦。下面是使用技巧:

  • 重写WriteString方法并避免使用常规的XML编码。对HTML文件手动更改编码。

  • 重写WriteStartElementis以避免不被允许的标签写到输出中。 

  • 重写WriteAttributesis以避免不需求的属性。

  让我们分部分来看下整个类:

  可配置性

  你可以通过修改下面的部分配置HtmlWriter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public 
class 
HtmlWriter : XmlTextWriter
{
    
// If set to true, it will filter the output
    
/// by using tag and attribute filtering,
    
/// space reduce etc
    
///public bool FilterOutput = false;
    
// If true, it will reduce consecutive   with one instance
    
///public bool ReduceConsecutiveSpace = true;
    
// Set the tag names in lower case which are allowed to go to output
    
///public string [] AllowedTags = 
        
new 
string[] { 
"p"
"b"
"i"
"u"
"em"
"big"
"small"
        
"div"
"img"
"span"
"blockquote"
"code"
"pre"
"br"
"hr"
        
"ul"
"ol"
"li"
"del"
"ins"
"strong"
"a"
"font"
"dd"
"dt"
};
    
// If any tag found which is not allowed, it is replaced by this tag.
    
/// Specify a tag which has least impact on output
    
///public string ReplacementTag = "dd";
    
// New lines \r\n are replaced with space 
    
/// which saves space and makes the
    
/// output compact
    
///public bool RemoveNewlines = true;
    
// Specify which attributes are allowed. 
    
/// Any other attribute will be discarded
    
///public string [] AllowedAttributes = new string[] 
    
        
"class"
"href"
"target"
"border"
"src"
        
"align"
"width"
"height"
"color"
"size" 
    
};
}

  WriteString方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// The reason why we are overriding
/// this method is, we do not want the output to be
/// encoded for texts inside attribute
/// and inside node elements. For example, all the  
/// gets converted to &nbsp in output. But this does not 
/// apply to HTML. In HTML, we need to have   as it is.
//public override void WriteString(string text)
{
    
// Change all non-breaking space to normal space
    
text = text.Replace( 
" "
" " 
);
    
/// When you are reading RSS feed and writing Html, 
    
/// this line helps remove those CDATA tags
    
text = text.Replace(
""
""
);
 
    
// Do some encoding of our own because
    
// we are going to use WriteRaw which won't
    
// do any of the necessary encoding
    
text = text.Replace( 
"<"
"<" 
);
    
text = text.Replace( 
">"
">" 
);
    
text = text.Replace( 
"'"
"&apos;" 
);
    
text = text.Replace( 
"\""
""
e;" );
 
    
if
this
.FilterOutput )
    
{
        
text = text.Trim();
 
        
// We want to replace consecutive spaces
        
// to one space in order to save horizontal width
        
if
this
.ReduceConsecutiveSpace ) 
            
text = text.Replace(
"   "
" "
);
        
if
this
.RemoveNewlines ) 
            
text = text.Replace(Environment.NewLine, 
" "
);
 
        
base.WriteRaw( text );
    
}
    
else
    
{
        
base.WriteRaw( text );
    
}
}

  WriteStartElement: 应用标签过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public 
override 
void 
WriteStartElement(string prefix, 
    
string localName, string ns)
{
    
if
this
.FilterOutput ) 
    
{
        
bool canWrite = 
false
;
        
string tagLocalName = localName.ToLower();
        
foreach( string name in 
this
.AllowedTags )
        
{
            
if
( name == tagLocalName )
            
{
                
canWrite = 
true
;
                
break
;
            
}
        
}
        
if
( !canWrite ) 
        
localName = 
"dd"
;
    
}
    
base.WriteStartElement(prefix, localName, ns);
}

  WriteAttributes方法: 应用属性过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool canWrite = 
false
;
string attributeLocalName = reader.LocalName.ToLower();
foreach( string name in 
this
.AllowedAttributes )
{
    
if
( name == attributeLocalName )
    
{
        
canWrite = 
true
;
        
break
;
    
}
}
// If allowed, write the attribute
if
( canWrite ) 
    
this
.WriteStartAttribute(reader.Prefix, 
    
attributeLocalName, reader.NamespaceURI);
while 
(reader.ReadAttributeValue())
{
    
if 
(reader.NodeType == XmlNodeType.EntityReference)
    
{
        
if
( canWrite ) 
this
.WriteEntityRef(reader.Name);
        
continue
;
    
}
    
if
( canWrite )
this
.WriteString(reader.Value);
}
if
( canWrite ) 
this
.WriteEndAttribute();

 结论

  示例应用是一个你可以立即用来清理HTML文件的实用工具。你可以将这个类应用在像博客等需要发布一些HTML到Web服务的工具中。

  原文地址:

转载于:https://www.cnblogs.com/ranran/p/3656099.html

你可能感兴趣的文章
碰撞检测
查看>>
到底哪种类型的错误信息会阻止business transaction的保存
查看>>
几句话熟悉Laravel/Symfony 事件系统
查看>>
webpack升级2.0遇到的坑
查看>>
以Redis来谈消息队列
查看>>
学习笔记DL008:概率论,随机变量,概率分布,边缘概率,条件概率,期望、方差、协方差...
查看>>
BAT等大厂已开源的70个实用工具盘点(附下载地址)
查看>>
CSS布局
查看>>
【225天】黑马程序员27天视频学习笔记【Day26-上】
查看>>
除了区块链和比特币,这些技术成果正在改变世界
查看>>
Django REST FrameWork中文教程5:关系和超链接API
查看>>
【网易云信】DNS 调度原理解析
查看>>
GitChat · 架构 | 从好友中心开始,聊「多对多」类业务数据库水平切分架构实践...
查看>>
composer - 初始化项目
查看>>
20170813-CSRF 跨站请求伪造
查看>>
jQuery 对象、基本选择器、筛选选择器
查看>>
npm install、npm init、npm update、npm uninstall和package.json
查看>>
优秀Demo - 收藏集 - 掘金
查看>>
javascript设计模式(Alloy Team)
查看>>
Powershell快速入门(一) 安装和使用
查看>>