2005年01月31日

前面我们基本结束了界面生成部分,下面开始进入交互部分。

XUL的事件处理方式与HTML中的基本类似。对于需要响应事件的元素,只要在元素中增加相应的事件处理函数即可。如:

<menuitem label=”Close” accesskey=”c” oncommand=”window.close();”/>

 
<button id=”cancel-button” label=”Cancel”
     oncommand=”window.close();”/>

这个例子并未使用自定义的函数,而是直接使用DOM对象的方法进行调用。对于自定义的方法可以在XUL文件中设置script元素,将代码放在script代码中即可。或者在script中设置src属性,指向javascript代码文件。在XUL中目前都是使用javascript来进行程序处理的。

基本可响应的事件可以看原教程。

事件模型

XUL使用与DOM2 Events描述的事件模型一样。(至于DOM2 事件模型到底怎么回事我也没仔细看过,如果需要再了解好了)简单地说,一个事件的发送有两个状态:捕获状态和冒泡状态。在捕获状态,一个事件先发送到document,然后按照元素的分级结构层层传递,直到触发事件的元素。冒泡状态是反方向传递。

在处理路径上,如果事件被某个元素处理,那么事件传递即结束,如果没有被处理,则继续传到下一个元素。如果都没有处理,则缺省的处理被执行。这就意味着,不一定要把事件处理放在触发事件的元素上,而是放在它的父元素中进行处理。

如果一个事件被处理,处理函数应该返回true,如果返回false则表示未被处理。因此,有时可以在处理了事件后,仍然返回false,从而使事件可以继续传递。

你可以使用event对象的target属性来得到触发事件的元素,如:

<window
    onclick=”alert(event.target.tagName); return false;”
    .
    .
    .
>

当你在窗口中点击任何一个元素时,都会引发一个alert对话框,它将显示被点击的元素的名字。

2005年01月28日

模板可以让我们从RDF中自动生成需要的元素。当我们需要做特殊处理时,我们可以通过rule来进行不同的处理。那么前面我们学习了一些rule元素的使用,但那些其实都只是简写。完整的rule元素有三个子元素:conditions, bindings, action。

mozilla在处理的时候,模板生成器会先根据conditions中的条件对资源进行匹配,如果匹配成功,则调用相应的action中的内容进行复制处理。

条件

conditions元素是rule中用来进行匹配使用的条件,它有三个子元素:content, member, triple。

  • content
    只能写一次。它用来将包含模板的元素中的rel所指的起始根对应到一个变量中。如:

    <content uri=”?var”/>

    uri的属性值将对应rel中的根资源。?表示后面的标识符是一个变量。var是变量名,可以随便写。

  • member
    用来映射每条资源的变量。

    <tree id=”citiesTree” datasources=”weather.rdf”
        ref=”http://www.xulplanet.com/rdf/weather/cities”> 
        <template>
            <rule>
                <conditions>
                    <content uri=”?list”/>
                    <member container=”?list” child=”?city”/>
                </conditions>
            </rule>
        </template>
    </tree>

    从本例可以看出list对应http://www.xulplanet.com/rdf/weather/cities。这样container对应list变量,child对应的值放在city变量中。那么content与member给我的感觉就是用来定义变量。content用来定义根变量,child用来定义每条资源。

  • triple
    它是一个三元组,用来定义匹配规则。一个triple由三要素组成:主题(subject), 谓词(predicate), object(目标),这一点我们在讲RDF时讲过。不过这里使用triple是用来检查一条资源是否之定义的规则相匹配。

    <conditions>
        <content uri=”?list”/>
        <member container=”?list” child=”?city”/>
        <triple subject=”?city”
            predicate=”http://www.xulplanet.com/rdf/weather#prediction”
            object=”Cloud”/>
    </conditions>

  • 这里定义了一个triple,它用来检查一条资源的天气是否与目标相一致。主题就是city变量对应的资源,谓词就是http://www.xulplanet.com/rdf/weather#prediction,目标在这里就是”Cloud”。当目标是一个值时,那么做判断处理。但是当它设为一个变量时,如”?pred”,那么处理时就是将对应的值放在pred变量中,同时判断它是否不为空。条件中可以放置多个triple。

