2007-04-26
使用Dxpcom进行HTML文本的DOM解析
关键字: D语言,dxpcom,html,dom
开帖纪念,dxpcom终于可以使用了.
找了好半天,才知道怎么使用mozilla xpcom进行HTML的DOM解析.
解析使用的组件是"@mozilla.org/xmlextras/domparser;1",可以解析HTML和XML.解析使用的接口是nsIDOMParser.
代码如下,保存时要注意为UTF-8格式,不然无法用DMD编译.
看上去好像很繁琐,但等D的异常风格包装完事后,会好看的多!
再次对qiezi的工作表示敬意!为我们提供了在D中使用xpcom的可能!
:)
其他不明的相关事宜,请大家讨论.
这次修改,加入了Release调用.
最终的运行结果是:
找了好半天,才知道怎么使用mozilla xpcom进行HTML的DOM解析.
解析使用的组件是"@mozilla.org/xmlextras/domparser;1",可以解析HTML和XML.解析使用的接口是nsIDOMParser.
代码如下,保存时要注意为UTF-8格式,不然无法用DMD编译.
import mozilla.xpcom.nsXPCOM;
import mozilla.xpcom.nsIDOMParser;
import mozilla.xpcom.nsIComponentManager;
import mozilla.xpcom.nsIDOMDocument;
import mozilla.xpcom.nsIDOMHTMLDocument;
import mozilla.xpcom.nsISupports;
import mozilla.dxpcom.StringAPI;
import mozilla.dxpcom.QueryInterface;
import std.string;
import std.stdio;
void main(char[][] args)
{
//定义xpcom组件管理器接口
nsIComponentManager componentManager;
nsresult result;
//定义一个临时使用的空串
AString tStr=new AString();
//初始化xpcom环境
result = NS_InitXPCOM2(null, null, null);
assert(result==0);
//得到xpcom组件管理端接口
result = NS_GetComponentManager(&componentManager);
assert(result==0);
//定义DOM解析器接口
nsIDOMParser DOMParser;
//使用xpcom组件管理端,从指定的组件中得到指定的接口
result = componentManager.CreateInstanceByContractID("@mozilla.org/xmlextras/domparser;1",null,
&nsIDOMParser.IID,cast(void**)&DOMParser);
assert(result==0);
//定义待解析的HTML文本串
PRUnichar HtmlStr[]=r"<html><head><title>test_title</title></head><body><al>test</al></body></html>"w;
//定义DOM文档对象接口
nsIDOMDocument DOMDoc;
//使用DOM解析接口解析html文本串,得到DOM文档对象接口
result=DOMParser.ParseFromString(cast(PRUnichar*)HtmlStr,"application/xhtml+xml",&DOMDoc);
assert(result==0);
DOMParser.Release();
/*
//得到文档的类型
nsIDOMDocumentType DocType;
result=DOMDoc.GetName(&DocType);
assert(result==0);
result=DocType.GetInternalSubset(cast(nsAString*)tStr);
assert(result==0);
writefln("Doc Type=: %s", tStr.GetString());*/
//定义DOM节点列表接口
nsIDOMNodeList NodeList;
//定义待解析得到的节点的名字
AString TagName = new AString("title"w);
//解析得到节点列表
result=DOMDoc.GetElementsByTagName(cast(nsAString*)TagName,&NodeList);
assert(result==0);
//定义DOM节点接口
nsIDOMNode Node;
uint Len=0;
//判断节点列表是否为空
result=NodeList.GetLength(&Len);
assert(result==0&&Len!=0);
//从节点列表中得到一个节点
result=NodeList.Item(0,&Node);
assert(result==0);
NodeList.Release();
//得到这个节点的名字
result=Node.GetNodeName(cast(nsAString*)tStr);
assert(result==0);
//显示这个节点的名字
wchar wStr[]=tStr.GetString();
Len=wStr.length;
writefln("Node Name =: %s", wStr);
//再定义一个节点接口,用于表示子节点
nsIDOMNode cNode;
//得到这个节点的子节点
result=Node.GetFirstChild(&cNode);
assert(result==0);
//得到子节点的值
result=cNode.GetNodeValue(cast(nsAString*)tStr);
assert(result==0);
cNode.Release();
//显示这个子节点的值
wStr=tStr.GetString();
writefln("Node Value=: %s", wStr);
//释放所有用过的接口
Node.Release();
DOMDoc.Release();
componentManager.Release();
//关闭xpcom环境
result = NS_ShutdownXPCOM(null);
assert(result==0);
}
看上去好像很繁琐,但等D的异常风格包装完事后,会好看的多!
再次对qiezi的工作表示敬意!为我们提供了在D中使用xpcom的可能!
:)
其他不明的相关事宜,请大家讨论.
这次修改,加入了Release调用.
最终的运行结果是:
Node Name =: title Node Value=: test_title
评论
qiezi
2007-04-28
用browser太浪费了吧。。看一下firefox源代码是怎么使用的。。
h_rain
2007-04-28
都试过了,这个东西在文档上就说了,应该只能解析XML,不能解析HTML.
我打算使用Browser试试吧.
麻烦.
我打算使用Browser试试吧.
麻烦.
qiezi
2007-04-27
应该不用显式地指定nsIDOMHTMLDocument,使用"text/html"作为XML的类型试试。
qiezi
2007-04-27
操作HTML应该用nsIDOMHTMLDocument吧。
h_rain
2007-04-27
再次仔细看了Mozilla的文档,上面说,nsIDOMParser.ParseFromString只能解析标准的XML DOM
...........
看来,还得找其他的组件来解析HTML了...
...........
看来,还得找其他的组件来解析HTML了...
h_rain
2007-04-27
想用上面的代码解析一个大点的文件,结果却发现了问题:
有<script></sctipt>的时候,好像就不好使.
再发现,上面的代码也不行,好像不认识table!!
狂晕...
有<script></sctipt>的时候,好像就不好使.
<html> <head> <title>test</title> </head> <body topMargin="0"> <table width="100%"></table> </body> </html>
再发现,上面的代码也不行,好像不认识table!!
狂晕...
h_rain
2007-04-27
C++接口风格,D接口风格,那就这么定了吧.
D风格里面,对象的复制也是单个对象自己管理自己的引用吧?
这么看确实,nsISupportsD好像就不用再提供AddRef和Release了.
D风格里面,对象的复制也是单个对象自己管理自己的引用吧?
这么看确实,nsISupportsD好像就不用再提供AddRef和Release了.
qiezi
2007-04-27
D风格的nsISupportsD好像就不用再提供AddRef和Release了亚,它的构造函数里接受了一个nsISupports对象,接受时已经是从QueryInterface里AddRef过的,所以只需要在nsISupportsD的析构函数里调用Release就行了。只有进行对象拷贝时才需要显式地调用inner.AddRef和inner.Release。D对象的clone是怎么调用的?我还没用过呢。
qiezi
2007-04-27
Native接口风格好长啊,而且这么也显得好像D不够Native似的。干脆叫C++接口风格和D接口风格算了,反正也确实是这么回事。。
qiezi
2007-04-27
就这么称呼吧。
是不是有黑幕,还是要看一下源码亚,我只是觉得奇怪,如果没有黑幕,它如何知道对象是不是该释放呢?
DMD代码里有许多地方都有COM类型判断,我怀疑就在某处,有时间找找看。
是不是有黑幕,还是要看一下源码亚,我只是觉得奇怪,如果没有黑幕,它如何知道对象是不是该释放呢?
DMD代码里有许多地方都有COM类型判断,我怀疑就在某处,有时间找找看。
h_rain
2007-04-27
晕~
我讨厌黑幕...
:)
我讨厌黑幕...
:)
h_rain
2007-04-27
现在是该好好的定一下称呼了.
那就把目前我的这个例子中的dxpcom接口风格称为"dxpcom的Native接口风格",把待最终实现的D风格包装的接口称为"dxpcom的D接口风格"怎么样?
那就把目前我的这个例子中的dxpcom接口风格称为"dxpcom的Native接口风格",把待最终实现的D风格包装的接口称为"dxpcom的D接口风格"怎么样?
qiezi
2007-04-27
调用XPCOM时,多次调用AddRef或者是过多或过少调用Release都是错误的,使用上的错误不能完全避免。我建议是QueryInterface调用AddRef,包装类的析构里面调用Release,其它地方不调用这2个就不会有麻烦。
用D写XPCOM时,只需要找一个全局的地方保存对象引用防止被GC掉,在引用计数归0时去掉引用就行了,下次GC的时候自然会释放掉,ComObject是这么做的,不过只看到它处理引用计数,没有一个全局的保存对象的东西,那么GC是如何判断该释放掉对象?莫非这方面在DMD里面也有类似IUnknown这样的黑幕?
用D写XPCOM时,只需要找一个全局的地方保存对象引用防止被GC掉,在引用计数归0时去掉引用就行了,下次GC的时候自然会释放掉,ComObject是这么做的,不过只看到它处理引用计数,没有一个全局的保存对象的东西,那么GC是如何判断该释放掉对象?莫非这方面在DMD里面也有类似IUnknown这样的黑幕?
h_rain
2007-04-27
"析构时调用Release说的是我们的D包装类"
我说的也是这个,但如果担心AddRef被反复调用,而导致最终无法正常释放的话,就应该需要一个引用计数,在析构函数里面循环Release.
当然了,如果不提供这个功能的话也是可以的,只是需要程序员仔细的使用AddRef或不使用.
我说的也是这个,但如果担心AddRef被反复调用,而导致最终无法正常释放的话,就应该需要一个引用计数,在析构函数里面循环Release.
当然了,如果不提供这个功能的话也是可以的,只是需要程序员仔细的使用AddRef或不使用.
qiezi
2007-04-27
上面的各个D包装类型后面要加上D的,nsIDOMNode生成出来的是nsIDOMNodeD。
qiezi
2007-04-27
容器类型应该是可以加上opApply的,不过修改idl应该是不行,会造成其它语言兼容问题,修改生成的代码也不好,下次重新生成又要修改,有什么好的办法呢?
还是采取打补丁的方式?像这样:
如果当前接口是nsIDOMNodeList,就产生一个opApply:
还是采取打补丁的方式?像这样:
if classname == "nsIDOMNodeList"
generate_opapply("nsIDOMNode", "length", "item");
如果当前接口是nsIDOMNodeList,就产生一个opApply:
void opApply(void delegate(uint, nsIDOMNode) dg)
{
for(uint _i=0; _i<Length; ++_i)
{
nsIDOMNode node = Item(_i);
dg(_i, node);
}
}
qiezi
2007-04-27
引用
最好把只有一个参数的函数转换为使用返回值
应该是只有一个out参数并且返回类型是void吧,这是idl写的不好造成的。实现应该是可以的。
oldrev
2007-04-27
最好把只有一个参数的函数转换为使用返回值
qiezi
2007-04-27
现在异常封装在调用的时候就是这样的:
这是一个异常风格+D风格包装的例子,完成了几个工作,一是参数类型从nsAString*换成wchar[] path,二检查异常。在一些更复杂的例子里,可能还有接口类型到外覆类型的转换、返回值转换(原来是把返回值生成一个out参数,异常风格将转换成和IDL形式一样的返回值)、数组参数转换(C++版本是转成2个参数)。
这里说的异常风格指的是CheckException检查异常,其实更多的工作应该是D风格的转换,以后统一称为D风格算了。。
void InitWithPath(wchar[] path)
{
scope auto _path = new AString(path);
nsresult result = inner.InitWithPath(cast(nsAString*)_path);
CheckException(result); // 如果不是NS_OK则抛出异常
}
这是一个异常风格+D风格包装的例子,完成了几个工作,一是参数类型从nsAString*换成wchar[] path,二检查异常。在一些更复杂的例子里,可能还有接口类型到外覆类型的转换、返回值转换(原来是把返回值生成一个out参数,异常风格将转换成和IDL形式一样的返回值)、数组参数转换(C++版本是转成2个参数)。
这里说的异常风格指的是CheckException检查异常,其实更多的工作应该是D风格的转换,以后统一称为D风格算了。。
DavidL
2007-04-27
没看代码,我不知道异常的封装是什么样的,听你这么说,如果xpcom设计成异常情况抛出异常就好了。
发表评论
- 浏览: 25249 次
- 性别:

- 来自: 哈尔滨

- 详细资料
搜索本博客
最近加入圈子
最新评论
-
深入分析D语言接口与COM ...
收藏~
-- by tomqyp -
在 Windows 上配置 CodeB ...
能加一下QQ吗?2 下载CodeBlocks的更新包(每夜构建),这个是列表 ...
-- by jy03207715 -
使用Dxpcom进行HTML文本的 ...
用browser太浪费了吧。。看一下firefox源代码是怎么使用的。。
-- by qiezi -
使用Dxpcom进行HTML文本的 ...
都试过了,这个东西在文档上就说了,应该只能解析XML,不能解析HTML. 我打算 ...
-- by h_rain -
使用Dxpcom进行HTML文本的 ...
应该不用显式地指定nsIDOMHTMLDocument,使用"text/html ...
-- by qiezi






评论排行榜