C# 记一次对chm帮助文档的信息提取
事情时这样,有用友u8的字典数据的帮助文档一份,同事需要把里面的很多张表的字典信息给提取出来,然后构成sql语句,插入数据库。字典就是一张对表里的字段的一个说明,长这样

同事一开始是手动复制到excel文档在改的,他问我有没有什么简单的办法,所以我就决定用代码去实现,把表格、表名等一些有效数据构成对象,有了一个对象就好写sql了。
首先,我在百度上搜索,发现这个chm帮助文档能被反编译成html,经过一番操作,使用windows自带的工具 hh.exe 就可以实现帮助文档的反编译。运行cmd,直接输入命令就行,具体命令是这样:
hh -decompile d:\test\help help.chm
d:\test\help是反编译后的目录。
反编译之后,就会得到具体的html文档,和js、css,长这样:

test目录是我自己建的。
后面就是查看html源码,分析出关键信息的xPath路径该怎么写,因为这里我用到了.net的一款工具专门对html操作的,叫做:HtmlAgilityPack,我的翻译是:html敏捷开发包,写xpath比写正则来的容易,这个包能很好的操作html的节点,获取html、innertext、属性。
贴上我的关键方法:
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | public TableInfo GetTableInfo() { TableInfo tab = new TableInfo(); HtmlDocument doc = new HtmlDocument(); doc.Load(FullPathName, Encoding.GetEncoding( "gb2312" ), true ); if (doc == null ) { throw new NullReferenceException(FullPathName + "\r\n没有加载出文档" ); } string pathGetTableName = "/html/head/title" ; string pathGetTableDesc = "/div/p" ; String pathGetTd = "/div/table/tr" ; var nodeTitle=doc.DocumentNode.SelectSingleNode(pathGetTableName); if ( null != nodeTitle) { tab.TableName = nodeTitle.InnerText.Split( new char [1] { ' ' })[0].Replace( "\r" , "" ).Replace( "\n" , "" ).Replace( "\t" , "" ).Replace( "&" , "" ).Replace( "nbsp;" , "" ); } var nodeBody = doc.GetElementbyId( "pagebody" ); var str = nodeBody.OuterHtml; var doc1 = new HtmlDocument(); doc1.LoadHtml(str); var nodeDesc = doc1.DocumentNode.SelectSingleNode(pathGetTableDesc); if ( null != nodeDesc) { tab.tableDescription = nodeDesc.InnerText.Split( new char [1] { ' ' })[0].Replace( "\r" , "" ).Replace( "\n" , "" ).Replace( "\t" , "" ).Replace( "&" , "" ).Replace( "nbsp;" , "" ); } var nodesTr = doc1.DocumentNode.SelectNodes(pathGetTd); if (nodesTr == null ) { return tab; } List<TabFieldInfo> lists = new List<TabFieldInfo>(); for ( var i = 1; i < nodesTr.Count(); i++) { var childs = nodesTr[i].ChildNodes; if (childs == null ) { continue ; } TabFieldInfo fi = new TabFieldInfo(); if (childs.Count <= 5) { continue ; } fi.ColumnName = childs[1].ChildNodes[1].InnerText.Replace( "\r" , "" ).Replace( "\n" , "" ).Replace( "\t" , "" ).Replace( "&" , "" ).Replace( "nbsp;" , "" ); fi.Description = childs[2].InnerText.Replace( "\r" , "" ).Replace( "\n" , "" ).Replace( "\t" , "" ).Replace( "&" , "" ).Replace( "nbsp;" , "" ); fi.Datatype = childs[3].InnerText.Replace( "\r" , "" ).Replace( "\n" , "" ).Replace( "\t" , "" ).Replace( "&" , "" ).Replace( "nbsp;" , "" ); fi.Length = childs[4].InnerText.Replace( "\r" , "" ).Replace( "\n" , "" ).Replace( "\t" , "" ).Replace( "&" , "" ).Replace( "nbsp;" , "" ); fi.AllowNulls = childs[5].InnerText.Replace( "\r" , "" ).Replace( "\n" , "" ).Replace( "\t" , "" ).Replace( "&" , "" ).Replace( "nbsp;" , "" ); lists.Add(fi); } tab.fields = lists; return tab; } |
这里还出现一个问题,“指定的路径不合法”,原因是,我直接点击文件右键-》属性-》安全 把那里的文件路经复制到代码上去了,其实这样复制,会造成路径字符串最开始的地方有个特殊字符,在vs里是隐藏的,后来我就复制地址栏上的路径,就没问题了。
最后,需要完善的是,通过读取目录,把目录中的所有html结尾的文件遍历,并过滤出需要的表,在构建对象。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了