那么conditions元素的作用一方面是进行条件的匹配,一方面是将相应的值放在变量中。不过现在还不清楚是否有更复杂的条件判断功能。

内容创建

在匹配成功后,生成器会自动调用action子元素中的内容进行处理。在action中你可以使用conditions中定义的变量。在rule的简单语法中,你使用uri=”rdf:*”来指明内容应该从哪里生成。在全语法中,你应该设置uri为conditions中的变量。通常使用member元素中的child属性所对应的变量。下面是一个完整的例子:

<tree id=”weatherTree” flex=”1″ datasources=”weather.rdf”
    ref=”http://www.xulplanet.com/rdf/weather/cities”>
    <treecols>
        <treecol id=”city” label=”City” primary=”true” flex=”1″/>
        <treecol id=”pred” label=”Prediction” flex=”1″/>
    </treecols>

<template>
    <rule>
        <conditions>
            <content uri=”?list”/>
            <member container=”?list” child=”?city”/>
            <triple subject=”?city”
                predicate=”http://www.xulplanet.com/rdf/weather#name”
                object=”?name”/>
            <triple subject=”?city”
                predicate=”http://www.xulplanet.com/rdf/weather#prediction”
                object=”?pred”/>
        </conditions>
        <action>
            <treechildren>
                <treeitem uri=”?city”>
                    <treerow>
                        <treecell label=”?name”/>
                        <treecell label=”?pred”/>
                    </treerow>
                </treeitem>
           </treechildren>
        </action>
    </rule>
</template>
</tree>

从例子我们可以看出,action元素中,uri=”?city”,而city是在member中的child属性对应的变量。treecell对应的值分别为”?name”和”?pred”。这个例子所对应的wheather.rdf文件在原教程中有,大家可以把它保存到自已的测试目录下,运行看一看。运行结果为:

从例子我们注意到这里没有设置flags=”dont-build-content “,因此这例子的内容不是直接从RDF文件中得到的。如果我们设置flags=”dont-build-content “,那么需要把上面的content元素改为treeitem。大家可以自行测试。

增加额外的绑定

bindings元素中可以定义多个binding元素,那么它的语法与triple很相似,主要的作用就是将信息与变量关联,如:

<bindings>
    <binding subject=”?city”
        predicate=”http://www.xulplanet.com/rdf/weather#temperature”
        object=”?temp”/>
</bindings>

那么它与triple不同之处就是不作判断处理。当指定的谓词不满足时,变量值为空。

2005年01月27日

scanf — 熟悉C的人一定对它不陌生,它可以从一个字符串中读出想要的数据类型的数据到对应的变量中。今天偶然发现有人用 Python 写了一个这样的模块。主页访问  模块下载

它支持大部分scanf的语法,现在提供scanf(formatString), sscanf(inputString, formatString), fscanf(inputFile, formatString)三个函数。举例为:

import scanf
print scanf.sscanf(“/usr/sbin/sendmail – 0 errors, 4 warnings”,
                   “%s – %d errors, %d warnings”)

有兴趣可以下载试一试。

2005年01月25日

Mozilla内置了一些数据源,它们与bookmarks相似,不过字段与可用的起始root可能有所区别。这里我不想多说了,看原教程吧。

那么我真正感兴趣的就是如何生成自已的RDF,但教程中并没有详细的介绍。考虑到RDF可以为列表和树之类的模板提供数据,那么它需要定义结点集,通过seq, bag, alt来定义。而真正的结点是通过description来定义的。这样一个RDF基本上需要定义两种东西:

  • 表示结点集合的seq, bag, alt
  • 表示结点的description

这样我们在使用这个RDF时,datasource即为这个RDF文件的URL,而rel为结点集的某个层次结点,如根结点或某个子结点。通过结点集就可以得到真正的结点数据。

从原教程所提供的RDF可以看出来,每种动物及分类都使用了一个description来定义,最后seq将分类与具体的动物结合起来。在使用模板时,就是从seq级别中选取某个层次作为起始的root进行处理。

不过XML这种格式的文件的确很冗长,如果没有好的工具来支持手工处理会很麻烦。

2005年01月24日

向tree增加数据源

