凌华 的个人资料张凌华照片日志列表更多 工具 帮助

日志


3月22日

Delphi 中的XML Data Binding . 用于SOAP的好方法

Delphi 6 含有许多更新更强的XML支持功能,增加了XML文件编程,XML数据绑定向导,XML映象和BizSnap(SOAP/XML Web服务)。我在上一篇文章论述了Delphi 6中的XML文件编程(XML Document Programming)。本文是三篇论述Delphi 6中XML功能系列文章的第二篇,论述Delphi 6中的XML数据绑定(XML Data Binding)。

XML文件编程
XMLDocument组件让我们能够遍历和编辑XML文件。但是在上一篇文章中我提到了,我们只能与无类型节点打交道,必须记住节点元素的名字。这意味着无法进行实时编译调试!幸亏的是,如果Delphi只能处理这样简单的问题就不成其为Delphi了。运用XML的内容相关结构可以做更高级的应用,这就是Delphi 6的XML数据绑定向导(XML Data Binding Wizard)。

XML数据绑定
在Delphi 6的模块仓库(Object Repository)中可以找到XML数据绑定向导(XML Data Binding Wizard)。程序员能够用它生成相应的接口和类来访问与修改XML文件数据,诸如ClientDataSetXML数据,ADO XML数据,其它XML文件数据(如我们在前文用到的Clinic.xml,本文继续使用这个简单的XML文件作示例)。

现在开始吧,启动Delphi 6,在主菜单上选择File | New - Other,然后在仓库中选择XML Data Binding,如图1所示。

向导有三个页面。第一页定义XML纲(Schema)或XML文件(本例用Clinic.xml),如图2所示。
在资源输入框内输入XML纲(Schema)或XML文件。“选项”(Options)对话框定义编码选项和数据类型映射关系(Data Type map)。以后我们还会谈到这些选项。

向导的第二页显示了树结构和节点数据类型(亦即向导生成了些什么样的代码)。图3可以看到我的XML文件结构。
可以看到XML文件里描述的嵌套节点(ClinicsType与ClinicType)和单节点(String)。这时可以打开选项(Options)对话框(图4),修改编码(比如修改前缀)和数据类型映射。

向导的第三页显示生成的相应接口和类。可以把这些结果保存到文件(例如生成Clinic.xdb)。
结果(存储为Clinic.xdb文件)显示如下。我们得到一个ClinicsType类型的Clinics元素,其中包括ClinicType类型的Clinic系列元素。

  <?xml version="1.0"?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xdb="http://www.borland.com/schemas/delphi/6.0/XMLDataBinding">
    <xs:element name="Clinics" type="ClinicsType"/>
    <xs:complexType name="ClinicsType">
      <xs:annotation>
        <xs:appinfo xdb:docElement="Clinics"/>
      </xs:annotation>
      <xs:sequence>
        <xs:element name="Clinic" type="ClinicType" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
    <xs:complexType name="ClinicType">
      <xs:sequence>
        <xs:element name="Title" type="xs:string"/>
        <xs:element name="Date" type="xs:string"/>
        <xs:element name="Topics" type="xs:string"/>
      </xs:sequence>
      <xs:attribute name="No" type="xs:string"/>
    </xs:complexType>
  </xs:schema>

文件同时定义ClinicType类型的Clinic元素包含一系列字符串元素(Title, Date和Topics)。

