XmlDocument 解决 Clone、CloneNode、ImportNode 等节点克隆后的标签自闭合问题
前言:
这两天在对 Taurus.Mvc 做 html 加载性能优化时,发现存在这个问题。
具体优化的是 CYQ.Data 组件的 XHtmlAction 相关类。
问题过程:
之前 XmlDocument 调用 LoadXml(xml)之后,缓存对象,再次使用时,都是重新LoadXml:
XmlDocument newDoc = new XmlDocument();
try
{
newDoc.LoadXml(缓存xDoc.InnerXml);
}
catch (Exception err)
{
Log.Write(err, LogType.Error);
newDoc.InnerXml = xDoc.InnerXml;
}
return newDoc;
上面的代码,多年来一直工作很好,直到最近,在做优化,发现还原节点,可以通过 Clone 方式,而且性能提升不少:
代码如:
//克隆速度快。
return 缓存xDoc.Clone() as XmlDocument;
后面发现用 CloneNode 方式,还能更优一点:
//克隆速度快。
return 缓存xDoc.CloneNode(true) as XmlDocument;
以为问题解决时,却出现了样式怪异的问题,一开始以为是克隆还保持引用的问题,花了不少时间,找错了方向。
经反复排查,对比生成的内容,才发现以上的方法,都会造成 div 空节点标签被自闭合了:
成了:<div xxx=xxx />
经测试,确认是该问题(仅.NET版本出问题,.NET Core 在以上方法,不会产生自闭合问题)。
解决问题:
要解决这个问题,网上找找解决方案:
意外发现还有 ImportNode 方式可以用,尝试了一下,似乎更优一丁点,蚊子腿也是肉:
HtmlDocument document = new HtmlDocument();
XmlNode node = document.ImportNode(缓存xDoc.DocumentElement, true);
document.AppendChild(node);
return document;
但,网上只有个别提问题,没有解决方案。
但发现了标签是否闭合和以下属性有关:
设置 XmlElement 的 IsEmpty = false;//不自闭合标签
而 Clone 或 ImportNode,没有提供参数设置该参数。
没思路的时候,就多看看.Net 源码。