从前面我们了解了从RDF读取数据后,利用模板生成元素有两种生成器,一是内容生成器用于绝大多数元素;二就是树生成器只用于tree元素。下面我们就介绍树和它的模板。象同其它的元素一样,你需要在tree元素中加入datasource和rel两个属性。下面一个例子是把history作为数据源:

<tree datasources=”rdf:history” ref=”NC:HistoryByDate”
          flags=”dont-build-content”>

前面我们已经知道,树生成器可以不生成每行数据,而是直接从数据源生成。上例的flags设为”dont-build-content”就是表示使用树生成器。如果没有flags属性,将会使用内容生成器。下面是一个完整的例子:

<tree id=”my-tree” flex=”1″
       datasources=”rdf:files” ref=”file:///” flags=”dont-build-content”>
  <treecols>
    <treecol id=”Name” label=”Name” primary=”true” flex=”1″/>
    <splitter/>
    <treecol id=”Date” label=”Date” flex=”1″/>
  </treecols>

    <template>
      <rule>
        <treechildren flex=”1″>
          <treeitem uri=”rdf:*”>
            <treerow>
              <treecell label=”rdf:http://home.netscape.com/NC-rdf#Name”/>
              <treecell label=”rdf:http://home.netscape.com/WEB-rdf#LastModifiedDate”/>
            </treerow>
          </treeitem>
        </treechildren>
      </rule>
    </template>
</tree>

这个例子很有趣。在开始时,我一运行它,内容是空的,后来我仔细地看了一下。原来是被前面的history给误导了,因为这个例子与history根本没有关系。它的datasource是rdf:files,说明要处理的是文件系统。rel为file:///说明是从根目录开始。之所以出不来结果是因为我是在Windows XP下运行的,而这个例子是在Linux下运行的。只要我把rel写为正确的file:协议即可。如:file:///d:/newedit/,那么在我的机器上的运行结果为:

这个例子生成一个两列的树,第一列为文件或目录的名字,第二列为最后修改时间。注意uri放置的地方,它放在了treeitem中,这样模板将从这里开始生成。而整个模板的开始元素是treechildren,但由于treechildren在treeitem外面,因此它只用生成一次。这正是我们需要的,我们不需要多次生成treechildren。模板中使用了rule,但由于没有任何属性因此它会匹配全部数据。同时我们还可以看到当碰到一个目录时,树生成器也可以正确处理子元素。另外就是,更深层的结点不需要时并未创建,而是当用户展开时才真正创建。从这几点,我的确体会以Mozilla在这些方面的易用性和高效。以前做过的GUI哪一个不是自已一个个结点插入,如果有子结点还要考虑创建子结点,同时性能还很难保证。就是想实现与Mozilla相同的效率处理方式,但也要自已花费大量的编程时间。

列排序

试了上面的例子之后,你会发现列数据是无序的(在xp上好象已经排好顺序了,原教程是这样说的,我想可能是在Linux下吧)。树在从数据源生成数据的时间可以对数据进行排序。用户还可以在列头上点击进行排序。这种排序的特性,对于有静态内容的树来说是无效的。因此上面的flags属性还是很重要的。

有三个与排序有关的属性:

  • sort
    属性应设为一个RDF属性,用来指明排序所用的关键字。如果在某一列设置了这个属性,那么这一列将进行排序。
  • sortDirection
    用来指明缺省的排序的方向,有三个值:ascending(升序)、descending(降序)、natural(自然顺序)。
  • sortActive
    当某一列sortActive属性设置为”true”时,缺省将进行排序。

一般使用上面三个属性已经足够了,但通常还要使用样式类sortDirectionIndicator来指明哪一列正在被排序。正在被排序的列会出现一个三角型表示排序的方向。下面是一个上面的例子的修订版:

    <treecols>
      <treecol id=”Name” label=”Name” flex=”1″ primary=”true”
                class=”sortDirectionIndicator” sortActive=”true”
                sortDirection=”ascending”
                sort=”rdf:http://home.netscape.com/NC-rdf#Name”/>
      <splitter/>
      <treecol id=”Date” label=”Date” flex=”1″ class=”sortDirectionIndicator”
               sort=”rdf:http://home.netscape.com/WEB-rdf#LastModifiedDate”/>
    </treecols>

你也可以使用persist属性来保存某些属性的值。