生成代码
向导生成的代码可以直接在应用中使用。不幸的是,Delphi 6有时会产生“非法操作”的出错信息。重新执行一遍,它又能工作了。
以下是生成的代码(Clinic.pas):

  {****************************************************}
  {                                                    }
  {              Delphi XML Data Binding               }
  {                                                    }
  {         Generated on: 2001/11/07 00:37:00          }
  {       Generated from: D:D6ClinicsrcClinic.xml   }
  {   Settings stored in: D:D6ClinicsrcClinic.xdb   }
  {                                                    }
  {****************************************************}
  unit Clinic;
  interface
  uses xmldom, XMLDoc, XMLIntf;

  type

  { Forward Decls }

    IXMLClinicsType = interface;
    IXMLClinicType = interface;

  { IXMLClinicsType }

  IXMLClinicsType = interface(IXMLNodeCollection)
    ['{06723E03-662D-11D5-81CE-00104BF89DAD}']
    { Property Accessors }
    function Get_Clinic(Index: Integer): IXMLClinicType;
    { Methods & Properties }
    function Add: IXMLClinicType;
    function Insert(const Index: Integer): IXMLClinicType;
    property Clinic[Index: Integer]: IXMLClinicType
      read Get_Clinic; default;
  end;

  { IXMLClinicType }

  IXMLClinicType = interface(IXMLNode)
    ['{06723E04-662D-11D5-81CE-00104BF89DAD}']
    { Property Accessors }
    function Get_No: WideString;
    function Get_Title: WideString;
    function Get_Date: WideString;
    function Get_Topics: WideString;
    procedure Set_No(Value: WideString);
    procedure Set_Title(Value: WideString);
    procedure Set_Date(Value: WideString);
    procedure Set_Topics(Value: WideString);
    { Methods & Properties }
    property No: WideString read Get_No write Set_No;
    property Title: WideString read Get_Title write Set_Title;
    property Date: WideString read Get_Date write Set_Date;
    property Topics: WideString read Get_Topics write Set_Topics;
  end;

  { Forward Decls }

    TXMLClinicsType = class;
    TXMLClinicType = class;

  { TXMLClinicsType }

  TXMLClinicsType = class(TXMLNodeCollection, IXMLClinicsType)
  protected
    { IXMLClinicsType }
    function Get_Clinic(Index: Integer): IXMLClinicType;
    function Add: IXMLClinicType;
    function Insert(const Index: Integer): IXMLClinicType;
  public
    procedure AfterConstruction; override;
  end;

  { TXMLClinicType }

  TXMLClinicType = class(TXMLNode, IXMLClinicType)
  protected
    { IXMLClinicType }
    function Get_No: WideString;
    function Get_Title: WideString;
    function Get_Date: WideString;
    function Get_Topics: WideString;
    procedure Set_No(Value: WideString);
    procedure Set_Title(Value: WideString);
    procedure Set_Date(Value: WideString);
    procedure Set_Topics(Value: WideString);
  end;

  { Global Functions }

  function GetClinics(Doc: IXMLDocument): IXMLClinicsType;
  function LoadClinics(const FileName: WideString): IXMLClinicsType;
  function NewClinics: IXMLClinicsType;

这里有二个接口类型:IXMLClinicsType和IXMLClinicType;用二个类(TXMLClinicsType和TXMLClinicType)来执行这二个接口。另外还有三个全局函数:GetClinics (获得根元素),LoadClinics (从外部XML文件加载)和NewClinics (在内存生成新文件)。

用法
使用生成的Clinic.pas单元是很容易的。跟前一篇文章的做法一样,使用XMLDocument组件(在Inernet标签内)。不过我们不再使用无类型节点了,我们可以调用GetClinics函数获得IXMLClinicsType类型。以下是具体操作过程:

在Delphi 6建立一个新的应用(project)
在XML数据绑定向导指引下建立Clinic.pas文件(经过命名存盘 - 译者)
在主窗体上加入一个XMLDocument组件,其FileName属性为Clinic.xml
在主窗体的OnCreate事件中加入以下代码:
  procedure TForm1.FormCreate(Sender: TObject);
  var
    Clinics: IXMLClinicsType;
  begin
    Clinics := GetClinics(XMLDocument1);
  end;

把Clinics变量放到主窗体中是很有用的,这样就可以在主窗体运行期间使用Clinics接口。使用IXMLClinicsType变量类型要比以前使用普通XMLDocument组件方便多了。现在可以通过Get_Clinic方法来获得各个Clinic元素,还可以在特定位置插入新的Clinic元素。用Clinics.Clinic可以获得节点元素,用Getter和Setter方法可以得到或设置元素值。现在可以直接访问No, Title, Date, Topics等属性了:
  procedure TForm1.ButtonGetClick(Sender: TObject);
  var
    Clinic: IXMLClinicType;
  begin
    Clinic := Clinics.Clinic[0];
    EditNo.Text := Clinic.No;
    EditTitle.Text := Clinic.Title;
    EditDate.Text := Clinic.Date;
    EditTopics.Text := Clinic.Topics
  end;