于是,想到通过继承:XmlDocument,改写 CreateElement 方法,来实现:
class XHtmlDocument : XmlDocument
{
public override XmlElement CreateElement(string prefix, string localName, string namespaceURI)
{
XmlElement xe = base.CreateElement(prefix, localName, namespaceURI);
switch (localName)
{
case "meta":
case "br":
case "hr":
case "img":
case "link":
case "base":
case "area":
case "input":
case "source":
case "!DOCTYPE":
break;
default:
xe.IsEmpty = false;//不自闭合标签
break;
} return xe;
}
}
总结:
Xml 需要标签不自闭合的场景,可能很少,但若需要,这就是个解决方案之一。
再补充 CYQ.Data 关于加载 html 的性能优化说明:
/*
* 性能优化说明:
* 1、DTD:如果界面没有实体&xxx;则不加载,否则修改DTD路径到本地。
* 2、XmlDocument:LoadXml 性能优化:加载后缓存,后续从缓存转化:这里要转化也没那么简单,需要解决以下问题:
* ---------------------------------------------------------------------------------------
* A、从缓存拿到,从缓存Doc拿出InnerXml,再重新LoadXml(xml),兼容性最好,但可优化。
* B、从缓存拿到,从缓存Doc调用:Clone、CloneNode(true)、两个性能差不多,节点多时,后面那个更优。
* C、从缓存拿到,从缓存Doc发现:XmlDocument ImportNode 方法比CloneNode(true) 更优,准备采用这个。
* D、上面B、C两种方式,产生新的问题:.NET 下标签自闭合、.NET Core下正常,改动见:GetCloneFrom 方法。
* E、解决标签自闭合问题:继承XmlDocument,改写CreateElement,根据W3C标准找出需要自闭合的,其余条件设置XmlElement的IsEmpty=false,见:XhtmlDocument
* F、解决上述问题后,为了性能,从缓存中不加载DTD、引发样式问题:
* G、解决F的问题是,输出的时候检测没有DTD头,则追加:<!DOCTYPE html>头,见:XHtmlAction OutXml输出。
* ----------------------------------------------------------------------------------------
* 4、避免使用 InnerXml 属性,用其它方式替代:InnerText、节点引用等,但引发另一个问题,赋值text,则后续无法通过节点操作,这在循环绑定时会拿不到节点。
*/
XmlDocument 解决 Clone、CloneNode、ImportNode 等节点克隆后的标签自闭合问题的更多相关文章
- jQuery实现节点克隆、替换和互换
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...
- DOM节点克隆
var newDiv = red.cloneNode();document.body.appendChild(newDiv);注意:1.默认只克隆元素本身:设置参数为true,进行深度克隆,可以克隆元 ...
- 解决CentOS虚拟机克隆后无法上网(网卡信息不一致)的问题
一.问题描述 虚拟机克隆后,由于网卡信息不一致的问题,导致不能上网或者执行"sercice network restart"命令失败 [root@lyy 桌面]# ifconfig ...
- 解决Table不继承父节点的属性的方法
解决Table不继承父节点的属性的方法 发现table不继承父节点的属性. 解决方法:给html文件加上<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML ...
- 解决jQuery ajax动态新增节点无法触发点击事件的问题
在写ajax加载数据的时候发现,后面添加进来的demo节点元素,失去了之前的点击事件.为什么点击事件失效,我们该怎么去解决呢? 其实最简单的方法就是直接在标签中写onclick="" ...
- 解决CentOS6.5虚拟机克隆后无法上网(网卡信息不一致)的问题
一.问题描述 虚拟机克隆后,由于网卡信息不一致的问题,导致不能上网或者执行“service network restart”命令失败 [root@lyy 桌面]# ifconfig //查看当前网卡信 ...
- 用虚拟机安装了一台Linux系统,突然想克隆一台服务器,克隆后发现无法上网,如何解决?
用虚拟机安装了一台Linux系统,突然想克隆一台服务器,克隆后发现无法上网,如何解决? 答: a.编辑网卡配置文件/etc/sysconfig/network-scripts/ifcfg-eth ...
- linux中如何解决克隆后的电脑的问题
1.如何解决克隆后的电脑的网络问题 克隆出来的电脑,IP地址,网卡都是重复的,不能直接使用,需要修改 1)vim /etc/udev/rules.d/70-persistent-net.rules ...
- vmware14克隆后UUID相同的解决方法
查看网卡 UUID值 [root@localhost network-scripts]# nmcli connection showNAME UUID TYPE DEVICE ens33 cf228d ...
- Linux VMware 克隆后无法启动eth0网卡
引: VMware 下LINUX出现:Device eth0 does not seem to be present, delaying initialization.解决办法 VMWare 克隆 复 ...
随机推荐
- Linux一键安装docker脚本,含ubuntu和centos
将脚本保存为docker_install.sh,可以上传git,到服务器中,git clone下来后,sh docker_install.sh即可自动安装 ubuntu实现 # 以Ubuntu为例 # ...
- 分享这位大神的WPF界面设计系列视频
本文结构: 前言 视频详情 搬运详情 总结 4.1 国内推荐WPF资源 4.2 B站是学习的天堂 4.3 去外面看看 4.4 个人给C/S同学建议 1. 前言 今天介绍油管上一个大佬发的WPF设计系列 ...
- C# WPF侧边栏导航菜单(Dropdown Menu)
时间如流水,只能流去不流回! 点赞再看,养成习惯,这是您给我创作的动力! 本文 Dotnet9 https://dotnet9.com 已收录,站长乐于分享dotnet相关技术,比如Winform.W ...
- Go-快速排序
package main import "fmt" // 快速排序 // 特征: // 1. 选定一个数,让这个数左边的比这个数小,右边比这个数大 // 2. 然后这个基数就是已经 ...
- ONVIF网络摄像头(IPC)客户端开发—RTSP RTCP RTP加载H264视频流
前言: RTSP,RTCP,RTP一般是一起使用,在FFmpeg和live555这些库中,它们为了更好的适用性,所以实现起来非常复杂,直接查看FFmpeg和Live555源代码来熟悉这些协议非常吃力, ...
- [转帖]ipv6相关内核参数配置的优化实践
https://zhuanlan.zhihu.com/p/605217713 调整ARP缓存大小 这个参数通常需要在高负载的访问服务器上增加.比如繁忙的网络(或网关/防火墙 Linux 服务器),再比 ...
- [转帖]linux将大目录等分切割成多个小目录
https://www.jianshu.com/p/6f9e6743a1dc 需求:有一个目录存放了数十万个文件,现在需要将这个目录上传,如果整个目录上传,中间因为某些故障断开连接了,可能又要从头开始 ...
- [转帖]tikv下线Pending Offline卡住排查思路
https://tidb.net/blog/5e960334?utm_source=tidb-community&utm_medium=referral&utm_campaign=re ...
- Windows平台文件拆分与完整性检查的过程
Windows平台文件拆分与完整性检查的过程 场景 有时候在没有linux主机的情况下, 自己下载下来的文件比较大. 比较难以上传到一些特殊的系统/主机上面. 这个时候需要将文件进行拆分. 所以可以通 ...
- [转帖]TiDB 热点问题处理
TiDB 热点问题处理 本文介绍如何定位和解决读写热点问题. TiDB 作为分布式数据库,内建负载均衡机制,尽可能将业务负载均匀地分布到不同计算或存储节点上,更好地利用上整体系统资源.然而,机制不是万 ...