对于rule元素还可以指定特殊的属性来匹配特殊的情况,如:

  • iscontainer
    如果设为”true”将用来匹配哪些拥有子元素的资源。例如象文件夹。
  • isempty
    如果设为”true”将用来匹配没有子结点的资源。

上面这两个属性是相反的。一个资源既可能是一个容器也可能没有子结点。不过它与一个资源不是一个容器是不同的。

大赛已经过去了,还是静下心来先学好XUL吧 :)

元素组装

那么在前面我们学习了生成列表、树这样的元素的生成,但是手工生成的。其中我还谈到可以通过RDF来生成,这对于大量数据是一个很方便的方式。这些数据或者来源于RDF文件,或者来源于内部的数据源(datasource)。Mozilla提供了象bookmarks, history和邮件信息这样的数据源。

为了从RDF中得到数据,我们需要提供第一个元素的模板(template)。这一点非常象xslt,通过提供模板,其实就是一个搜索条件,可以把目标XML文件中的满足条件的元素找到,不过xslt提供类似于循环、分支这样的操作,功能很强,与XUL的模板可能不太一样(反正现在是没见着)。

为了生成一个模板你需要使用template标签,它的内容就是要生成的元素。template需要放在一个容器内,如tree中。

下面让我们通过一个例子来学习。这个例子演示了将 bookmarks 中的顶层书签生成按钮的过程。

为了测试这个例子,你需要按chrome的要求配置好。不过前面我所做的任何测试都是在chrome下进行的,因此是没什么问题的。

示例代码为:

<vbox datasources=”rdf:bookmarks” ref=”NC:BookmarksRoot” flex=”1″>
  <template>
    <button uri=”rdf:*” label=”rdf:http://home.netscape.com/NC-rdf#Name”/>
  </template>
</vbox>

上面的例子很有意思,如果你直接在命令行上运行。那么刚开始什么都没有。但一旦你打开浏览器,你会发现窗口增加了许多按钮都是与bookmarks相对应的。如果你在浏览器中增加或删除,这个窗口也会立刻发生变化。你也可以直接打开浏览器,在定位框中直接输入chrome链接,窗口内容就会显示在浏览器中。

从上面的例子我们可以看到,vbox就是一个容器,datasources属性用来设置数据源,通过值可以想象就是bookmarks。这同时也说明它是由Mozilla提供的,如果想使用其它的RDF可以使用不同的URL,如:

<box datasources=”chrome://zoo/content/animals.rdf”
     ref=”http://www.some-fictitious-zoo.com/all-animals”>

同时你还可以一次指定多个数据源,只要把它们用空格分开。

rel属性用来指明数据是从数据源何处来的。上面的例子中,NC:BookmarksRoot用来指明bookmarks的根元素。针对不同的数据源你可以使用不同的值。如果你使用自已的RDF文件,那么这个值就与Seq, Bag, Alt中的about属性值相对应。

通过加入datasources和rel这两个属性,就可以在元素内部通过模板来生成元素了。但是模板中的元素声明与平常有些不同。如上面例子中的button,增加了uri属性,label属性也不太一样。

在模板中的元素属性值如果是以rdf:开头的,表明这个值应该是从数据源来的。rdf:后面的值表示数据源中的属性名。

元素中的uri属性用来指明生成的内容从何处开始。在此之前的内容(即这个元素之外的其它内容)只生成一次,元素内部的内容会根据每个资源生成一次。下面是另一个例子:

<vbox datasources=”rdf:bookmarks” ref=”NC:BookmarksRoot” flex=”1″>
  <template>
    <vbox uri=”rdf:*”>
      <button label=”rdf:http://home.netscape.com/NC-rdf#Name”/>
      <label value=”rdf:http://home.netscape.com/NC-rdf#URL”/>
    </vbox>
  </template>
</vbox>

通过这个例子我们可以看出,这个模板将生成一个vbox的集合,每个vbox又有一个按钮和一个标签。

模板生成过程

当一个元素拥有datasource属性时,表示它的内容希望是从一个模板来的。当存在这个属性时,会在这个元素上增加一个builder的对象,这个对象负责从模板生成元素。在Javascript中你可以使用builder属性来访问这个builder对象。一般你不会使用它,通常是当自动生成有问题时,才会使用这个对象来重新生成内容。