可以在Clinic.pas中看到,Getter和Setter是方法而不是属性(实际上,我始终认为使用属性更清楚些)。但是Delphi 6让你看到的却是属性描述而不是方法本身(Delphi 6的另一个受欢迎的优点)。将上面这段代码与前一篇文章使用的方法相比较,就能感到操作方便多了。

下面的例子在XML树的末尾加入一个节点:
  procedure TForm1.ButtonAddClick(Sender: TObject);
  begin
    with Clinics.Add do
    begin
      No := '2001-2-8;  // 8th Clinic of the 2nd series of 2001
      Title := 'Special Kylix 2 Clinic';
      Date := '2001/12/21';
      Topics := 'Kylix 2 New Features'
    end
  end;

如果没有把XMLDocument组件的AutoSave设置为真,可以用以下方法保存更动结果:
  procedure TForm1.FormDestroy(Sender: TObject);
  begin
    XMLDocument1.SaveToFile;
  end;

这就是XML数据绑定向导,一个非常方便的方法。它能做得越来越好。

下一篇文章:
我们已经看到了XML数据绑定的优点。不过好象还有点不“满足”,比方要遍历各个节点,存取节点值(不单单是字符串类型),虽然可用选项决定,但还是用Delphi 6的XML映象更好,它的功能更强。我们将在下一篇文章论述。

Delphi 调用 .net 开发的WebService 强类型处理

最近要写一个产品 。用到Delphi来做客户端,调用C#写的WebService   。 这里把自己的一些心得写一下:
调用方法是看了一篇老外的文章。经过我的实验,证实老外文章中方法是正确的,可恶的是很多小地方没有提及,花了我不少时间,这里我用红色字写出来,希望大家不要再走我的弯路。
  delphi调用返回数据集web services的方法:
  delphi通过httpRIO的控件,来接收soap。然后把soap写成xml文件,通过外部工具xml mapper生成一个xtr翻译文件。这个xtr就做为XMLTransformProvider的transformFile(翻译文件)。以后只要httpRIO传来的soap传给xmlTransformProvider后,xmTransformProvider就可以通过翻译文件(xtr)得到数据,提供给clientDataSet。
        是不是觉得很麻烦,dotnet里面dataset可以直接接住数据。不过我个人认为delphi还残留一点优势,毕竟win32程序从开始淘汰到正式淘汰还有漫长的岁月。就算longhorn系统出现,也仍有虚拟机来跑win32程序。那么使用delphi7结合web services开发,一方面可以暂时省去学习其他开发工具的时间,另一方面使用web services也可以为以后开发重用。如果项目时间紧,开发成员对vs.net开发环境不熟悉,倒是一种过渡性的开发方式。

下面文章摘于http://community.borland.com/article/0,1410,28631,00.html

Use ADO.NET datasets in Delphi
Ratings: be the first!  Rate It

Abstract: Learn how to use ADO.NET datasets in Delphi, using XML mapper to transform XML across the platforms. Demonstrated using a .NET web service and Delphi client. 

Use ADO.NET Datasets in Delphi


By Deepak Shenoy

Introduction

If you've experimented with Web Services, you might have hit some Microsoft .NET based Web Services which return data all right, but it's in the default XML format from ADO.NET. So you end up with some XML but you have no clue what to do with it! This article explains how you can take this XML, make sense out of it and even display it in a DB Grid.

Scope

I'm not going to explain much about .NET, or the ADO.NET XML format. What I'll talk about is the most probable case you'll encounter .NET datasets: as XML returned from a .NET based Web Service. If you're going to use .NET datasets in some other way, you might want to read this article to get an idea of how to make your Delphi application aware of them.

Hitting the .NET service

Let's start with a simple .NET service, as given in http://services.pagedownweb.com/ZipCodes.asmx. I've used the Web Service Importer in File | New | Other | Web Services and generated the Pascal files. Here's the declaration that looks odd:


  rtnZipDSResult = class(TRemotable)
  private
    Fs_schema: String;
  published
    property s_schema: String read Fs_schema write Fs_schema;
  end;

  ZipCodesSoap = interface(IInvokable)
  ['{FEF279A0-29EE-CF0B-FBB2-7DD79A5502CE}']
    ...
	function  rtnZipDS(const City_IN: String; const State_IN: String): rtnZipDSResult; stdcall;
	...
  end;
