2023年3月

首先表达歉意,这几天一直忙于联系暑期实习单位,没有及时回复与更新。现在还没有搞定,可以的话大家帮个忙,看看我的
实习求职
我对现在的解析html的算法还是比较满意的。现阶段,经过我的一些测试,添加了对BR,IUPUT,IMG,META,SCRIPT,注释等特殊html语法的支持。对于完全符合html语法规范的页面,效果是令人满意的。不足之处是缺乏对错误的包容能力,对不符合html语法的页面可能解析出错或者异常。如果要把它做成完善的html解析器,我认为必须实现一个优先级算法,提供错误的包容能力。不过我想,这个问题相当复杂,暂时不能很好的解决。现在,我决定采取另外一种折中的方式,即只解析自定义的控件,而不处理普通的html控件。以现在的算法,可以很轻易的实现这个功能。
个人觉得,使用用户控件,然后在控件输出的时候截获render应该是可取的。但个人感觉这种方式实际使用负载,不够灵活。我个人更倾向于实现一个轻量级的、易控的静态页面生成类库,可以轻松自由的进行自定义和扩展。对于大多数网站来说,首页和分类页面的请求都是很频繁的,并且内容也需要经常性的更新,使用Asp.Net的缓存机制是一个很好的选择;但是对于网站的内容页,如新闻或者软件下载的内容页面,相对来说请求频率要低得多,动态生成或者使用缓存都是不合适的。这种情况最好的选择是生成静态页面,然后保存在硬盘上。另外,对于实时性要求不高的首页或者分类页,也可以结合shtml的include机制,将内容部分用模板的方式静态生成保存在硬盘上。
正如本文开头所说,由于联系暑期实习单位的事情,最近几天都暂停开发了。在这里我还是先将上一篇文章没说完的继续说完。
整个解析模块主要由三个类来构成:StaticControlFactory、ParseStatusManager和StaticBaseControl构成的。其中StaticControlFactory主要负责对模板进行字符分析处理和控件的处理;ParseStatusManager主要负责对控件解析状态进行处理,以及对StaticControlFactory发出处理命令;StaticBaseControl是实体类,保存相关结果。
代码结构自认为还是很清晰的,并且有很多注释,我就不详细解释了,主要说明几个关键的地方。StaticControlFactory中使用了堆栈来保存控件的层次结构。每当创建了新的控件,就将新控件加入到当前控件的子控件集合中,然后将当前控件推入堆栈,新控件成为当前控件。当新控件解析完毕后则反向操作。ParseStatusManager的状态管理也采用了相似的方式,只是没有前者的层次结构。每次StaticControlFactory读取到边界字符时,就调用ParseStatusManager对象的ChangeStatus方法,实现相应的状态转化。ParseStatusManager对StaticControlFactory的操作,我使用了代理结合Command模式的方式来实现。这种方式最大的好处是ParseStatusManager不需要维护StaticControlFactory的一大堆方法签名,只需要传入合适的命令就可以了。如果需要在处理状态转换的时候,需要增加新的处理,只需要使StaticControlFactory增加对一个新的命令的支持就可以了。
为了增加对不符合<flag name=value>body</flag>形式的标签,包括img、br之类可以无结尾或使用/>简短结束标志的标签的支持,对StaticControlFactory增加了几个方法,ReadNextWord用以获取控件开始标签后的下一个单词,以判断当前标签是否是定义的特殊标签,ProcessForScriptBlock用以专门处理Script模块。如果希望将类库改成指处理我们定义的特殊标签,就可以在每次读到控件开始标记的时候使用ReadNextWord读取控件类型,在判断正确后才开始控件的解析操作;对每次读到控件结束标记时也进行相似操作。

现在的方案实际上是我的第二个方案。第一个方案使用了递归,思路不是很清晰,调试起来相当麻烦,现在的方案要清晰多了。对于数据绑定,在我的第一个方案里已经部分实现了,主要采用了遍历加反射的方式。遗憾的是还只支持了对对象数组这种数据源的支持,主要原因是我现在的项目使用了petshop3的结构,以数据实体的方式传递数据,并且没有实现repeate之类控件嵌套形式下的绑定。不过预计这两个问题都比较简单,可以比较快的实现。我会尽快实现一个可使用的版本发布出来。

花费了一天半的时间,终于完成了第一个可用版本。和以前的设想有几点不同:

1、标签格式
参考了大家的意见之后,标签的格式改为:<homer:tag name=value>body</homer:tag>的形式。

2、模版解析方式
以前考虑的方式是解析所有的页面标签(包括html和自定义标签)后,再从中找出自定义标签进行处理。这样的处理方式主要是考虑到以后增加标签的话,无须修改解析模版的方式。现在看来,这是不必要的,无端增加复杂度。现在的方式是对html标签不理睬,而只解析自定义标签。

3、数据源支持
现在可以同时支持实体类、DataTable、DataReader作为数据源(注:DataReader还没有经过严格测试)。

图片时demo的截图,同时
源码
也作了更新:

Stella Forum

notus
写的一个开源论坛,使用了
听棠
的SPL这个orm组件。我由于学习SPL的缘故,参看了论坛的源码,在项目的贴子上谈了一些自己对于orm的想法,猜想可能对orm新手可能会有点启示,转过来和大家分享。