有两种不同的生成器,一种是内容生成器用于绝大多数元素;另一种是树生成器只用于tree元素。

内容生成器会取出template元素中的内容,根据每行数据对它进行复制。在生成之后,你可以使用DOM来访问生成的元素,template元素本身不会显示出来,但它在DOM中仍然是存在的。每个从模板生成的元素都有一个与资源相对应的id属性。

内容生成器总是从放置uri=”rdf:*”的地方开始生成。从包含uri属性的元素算起,在此元素这外的元素只生成一次。如:

<template>
  <hbox>
    <label uri=”rdf:*” value=”rdf:http://home.netscape.com/NC-rdf#Name”/>
  </hbox>
</template>

上例中,uri=”rdf:*”是放在label中的,因此在label之外的hbox只生成一次,而label则根据resource的个数生成多个。

而对于树生成器,它并不直接生成DOM元素,而是当需要时直接从RDF数据源得到数据。

Rules

上面的例子对所有的资源都是相同的处理,而有时不同的资源需要不同的处理,这时我们可以使用rule元素来处理。从上面的bookmarks的例子我们可以看到,有些是书签,有些是分隔用的线(我的示例就是空白),那么我们可以分别对待:

<?xml version=”1.0″?>
<?xml-stylesheet href=”chrome://global/skin/” type=”text/css”?>
<window
    id=”findfile-window”
    title=”Find Files”
    orient=”horizontal”
    xmlns:rdf=”http://www.w3.org/1999/02/22-rdf-syntax-ns#” 
    xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul”>

 <vbox datasources=”rdf:bookmarks” ref=”NC:BookmarksRoot” flex=”1″>
   <template>

    <rule rdf:type=”http://home.netscape.com/NC-rdf#BookmarkSeparator”>
     <spacer uri=”rdf:*” height=”16″/>
    </rule>

    <rule>
      <button uri=”rdf:*” label=”rdf:http://home.netscape.com/NC-rdf#Name”/>
    </rule>
 
  </template>
 </vbox>
 
 </window>

第一条用来把分隔线生成空白。一个rule的所有属性将用来匹配条件。第二条因为没有任何属性,因此对每个元素都进行处理。在这个例子中要特别注意上面红字的内容,它引入了一个新的名字空间。原来我想就拷贝window中的内容到以前的例子中即可,但生成结果与原教程不同。仔细看了代码才发现,它引入了新的名字空间,加入后就可以了。测试效果为:

那么rule之间应该是依次执行,如果当前rule匹配成功,则处理完毕后跳到下一条数据。如果不成功,则跳到下一个rule再继续进行处理。

为什么上面我们要引入新的名字空间呢?因为我们使用rdf:type要匹配的条件并不在xul名字空间内,因此需要把http://home.netscape.com/NC-rdf#BookmarkSeparator所在的名字空间引入。

2005年01月22日

2004年的中国开源软件竞赛今天晚上结束了。一共三十件作品,金奖2名,银奖4名,铜奖6名,其它也均有奖。NewEdit在这次比赛中的名次为银奖。今天真的很高兴!家里人也非常高兴。希望这次活动可以更好的宣传NewEdit,也希望我可以把它做得更好,更希望大家有更好的作品可以参加今后可能举办的开源大赛。

比赛从20号开始抽签,21号开始现场报告、演示和问题回答,今天颁奖。21号本来是下行倒数第三个答辩,但时间让我算错了,给调到最后一个,呵呵,想不到还犯这样的错误。

拍了一些照片,不过离得较远,光线有些差。

倪光南院士

嘉宾

我了

2005年01月19日

下面我们进入复杂的RDF知识的学习,说实在的,学了半天也只明白个大概,而且我还不能保证我理解得一定正确,因此建议大家多找资料学习,如果有心得一定分享一下啊。这里是一个链接,放在Mozilla中,它是一系列的文章。阅读这里

RDF介绍

什么叫RDF — Resource Description Framework(资源描述框架)

它是用来做什么的呢?