The rtnZipDS function returns a .NET dataset, as XML. Here, the s_schema of the rtnZipDSResult class is simply the dataset as XML in ADO.NET's default format. This means that a .NET client could easily get this XML and show it on a grid or a form - but can we do this with Delphi? Let's see.

Using the .NET service in Delphi

I've created a sample form , which looks like this:

Now we've setup the HTTPRio, and the code behind the Get Zip Codes button is:


procedure TForm1.Button1Click(Sender: TObject);
begin
  (HTTPRIO1 as ZipCodesSoap).rtnZipDS(edtCity.Text, edtState.Text);
end;
I've also added an event handler on the HTTPRio1.OnAfterExecute like so:

procedure TForm1.HTTPRIO1AfterExecute(const MethodName: String;
  SOAPResponse: TStream);
begin
  SOAPResponse.Position := 0;
  Memo1.Lines.LoadFromStream(SOAPResponse);

  SOAPResponse.Position := 0;
end;

This is only to display the returned content on to a Memo so we can figure out what to do with it. Here's how the form looks now:

Interpreting the .NET XML

We have to figure out how to get Delphi to USE this data. We would like to have a Client Data Set read the XML so we can display it all in a Grid. For that we'll have to use XDR transforms. No, that's not very complicated, and here's how we'll do it.

1. First we're going to save the XML returned into an XML file. I've saved it as "data.xml".
2. Run XML mapper from the Tools menu, and open this XML file. Here's a mega screen shot:

{用C#开发web services的时候,如果你这样写  oleDbDataAdapter1.Fill(ds,'tablename');}那么你是看不到上面橙色筐中的字段的。千万不要表明数据集中表名。你这样写就可以了,oleDbDataAdapter1.Fill(ds);就能显示字段了!

3. The ZIPDATA(*) means there's multiple rows of "ZIPDATA" available. Columns availabl are Zip, City, State, County and AreaCode. Let's double-click each one of these to add them to the transformation and then click the DataPacket from XML in the Create Menu. Here's what it all looks like:

4. Save the Transformation using File | Save | Transformation, as "Ziptrans.xtr". Don't try to test the transformation yet. (There's a bug in Delphi Source code that doesn't like SOAP namespaces in certain elements so it doesn't show up any data).

5. We'll now FIX this bug. The XTR file is an XML file which you can open in any text editor. Open it, and change the first line from:


<SelectEach dest="DATAPACKETROWDATAROW" from="soap:Envelopesoap:Body....">

   [Change To]

<SelectEach dest="DATAPACKETROWDATAROW" from="Envelopesoap:Body....">
The reason for this is that Delphi's XML Transform provider does not like the "soap:" in the first element of the "from" attribute. That might get fixed in some update pack, so this point might not apply

{from后面除了soap:,只要是单词后面有冒号的,该单词和冒号都要去掉,delphi才能显示数据}

6. We're nearly there. Drop a TClientDataset, a TXMLTransformProvider and a TDatasource on the form. Here's what the form looks like now:

Link the Grid, the Datasource and the ClientDataset, and set the ClientDataset's ProviderName to point to the XML Transform Provider. 7. Set the TransformRead.TransformationFile of the XMLTransformProvider to Ziptrans.XTR.

8. Now we need to set the data of the XML Transform Provider at run time. Here's some additional code in the HTTPRio's OnAfterExecute:


procedure TForm1.HTTPRIO1AfterExecute(const MethodName: String;
  SOAPResponse: TStream);
var
  XMLDoc: IXMLDocument;
begin
  SOAPResponse.Position := 0;
  Memo1.Lines.LoadFromStream(SOAPResponse);

  ClientDataset1.Active := FALSE;
  SOAPResponse.Position := 0;
  XMLDoc := NewXMLDocument;
  XMLDoc.Encoding := SUTF8; //应该是'SUTF8'并需要引用XMLIntf,XMLDoc两个单元
  SOAPResponse.Position := 0;
  XMLDoc.LoadFromStream(SOAPResponse);

  XMLTransformProvider1.TransformRead.SourceXmlDocument := XMLDoc.GetDOMDocument;
  ClientDataset1.Active := TRUE;
end;

You'll notice that we've created an XML Document , loaded it from the Received SOAP stream, and applied the transform to it. The client dataset gets data from the provider and displays the data :

