`
h_rain
  • 浏览: 120829 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
文章分类
社区版块
存档分类
最新评论

使用Dxpcom进行HTML文本的DOM解析

阅读更多
    开帖纪念,dxpcom终于可以使用了.
    找了好半天,才知道怎么使用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
分享到:
评论
31 楼 h_rain 2009-06-27  
karlzheng 写道
请问楼主:import mozilla.xpcom.nsXPCOM 的库从哪里得来的?

http://code.google.com/p/dxpcom/
这是当时qiezi发起的一个项目,目前基本停滞了.
因为xpcom也没有一个稳定的发布版本,变动太大了,文档不全.
30 楼 karlzheng 2009-06-15  
请问楼主:import mozilla.xpcom.nsXPCOM 的库从哪里得来的?
29 楼 qiezi 2007-04-28  
用browser太浪费了吧。。看一下firefox源代码是怎么使用的。。
28 楼 h_rain 2007-04-28  
都试过了,这个东西在文档上就说了,应该只能解析XML,不能解析HTML.
我打算使用Browser试试吧.
麻烦.
27 楼 qiezi 2007-04-27  
应该不用显式地指定nsIDOMHTMLDocument,使用"text/html"作为XML的类型试试。
26 楼 qiezi 2007-04-27  
操作HTML应该用nsIDOMHTMLDocument吧。
25 楼 h_rain 2007-04-27  
再次仔细看了Mozilla的文档,上面说,nsIDOMParser.ParseFromString只能解析标准的XML DOM
...........

看来,还得找其他的组件来解析HTML了...
24 楼 h_rain 2007-04-27  
想用上面的代码解析一个大点的文件,结果却发现了问题:
有<script></sctipt>的时候,好像就不好使.
<html>

<head>
	<title>test</title>
</head>

<body topMargin="0">
	<table width="100%"></table>
</body>

</html>

再发现,上面的代码也不行,好像不认识table!!

狂晕...
23 楼 h_rain 2007-04-27  
C++接口风格,D接口风格,那就这么定了吧.

D风格里面,对象的复制也是单个对象自己管理自己的引用吧?
这么看确实,nsISupportsD好像就不用再提供AddRef和Release了.
22 楼 qiezi 2007-04-27  
D风格的nsISupportsD好像就不用再提供AddRef和Release了亚,它的构造函数里接受了一个nsISupports对象,接受时已经是从QueryInterface里AddRef过的,所以只需要在nsISupportsD的析构函数里调用Release就行了。只有进行对象拷贝时才需要显式地调用inner.AddRef和inner.Release。D对象的clone是怎么调用的?我还没用过呢。
21 楼 qiezi 2007-04-27  
Native接口风格好长啊,而且这么也显得好像D不够Native似的。干脆叫C++接口风格和D接口风格算了,反正也确实是这么回事。。
20 楼 qiezi 2007-04-27  
就这么称呼吧。

是不是有黑幕,还是要看一下源码亚,我只是觉得奇怪,如果没有黑幕,它如何知道对象是不是该释放呢?

DMD代码里有许多地方都有COM类型判断,我怀疑就在某处,有时间找找看。
19 楼 h_rain 2007-04-27  
晕~
我讨厌黑幕...
:)
18 楼 h_rain 2007-04-27  
现在是该好好的定一下称呼了.
那就把目前我的这个例子中的dxpcom接口风格称为"dxpcom的Native接口风格",把待最终实现的D风格包装的接口称为"dxpcom的D接口风格"怎么样?
17 楼 qiezi 2007-04-27  
调用XPCOM时,多次调用AddRef或者是过多或过少调用Release都是错误的,使用上的错误不能完全避免。我建议是QueryInterface调用AddRef,包装类的析构里面调用Release,其它地方不调用这2个就不会有麻烦。

用D写XPCOM时,只需要找一个全局的地方保存对象引用防止被GC掉,在引用计数归0时去掉引用就行了,下次GC的时候自然会释放掉,ComObject是这么做的,不过只看到它处理引用计数,没有一个全局的保存对象的东西,那么GC是如何判断该释放掉对象?莫非这方面在DMD里面也有类似IUnknown这样的黑幕?
16 楼 h_rain 2007-04-27  
"析构时调用Release说的是我们的D包装类"
我说的也是这个,但如果担心AddRef被反复调用,而导致最终无法正常释放的话,就应该需要一个引用计数,在析构函数里面循环Release.

当然了,如果不提供这个功能的话也是可以的,只是需要程序员仔细的使用AddRef或不使用.
15 楼 qiezi 2007-04-27  
上面的各个D包装类型后面要加上D的,nsIDOMNode生成出来的是nsIDOMNodeD。
14 楼 qiezi 2007-04-27  
容器类型应该是可以加上opApply的,不过修改idl应该是不行,会造成其它语言兼容问题,修改生成的代码也不好,下次重新生成又要修改,有什么好的办法呢?

还是采取打补丁的方式?像这样:

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);
    }
}
13 楼 qiezi 2007-04-27  
引用
最好把只有一个参数的函数转换为使用返回值

应该是只有一个out参数并且返回类型是void吧,这是idl写的不好造成的。实现应该是可以的。
12 楼 oldrev 2007-04-27  
最好把只有一个参数的函数转换为使用返回值

相关推荐

Global site tag (gtag.js) - Google Analytics