我的理解就是描述资源之间关系用的一种模型。那么它的存储表示其实有多种,我们常用的是XML格式的表示,因此也称为RDF/XML。也就是说RDF与XML不是一个东西,而RDF/XML只是RDF的一种表示的格式。在RDF中有两种东西,一种是资源(resource),一种是文本(literal)。文本相当于具体的字符串,而资源相当于是一个抽象概念。那么RDF主要就用来描述由这两者对象构成的世界中个体的关系。

RDF怎么进行描述呢?它使用Triple方法,可以称为三元组的方法,它们是:主语(或主题)、谓语(或谓词)和宾语(或目标)。其中主语与宾语就是资源。而谓语是两个资源之间的关系。举一个例子:

<http://www.xulplanet.com/rdf/people/Sandra>  ->  name     ->  Sandra

这里<http://www.xulplanet.com/rdf/people/Sandra>就是resource,它使用URI的表示方法,它只是一个名字,怎么起都行,使用尖括号括起来。Sandra就是literal(文本)。name就是关系。上面的意思就是<http://www.xulplanet.com/rdf/people/Sandra>的名字叫Sandra。三者之间使用->连起来。当然这并不是XML文件,这只是一种表示triple关系的方法。那么RDF基本上就是通过这种三元表示法来描述资源之间的关系的。注意,因为泛泛的资源(Resource)与具体的类型(resource)单词一样,不好区分。这样在描述具体的资源的类型时我使用英文resource,在泛泛谈资源而不区分它的类型时我就用中文。

使用URI来表示resource并不表示在处理RDF时,要从相应的链接得到数据,它只是一个标识符。 如果在一个RDF中出现一样的URI,那就表示是同一个resource。使用triple可以表示从resource到literal和resource到resource的关系。有时,谓词也可以使用resource的表示方法。

有时我们需要表示一个对象是属于某一类的情况,即实例与类的关系,那么我们可以使用rdf:type这个谓词来定义实例与类的关系,如:

<http://www.xulplanet.com/rdf/people/Sandra>  ->  rdf:type  ->
      http://xmlns.com/wordnet/1.6/Person

上面就表示Sandra是一个Person。

有时我们还需要表示一类事物,把它们组织成列表。那么RDF提供了seq、bag、alt来定义。seq为顺序列表,bag为无序表,alt定义了多个备选值,但应该只有一个可用。

我不想在这里讲得过细了,让我们看一看在RDF/XML中的一些规范吧。

RDF/XML

前面我已经说过,RDF/XML只算是RDF的一种表示或方言,但也是我们常用的表示方法。针对上面我们所讲的资源表示与关系表示,我们分别举例来说明如何使用。

使用RDF/XML要按XML的要求声明XML的相应的头和名字空间:

<?xml version=”1.0″?>

<rdf:RDF xmlns:rdf=”http://www.w3.org/1999/02/22-rdf-syntax-ns#”
         xmlns:people=”http://www.xulplanet.com/rdf/people/”>

</rdf:RDF>

其它的内容就放在这里面。

resource到literal三元组

  <rdf:Description rdf:about=”http://www.xulplanet.com/rdf/people/Sandra”
                   people:name=”Sandra”/>

可以看出,一个Description描述了一个三元组。resouce为它的rdf:about属性值。literal为people:name的属性值。而谓词就是people:name。这样我们了解了,在RDF/XML中三元组可以使用属性来描述。属性名可能表示资源的类型和关系。而属性值可能表示革resource的URI或literal的字符串。

因为一个resource可能与其它的资源之间有多个关系,那么可以把这些关系简单地写在一起,如:

<rdf:Description rdf:about=”http://www.xulplanet.com/rdf/people/Sandra”
                 people:name=”Sandra”
                 people:gender=”female”/>

这实际上定义了两个关系,名字和性别关系。

resource到resource三元组

例如:

<rdf:Description rdf:about=”http://www.xulplanet.com/rdf/people/Sandra”
                 people:name=”Sandra”>
  <people:sibling rdf:resource=”http://www.xulplanet.com/rdf/people/Kevin”/>
</rdf:Description>

这里面定义了两个关系,一个是people:name,还有一个是people:sibling。而rdf:resource定义的是目标resource。

从这里我们还可以看到,三元组还可以使用子元素来描述。而且多种关系也可以放在一起混合进行表示:有的用属性表示,有的用子元素进行表示。非常灵活。当然,尽可能以简洁清晰为好。