That's it!

Amazing.

Thank you.

What's next?

This transformation is very specific to this particular service and XML schema. SO if you know what XML is going to be returned (the format) then you can use XML mapper to generate a transformation for it.

I haven't been able to write a "general" transform that can be applied to ANY .NET returned XML, but if anyone does I'd love to hear about it.

Also, why have I used the HTTPRio's OnAfterExecute, rather than manipulating the the s_schema parameter? There's another bug in Delphi that doesn't like parameters returned as XML. More revealed in this thread.

You can download all the code for this project at http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=17807 or at http://www.agnisoft.com/soap/dotnetds.zip.

Deepak Shenoy(shenoy@agnisoft.com) is a Director at Agni Software, a software company in India that offers consultancy and offshore development solutions. It might be a while before his hair gets pointy so he's allowed to understand some technology.

3月10日

有一段时间没有来这里说说话了 。 今天就说说最近亲身经历的数据灾难吧

3.7日 , 一个令人难忘的日子 。
因为机器中毒严重。我决定用TrueImage重新恢复一次系统 。 启动9.0企业版,发现恢复选项中多了一项Snap Recovery  。 也是推荐选项 。 大致的说明是用这个方式可以很快恢复到上次增量备份的状态,并且无需等待几分钟 。
好,就选他了 。 恢复速度满快的 。但恢复过程中都没有要求我选择恢复到哪个分区 。 当时心情就有些忐忑不安了 。 只好求上天保佑他会自动识别主分区  。
 
恢复完成 , 进入Windows  。 恢复成功 。 但,突然发现D盘没有了 。 进入磁盘管理器想找回来,却提示这是一个新分区,要求格式化。 疯掉了 。 我有三个项目包括:DigitalCity , MealO , Tolo 以及代码管理库SVNRoot都在D盘 。 要是这些资料丢失 , 就意味着直接2万块钱的损失以及最近一个多月的工作白做 。其中还包括一个通宵 。
 
拿出各款文件恢复软件 , FinalData , EasyRecovery  , FinalRecovery , 易我  ......  失败 , 还是失败  。 不断的失败后我放弃了 。
 
找数据恢复商 。 飞客  , 回天 还有一些不知道名字的非专业公司 。 这里再次强调 。 河南科技市场就没有维修的专业人士和公司。因此不到迫不得已,我是百万个不愿意去公司维修的 。 因为八成会修得情况越来越坏 。
 
问回来得几个是在300-800不等 。 其实对方也是拿软件来扫描和找回 。
 
最后在一家很不专业得回天做了恢复 。 找回来了大概3G得内容,有些已经永久找不回来了。 要知道,我原来盘上有40G内容啊 。 找不回来得包括一个项目  。 同时找回来得很多文件也不能用 。 不过总算老天见怜  。 我需要最重要得数据找回来一半多点儿。再加上家中得部分备份 。 交了钱回到家中 ,开始Diy  。
到晚上得时候终于恢复到了之前得9成 。
 
一次数据灾难挽救完成 。
 
结论 :  以后再Ghost一定手动备份另外得盘 。 河南所谓得维修人士还是如此烂  。
 
3月3日

达到6sigma水平的印度孟买送餐业

这是一个很简单的行业,从业者都是小学文化程度。但以99.999999%的精确性,它入选了《吉尼斯世界记录》;年收益高达1.8亿卢比,它成为许多经济管理学院研究、讨论的案例。
拉姆是印度孟买市政府的一名打字员。市政府位于繁华都市的中心地带,拉姆的家却位于30公里外的孟买郊区。但是,空间上的距离并不妨碍拉姆在工作日的中午吃到妻子为他精心准备的美味午餐,其中自然少不了他最喜爱的咖喱羊肉和黄豆汤。
    这一切都得益于孟买拥有一个独特的速递网络,专门提供从顾客家到顾客指定地点的送餐服务。
