首页 > 编程语言 >XmlDocument 解决 Clone、CloneNode、ImportNode 等节点克隆后的标签自闭合问题

XmlDocument 解决 Clone、CloneNode、ImportNode 等节点克隆后的标签自闭合问题

时间:2024-02-02 19:34:09浏览次数:27  
标签:case 缓存 标签 Clone XmlDocument 闭合 CloneNode 问题

前言:

这两天在对 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,则后续无法通过节点操作,这在循环绑定时会拿不到节点。
 */

 

标签:case,缓存,标签,Clone,XmlDocument,闭合,CloneNode,问题
From: https://www.cnblogs.com/cyq1162/p/18003665

相关文章

  • gitclone正常,但是git submodule报错Permission denied
    根本原因是,git这种形式没有权限参考https://www.hangge.com/blog/cache/detail_1561.html......
  • 【亲测管用】解决GitHub clone太慢或者远端意外挂断
    目录解决办法1使用GitHub的镜像,将代码库链接中的“github.com”替换为“github.com.cnpmjs.org”,如图所示:解决办法2将GitHub中的代码库导入码云,然后再进行clone返回目录方案1:github.com.cnpmjs.org返回目录使用GitHub的镜像,将代码库链接中的“github.com”替换为......
  • Git必知必会基础(16):git clone、git pull、git fetch、git push的区别
     gitclone没有本地仓库,将远端的整个项目下载到本地 gitpull本地已经有项目但不是最新(比如你的同事往远处仓库提交了代码),从远程获取最新版本并merge到本地,也就是将远程指定分支拉取到本地指定分支上命令格式:gitpull[远程仓库名][远程分支名]:[本地分支名]本地分支是当前分......
  • 使用git clone --recursive克隆,由于网络原因失败
    问题下载Github上某些代码仓库时,如果代码仓库中具有很多子模块,正常使用gitclone—-recursive下载方式,发现:下载缓慢并且子模块有极大概率不能完全下载。在此通过一个例子,来展示如何快速高效的下载代码库文件。该方法具有普适性。欲下载一代码库文件,原始下载方法为:gitclone......
  • 【github】Mac系统中,如何项目clone(1.通过vscode链接github,2.进行clone)
     1.通过vscode打开一个空文件夹(目录:确认想要放置新项目的目录)2.进行vscode和github的链接1)参考下方网址1-6步,生成sshkey,登录到github,检测SSHkeyhttps://cloud.tencent.com/developer/article/1952247,网址中有效内容如下:1.检查SSHkey是否存在在Mac终端输入:ls-a~/.......
  • Git Clone报错:Permission denied (publickey).
    GitClone报错具体报错如下:Permissiondenied(publickey).fatal:Couldnotreadfromremoterepository.Pleasemakesureyouhavethecorrectaccessrightsandtherepositoryexists.原因在于此电脑的sshpublickey没有放到服务器上。先看下本地是否有以下文件,......
  • cyclone list to python tuple!
    背景python有list和tuplecyclone只有list(被称为array)pythonreturn多个值pythontuplecyclonelistpythontocyclonepythonlistto_cyclonelistto_pythontuple!单个元素的tuple末尾有,确实是tuplepythontupleto_cyclonelist证明cyclone的list(被称为array)其......
  • 【设计模式】单例模式——clone()方法破坏单例模式的情景
    Java的对象不仅可以new关键字产生,也可以利用clone()方法产生,或者利用反射和反序列化产生。用DCL或静态内部类实现单例模式都是利用private修饰构造函数来解决new关键字产生多个对象的问题的,但单例模式仍然可以被clone()方法、反射和反序列化破坏。如下代码所示,让单例类实现Cloneabl......
  • ​​git clone​ 与 git 安装
    gitclone是一个用于从远程仓库克隆代码到本地的命令。使用方法如下:gitclone<仓库地址>其中,<仓库地址>是你要克隆的远程仓库的URL。例如:gitclonehttps://github.com/username/repository.gitGit可以通过官方网站下载并安装。以下是在不同操作系统上安装Git的步骤:Windows......
  • Windows下用rclone代替RaiDrive将ftp映射为本地盘
    Windows下用rclone代替RaiDrive将ftp映射为本地盘1.软件准备:nssm:官网下载地址:https://nssm.cc/downloadrclone:官网下载地址:https://rclone.org/downloads/WinFsp:官网下载地址:https://winfsp.dev/rel/2.使用:下载WinFsp,如我下载的是winfsp-2.0.23075.msi,下一步下......