因为我现在的项目计划需要使用SPL,所以打算从楼主的这个开源项目里面学习一下。但是在看了以后,我认为楼主的结构设计还是不错的,不过有几个地方我觉得不妥。楼主使用了SPL这个orm组件,但是我不知道楼主用这个做什么?难道只是使用它那个方便的代码生成器生成entity?或者使用entity中方便的CUID吗?或者就是为了使用orm而使用orm么?而且楼主除了使用我上面说的SPL的几种最基本的功能,没有使用任何高级的功能吧?总而言之,我认为楼主没有正确的使用orm。


我就我的理解提几个改进意见:

1
、就结构看,楼主的结构和petshop3的结构很类似,猜测可能也是对他的一种仿照吧?如果是这样,楼主可以去掉Factory模块了。就我理解,petshop3之所以设计这个模块,主要是提供可以根据web.config中不同的设置使用不同的数据库访问组件,但是SPL本身已经实现了对多种数据库的兼容,所以这是不需要的。

2
、对SPL生成的entity,由于是和数据库表的直接对应,肯定是不符合系统的业务模型的。为了改进entity,系统选择了重新编写一个Model,我不赞同。我认为可以采用两种方式,一种是组合,一种是继承。举个例子,在我写过的一个稿件管理系统中,一篇稿子(Thesis)有n个作者(Author)。对于组合,我可以新建一个ThesisModel类,以组合一个Thesis对象和一个Author数组;对于继承,我也可以新建一个ThesisModel类继承自SPL生成的ThesisEntity,然后添加Author数组等属性和其他的相应操作。

3
、对于entity的操作,我也喜欢使用一个单独的action来实现。实现的方式,和上面一样,也可以使用组合和继承,充分利用自动生成的action。这样做的一个好处就是,如果以后的数据库结构更改了,由于采用了组合或者继承,仍然可以使用自动生成的代码,轻易适应这种更改。

4
、orm的初衷就是要隔离数据对象的使用和对数据库实际的存储操作,以方便以面向对象的方式使用数据库,所以对数据库的操作最好通过orm内置访问方法进行。只有在orm组件提供的访问方式不能实现所需的操作或者性能不能满足要求的时候,才使用直接的SQl查询语句或存储过程实现。这样做的好处之一就是可以充分利用orm工具对异构数据库的支持的特性,便于移植;另一个好处就是更难出现低级错误,节省时间。这个项目使用了大量的存储过程,我没有仔细看过,不便评论,但还是建议简单的查询使用orm内置的面向对象的查询方式。



现在正值暑假,我呢,还在学校里面打工挣钱.马上大四了,我是决心考研的,所以现在辛苦挣点钱,好支持我的考研计划.所以呢,现在同时做了两个兼职,都是软件开发的,累死我了.不要奇怪我为什么能同时做两个,其实很简单,我专门找的可以在寝室里面做的那种,因为我想这样还可以给我一部分时间复习考研.哪想做起来才知道,这种方式实在是痛苦啊.以前还天真的以为可以有时间复习,现在才知道忙得连休息的时间都没有了.现在后悔了,早知道只做一个好了.SOHO都是在家里工作的,不知道他们怎么做的?如果都像我这样,那SOHO也太惨了,我宁愿上班去.

现在需要在网页上显示一个播放影视文件的ActiveX控件,但是我并不想页面刚加载便显示此控件,而是在缓冲完成后才显示此控件,缓冲完成之前在本该显示控件的地方显示一个广告。

我尝试了两种方法,都没有成功。第一种是使用两个层,一个放广告,一个放控件,使用display='none'和display=''来实现页面初次加载时显示广告层,点击播放按钮并缓冲完成后显示控件层。但是我发现如果设置display='none',则控件并没有加载,所以点击播放按钮时调用其函数不成功。此方法未能实现。

第二种方式如下:


<
html
>


<
head
>



<
script
language
="JavaScript"
type
="text/JavaScript"
>



<!--


function
load()



{

document.all['Layer1'].style.display

=
'none';

document.getElementById('Layer2').style.left

=
'11px';

document.getElementById('Layer2').style.top

=
'16px';

document.getElementById('Layer2').style.width

=
'500px';

document.getElementById('Layer2').style.height

=
'
375
';

}



//
-->


</
script
>


</
head
>


<
body
>


<
table
width
="10"
height
="10"
border
="0"
cellpadding
="0"
cellspacing
="0"
>


<
tr
>


<
td
height
="10"
><
div
id
="Layer1"
style
="width:500px; height:375px; z-index:1; background-color: #FF0000; layer-background-color: #FF0000; border: 1px none #000000;"
></
div
></
td
>


</
tr
>


<
tr
>


<
td
>


<
br
><
br
><
br
><
br
>


<
input
type
="button"
value
="click"
onClick
="load()"
><
input
type
="button"
value
="click2"
onClick
="load()"
>


</
td
>


</
tr
>


</
table
>


<
input
type
="button"
value
="click"
onClick
="load()"
>


<
div
id
="Layer2"
style
="position:absolute; width:500px; height:375px; z-index:1; left: -9999px; top: -9999px; background-color: #FF0000; layer-background-color: #FF0000; border: 1px none #000000;"
>
<!--
此处放置控件,略去
-->
</
div
>



</
body
>


</
html
>

也就是在开始将layer2放置在页面之外,在播放的时候可以移到页面之中,可以做到开始的时候页面不显示控件却可以加载控件的目的。这样做可以成功用layer2覆盖layer1,但是却奇怪的发现页面上的几个按钮一块消失了。我对DHTML不是很熟,希望高手可以帮我答疑解惑,或者有什么更好的方法?