从事这一行业的人员被称做“达巴瓦拉”,“达巴”在印地语中是“饭盒”、“小桶”的意思,“瓦拉”指某类人,合在一起就是送盒饭的人。达巴瓦拉在送餐时都穿着印度传统的白色长袍,头戴船形小白帽。每到中午时分,在孟买城区纵横交错的大街小巷穿梭的达巴瓦拉,是孟买一道独特的风景。
    拉姆的午餐经五道手送达
    在孟买,目前约有5000名达巴瓦拉,要为20万像拉姆那样的顾客送餐。达巴瓦拉同属于“孟买盒饭供应者协会”,相互之间有明确的分工和协作,他们是一个有机的整体,绝不会单打独斗。拉姆的午餐从家到办公室要经过五道达巴瓦拉的转手。
    拉姆一般早晨7点离家上班,妻子一定要在10点钟之前准备好他的午餐并把它放进餐盒里。餐盒是铝制的,长圆筒形,分里外两层。外面一层起到保温和固定作用,里面一层由4个小碗罗列而成,分别盛着主食、菜和甜点。
    这种餐盒是印度最常见的。餐盒上标有一些数字和字母,表明它来自何方、将要前往何地。外人对此一头雾水,达巴瓦拉却烂熟于胸。牢记标志含义是达巴瓦拉入行的基本功,也是保证送餐顺利的前提。10点钟,一个达巴瓦拉会准时赶到拉姆家。他取过餐盒,然后飞奔前往下一个顾客家。一个达巴瓦拉一般要负责30~35名顾客,取餐顺序都经过详细考虑,他的交通工具以自行车为主。10点半左右,从拉姆家取餐的那个达巴瓦拉赶到距离最近的一个城郊火车站,将收集来的餐盒交给在那里等候的达巴瓦拉。在火车站有人专门按照目的地迅速将餐盒进行分拣、归类,并由另一拨达巴瓦拉负责将盒饭带上火车。
    达巴瓦拉装盒饭的工具一般是一个2.5米长、85公分宽的木条箱,每个能装40盒左右。达巴瓦拉要头顶这个沉重的木条箱,在旅客中快速穿行并安全地登上列车。火车在一个站的停留时间是两分钟,所以达巴瓦拉必须动作敏捷、争分夺秒。10:40至11:30,是20万餐盒乘火车旅行的时间,拉姆的餐盒也在其中。
    与此同时,在城区各个火车站站台上,早有另一批达巴瓦拉在等候。火车到站后,他们从同伴手中接过餐盒,再次按区域分拣,落实到每个达巴瓦拉头上。这些达巴瓦拉会把餐盒送到顾客指定的地点。
    拉姆要求把餐盒放到单位门房,所以他与达巴瓦拉从不见面。但是,只要拉姆12:30以后来到门房,自己的饭盒总是在那里等着,从不爽约。吃过饭,拉姆只要将餐盒放回原处,达巴瓦拉就会按照来时的方法将它运抵家中。在返程中,由于没有强烈的时间压力,达巴瓦拉会心情放松而愉快,经常哼哼家乡小调或与同伴开开玩笑。