还要提醒的是rdf:about表示主题,而rdf:resource表示目标。

type关系

前面说了rdf:type表示实例与类之间的关系,就是一个实例是属于某个类别。例如:

<rdf:Description rdf:about=”http://www.xulplanet.com/rdf/people/Sandra”
  <rdf:type resource=”http://xmlns.com/wordnet/1.6/Person”/>
</rdf:Description>

这里就不多说了。rdf:type是RDF内置的谓词。

列表类型关系

有三种列表形式:seq, bag, alt,举例如下:

<rdf:Seq rdf:about=”http://www.xulplanet.com/rdf/people/KarensKids”>
  <rdf:_1 rdf:resource=”http://www.xulplanet.com/rdf/people/Sandra”/>
  <rdf:_2 rdf:resource=”http://www.xulplanet.com/rdf/people/Kevin”/>
  <rdf:_3 rdf:resource=”http://www.xulplanet.com/rdf/people/Jack”/>
</rdf:Seq>

那么这里使用了rdf:_1来表示顺序。还有一种简化的方法就是把rdf:_1改为rdf:li,如:

<rdf:Seq rdf:about=”http://www.xulplanet.com/rdf/people/KarensKids”>
  <rdf:li rdf:resource=”http://www.xulplanet.com/rdf/people/Sandra”/>
  <rdf:li rdf:resource=”http://www.xulplanet.com/rdf/people/Kevin”/>
  <rdf:li rdf:resource=”http://www.xulplanet.com/rdf/people/Jack”/>
</rdf:Seq>

不过,你要是使用RDF Api的话你得不到li这个谓词,而你只能得到相应的数值。

由于Mozilla使用的RDF比较早,它与标准的处理有区别。一个就是about和resource属性不需要有rdf:的限定。另外就是对于rdf:type,在Mozilla是使用rdf:instanceOf。

Spam现在好象是越来越多,而且如影随形,你到哪里它到哪里。

比较早我就申请了263信箱,随着信箱的公开垃圾邮件开始有了,以至于后来一天就几十封,特别严重的时候,垃圾邮件都带有病毒附件,经常有170多K,于是我只好在263的邮箱中增加了过滤器,大于150K的邮件全部不收,但并未减少其它垃圾邮件的产生。

就这样,我有了gmail的邀请,只用它来订阅邮件列表,我想邮件列表多少安全些吧。但照样可以收到垃圾邮件,只不过由于我未公开,因此每天数量不多,还算是好的。而且gmail有垃圾邮件过滤的功能,功能还不错。不过邮件列表也不安全,有人专门会注册邮件列表来发垃圾邮件,这种情况我已经见过多次了。

近来啄木鸟wiki上的垃圾攻击也是越来越多,只要有时间我就会上去看一看,目的已经主要是看有没有垃圾信息了。好在wiki可以恢复旧版本,恢复起来还算方便。wiki中我想应该加上权限了,只允许某些人编辑,虽然远离wiki的宗旨,但不会有垃圾信息的攻击,这也是不得以而为之的事。只不过,我做不了这事,只有等了。

我的Blog最近也是常受垃圾回复的攻击,而且我发现,好象就那么几个网站,似乎经常只对我的某几个贴子作回复。现在几乎每天都有。已经有人建议donews增加防止垃圾攻击的手段了,要不就加上认证码。好在我经常上网,发现就删除了。但突然我想,如果有人编一个程序,而且donews又没有认证机制,那么它可以不停地发,多线程地发,总有一天donews的硬盘有撑破的可能。

而且有些垃圾信息看上去还真不象,它们了解你的Blog内容,可以针对你的Blog作一些发言,只不它留言者的地址是与你的内容无关的商业链接。现在搞得我都不知道是删好还是不删好,再看一看吧。反正donews上删东西还方便。这种情况在我看国外的Blog也是有的。

现在垃圾制造者的心思与手段也越来越高明,但我们的服务提供者还没有跟上步伐,希望快快改进,这对我们大家都是好事。

xpcom是Mozilla中的一种组件技术,它可以允许Javascript调动本地对象,以完成Javascript所不具备的功能。那么它也有一个 Python 绑定,叫PyXPCOM,它是由ActiveState(发布ActiveState Python的公司)开发的,现在源代码已经并入Mozilla中。访问地址 

不过Mozilla并未在安装包中提供PyXPCOM的二进制包,因此,如果你想安装,那么要自已编译。(是真的吗?)这几天我尝试着编译Mozilla,但工具不全,因此一直还未成功。不过,在网上我发现一个叫mozpython的网站,它提供了一个叫MozPython的模块,可以在Mozilla中调用Python程序,不过我还是不清楚到底有什么用。因为它所演示的Python代码并不是嵌入到XUL页面中,而是独立的 Python 程序,它的执行结果要输出为HTML格式,然后供Mozilla进行显示。如果只把Mozilla当做 Python  代码的一个调用器还有点用,但现在我想实现的是用Python进行Mozilla的开发,象MozPython这样的效果想不出有什么用。希望Mozilla快点支持Python脚本的执行。不讲这个了,还是说PyXPCOM的下载吧。在MozPython的网站我发现了作者已经编译了几个版本,不过最新的是1.7版的。可以从这里下载。下载完的文件名是PyXPCOM_1.7_2.3_win32.zip。虽然版本有点低(我用的是1.7.5),但为了学习就无所谓了。怕有版本的问题,我还专门下载和安装了Mozilla 1.7版本。

安装PyXPCOM的经历并不轻松,安装说明在ActiveState网站上,可以阅读这里。不过它是从编译开始讲,我就只讲我是如何装的吧。

在讲述如何安装之前还要向大家交待一下:GRE。这里可不是出国考研要考的GRE英语。它是Gecko Runtime Environment的简称。Gecko就是Mozilla产品系统所用的引擎。那么大家可以读这篇文章来了解一下GRE的知识。那么它的作用就是将最小运行环境作为象Java的运行环境(JRE)一样的效果,公共的东西大家共享,这样可以减少安装所要的空间,便于维护。

安装XPCOM组件,有一个注册的步骤,就是要执行regxpcom.exe这个程序。但是在Mozilla 1.7下(它在Mozilla的安装目录下)如果你直接执行regxpcom.exe,那么很有可能不会成功,会报告:

Can not initialize XPCOM Glue
Can not aquire component registrar

这是为什么?我查了半天的资料(向大家提供一个邮件列表归档的网站很不错Mail Archive,其中我找到了mozilla.xpcom邮件列表)才大概明白,regxpcom.exe的执行需要有xpcom.dll才可以。但是在我的Mozilla安装目录下并没有。这是怎么回事,难到是Mozilla根本不包括这个东西吗?其实它就是放在GRE中的。那么这个GRE目录在我的机器上是:

C:\Program Files\Common Files\mozilla.org\GRE

它有一个子目录是跟版本相一致的。那么在这个目录下你会找到所有想要的东西。(我发现Mozilla越学东西越多,学习曲线是否有些太陡了吧。)那么把xpcom.dll所在的目录加入PATH环境变量中就可以了。在我的机器上是:

MOZ_GRE=C:\Program Files\Common Files\mozilla.org\GRE\1.7_2004061609
PATH=%PATH%;%MOZ_GRE%

那么regxpcom已经可以执行了。下一步就是把下载的PyXPCOM_1.7_2.3_win32.zip解压到上面这个目录下。那么因为PyXPCOM有Python代码,因此需要Python来执行,并且可以被Python进行调用。因此还要把解开后的python子目录加入到PYTHONPATH中。在我的机器上就是:

PYTHONPATH=%MOZ_GRE%\python

然后,我的做法是把Mozilla安装目录下的components子目录中的compreg.dat和xpti.dat文件删除。启动Mozilla,这样就会自动进行注册。这样就应该安装完毕了,剩下的找些例子试一试吧。

下面我小结一下:

  1. 如果不自行编译那么先要下载PyXPCOM
  2. 把GRE路径加进PATH中
  3. 解压PyXPCOM包到GRE目录中
  4. 把GRE的python目录加入到PYTHONPATH
  5. 删除Mozilla安装目录/components下的compreg.dat和xpti.dat文件
  6. 重启Mozilla

有些步骤也是多次试出来的,希望以后的Mozilla版本能够内置这一组件,简化操作。有问题欢迎交流。