孟买达巴瓦拉的历史可追溯到19世纪90年代。那时孟买处于发展初期,外地移民刚开始涌入。移民们来自印度各地,饮食习惯差别很大,比如南印度人要吃南印度饭,旁遮普人要吃旁遮普饭,众口难调。另外,印度人对饮食还有着诸多禁忌,常常与宗教和种姓连在一起。所以,大多数移民都希望能在工作一上午后吃上自己家里做的可口饭菜。
    这种需求导致送餐业的产生和达巴瓦拉的日渐繁荣。在自然竞争和淘汰中,来自孟买附近普纳地区的人主宰了这一市场。目前,绝大多数达巴瓦拉来自普纳,他们不是亲戚就是同乡,有共同的风俗习惯,信奉同一个神。当有空位出现时,总是由年长者推荐一名他在老家的亲戚。这种人际关系使达巴瓦拉有高度的认同感和归属感,非常抱团,外人很难涉足。
    达巴瓦拉的组织结构分为三层。最高层是协会执行委员会,负责组织、协调、处理紧急事务、福利和对外交往。第二层是协会内20~25个达巴瓦拉小组的负责人。他们一般是经验丰富的老达巴瓦拉,监管一个小组的工作运行。第三层就是具体干活的达巴瓦拉。
    达巴瓦拉与协会不是雇佣与被雇佣关系,而是成员关系。每个达巴瓦拉都是股东,都享有分红的权利。他们在加入协会时都必须交纳一定的资本金。最低投资要求是两辆自行车、一个木条箱、一套白色传统服装和一顶标志性的帽子,这几项约合5000卢比(5卢比约合1元人民币)。
    达巴瓦拉的工作是艰辛的,不仅需要体力,还必须与时间赛跑。他们的行规就是:无论发生什么,必须准时送达。几个月前,印度媒体曾报道过这样一件事:一个骑自行车送餐的达巴瓦拉在路口等红灯时被一违规卡车撞倒身亡。同伴们赶到后,有人处理善后事宜,有人立即继续他未完的工作。当盒饭到达目的地时,只比平时晚了30分钟。
    达巴瓦拉的文化程度都不高,一般是小学毕业。他们的月收入为4000~5000卢比,这个水平已足够他们养家糊口。此外,协会还提供紧急援助、子女就学等福利。
    成为孟买标志,与“宝莱坞”齐名
    百年来,达巴瓦拉与孟买共同发展,已成为孟买的标志之一,与“宝莱坞”、“孟买证交所”、“舞吧”齐名。跟印度人提达巴瓦拉,他们马上想到孟买。
    梅吉是孟买盒饭供应者协会负责人,他认为孟买独特的地理条件是达巴瓦拉成功的根基。孟买曾是海上的7个小岛,18世纪英国人开始了长达百年的填海造地。19世纪,7个海岛终于被连成一体并与大陆相通,形成今天孟买的主体。这一历史进程,使孟买最终成为一个狭长的城市,而且在以后的发展中孟买又基本形成了北部是居住区、南部是办公、商业区的格局。这两个地理特点大大方便了达巴瓦拉的送餐工作。
    据梅吉透露,几年前他们曾尝试把类似的服务推广到新德里,但遭到惨败。一个重要原因是新德里是一个圆形分布的城市,线路规划复杂,成本太高。
    在梅吉看来,孟买快速、准时且便宜的城郊铁路系统是送餐业的大动脉,提供了可靠的交通保障。孟买城郊铁路系统全长303公里,分西线和中线,把孟买的主要地区全部串连起来。这使达巴瓦拉能以各个火车站为餐盒集散地,对广阔地区形成辐射。据统计,达巴瓦拉在孟买的覆盖范围达六七十平方公里。另外,负责在火车上运送盒饭的达巴瓦拉每月的运输费只有200卢比,成本非常低。
    孟买是印度第一大城市,拥有1500万人口,是印度“商业和金融中心”。孟买是印度白领和小职员最集中的地方,这为达巴瓦拉扩展生意提供了充足的客源。白领和小职员是对价格非常敏感的阶层。他们如果每天中午到附近餐厅吃饭,花费就会翻好几倍,卫生质量还难以保障。要是通过达巴瓦拉送餐,每月只需付出300卢比左右,价格优势显而易见,而且干净、营养、味道好。
    成为经济学院研究案例
    达巴瓦拉辛勤而有创造性的耕耘,使孟买午餐配送成为一桩大生意,年收益高达1.8亿卢比。尤令人惊叹的是,文化程度很低的达巴瓦拉在高速运转中把差错率保持在八百万分之一,达到质量保证体系西格马6级标准,即送餐准确性为99.999999%。而这一切的取得没有依靠任何先进技术,只是凭着一套简单符号和达巴瓦拉的细致与相互间的密切合作。
    达巴瓦拉取得的成就引起媒体广泛关注。BBC、德国之声等国际大媒体为达巴瓦拉制作了专题片,使达巴瓦拉的名声传到海外。英国查尔斯王子2003年11月访印期间,特意看望了达巴瓦拉,详细了解他们的运作方式,对他们的效率赞不绝口。2005年4月,达巴瓦拉的4名代表还应邀参加了查尔斯王子的婚礼。目前,孟买午餐配送已被列入《吉尼斯世界记录》,并成为许多经济管理学院研究、讨论的案例。孟买盒饭供应者协会的负责人还多次应邀参加商业研讨会,介绍他们独特的经营管理经验。
    为更好地为顾客服务,孟买盒饭供应者协会建立了网站,开辟了新的沟通平台。顾客通过邮件或手机短信就可预订服务。协会负责人表示,他们要在推广、营销上与时俱进,采用新技术。但是,在核心业务和管理上将保持自己的传统,使达巴瓦拉的魅力长久存在