The Delphi XML SAX2 Component & MSXML 3.0 by Danny Heijl Example 1: (a) HRESULT _stdcall characters( [in] unsigned short* pwchChars, [in] int cchChars); (b) HRESULT characters( [in] const wchar_t * pwchChars, [in] int cchChars); (c) function characters( var pwchChars: Word; // * WRONG * // cchChars: SYSINT): HResult; stdcall; (d) function characters( const pwchChars: pWideChar; cchChars: SYSINT): HResult; stdcall; Example 2: (a) type TSAXContentHandler = class(TInterfacedObject, ISAXContentHandler) public function putDocumentLocator(const pLocator: ISAXLocator): HResult; stdcall; function startDocument: HResult; stdcall; ... other methods ... end; (b) var ContentHandler: TSAXContentHandler; begin Contenthandler := TSAXContentHandler.Create; Example 3: constructor TSAXParser.Create(AOwner: TComponent); begin inherited Create(AOwner); FLine := 0; FColumn := 0; FAttributeList := TSXPAttributeList.Create; // create an instance of the Reader COM object FReader := CreateComObject(CLASS_SAXXMLReader) as ISAXXMLReader; // instantiate the handler classes FErrorHandler := TSAXErrorHandler.Create; FLexicalHandler := TSAXLexicalHandler.Create; FContenthandler := TSAXContentHandler.Create; FDTDHandler := TSAXDTDHandler.Create; FDeclHandler := TSAXDeclhandler.Create; FContentHandler.FDocumentLocator := Nil; // Handlers need a reference pointing back to us // because they will continually update // our Line and Column properties on each event FLexicalhandler.SAXParser := Self; FContenthandler.SAXParser := Self; FDTDHandler.SAXParser := Self; FDeclHandler.SAXParser := Self; // pass the handler implementations to the reader FReader.putErrorHandler(FErrorhandler); FReader.putContentHandler(FContentHandler); FReader.putDTDHandler(FDTDHandler); Freader.putProperty('http://xml.org/sax/properties/lexical-handler', FLexicalhandler as ISAXLexicalHandler); Freader.putProperty('http://xml.org/sax/properties/declaration-handler', FDeclhandler as ISAXdeclHandler); end; Example 4: // OnComment is handled by the SAXLexicalHandler procedure TSAXParser.SetOnComment(const Value: TOnComment); begin FLexicalHandler.OnComment := Value; end; function TSAXParser.GetOnComment: TOnComment; begin Result := FLexicalHandler.OnComment; end; // OnStartDocument is handled by the SAXContentHandler procedure TSAXParser.SetOnStartDocument(const Value: TOnStartDocument); begin FContentHandler.OnStartDocument := Value; end; function TSAXParser.GetOnStartDocument: TOnStartDocument; begin Result := FContentHandler.OnStartDocument; end; Listing One // *********************************************************************// // Interface: ISAXContentHandler // Flags: (16) Hidden // GUID: {1545CDFA-9E4E-4497-A8A4-2BF7D0112C44} // *********************************************************************// ISAXContentHandler = interface(IUnknown) ['{1545CDFA-9E4E-4497-A8A4-2BF7D0112C44}'] function putDocumentLocator( const pLocator: ISAXLocator): HResult; stdcall; function startDocument: HResult; stdcall; function endDocument: HResult; stdcall; function startPrefixMapping( const pwchPrefix: pWideChar; cchPrefix: SYSINT; const pwchUri: pWideChar; cchUri: SYSINT): HResult; stdcall; function endPrefixMapping( const pwchPrefix: pWideChar; cchPrefix: SYSINT): HResult; stdcall; function startElement( const pwchNamespaceUri: pWideChar; cchNamespaceUri: SYSINT; const pwchLocalName: pWideChar; cchLocalName: SYSINT; const pwchQName: pWideChar; cchQName: SYSINT; const pAttributes: ISAXAttributes): HResult; stdcall; function endElement( const pwchNamespaceUri: pWideChar; cchNamespaceUri: SYSINT; const pwchLocalName: pWideChar; cchLocalName: SYSINT; const pwchQName: pWideChar; cchQName: SYSINT): HResult; stdcall; function characters( const pwchChars: pWideChar; cchChars: SYSINT): HResult; stdcall; function ignorableWhitespace( const pwchChars: pWideChar; cchChars: SYSINT): HResult; stdcall; function processingInstruction( const pwchTarget: pWideChar; cchTarget: SYSINT; const pwchData: pWideChar; cchData: SYSINT): HResult; stdcall; function skippedEntity( const pwchName: pWideChar; cchName: SYSINT): HResult; stdcall; end; Listing Two // ISAXContentHandler.StartElement callback function function TSAXContenthandler.startElement( const pwchNamespaceUri: pWideChar; cchNamespaceUri: SYSINT; const pwchLocalName: pWideChar; cchLocalName: SYSINT; const pwchQName: pWideChar; cchQName: SYSINT; const pAttributes: ISAXAttributes): HResult; stdcall; var strNamespaceURI: string; strLocalName: string; strQName: string; Attribute: TSXPAttribute; i: integer; nAttributes : integer; pURI, pLocalName, pQname, pValue, pType: pWideChar; URIsize, Localsize, Qsize, Typesize, size: integer; begin if Assigned(FOnStartElement) then begin GetLineColumn; // convert element name and URI to string try if pwchNamespaceUri <> Nil then strNamespaceURI :=WideCharLenToString(pwchNamespaceUri,cchNamespaceUri) else strNamespaceURI := ''; if pwchLocalName <> Nil then strLocalName := WideCharLenToString(pwchLocalName, cchLocalName) else strLocalName := ''; if pwchQName <> Nil then strQName := WideCharLenToString(pwchQName, cchQName) else strQName := ''; // build the attribute list try if pAttributes <> Nil then begin with pAttributes do begin getLength(nAttributes); FAttributeList.Capacity := nAttributes; for i := 0 to nAttributes - 1 do begin getName(i, pURI, URIsize, pLocalName, Localsize, pQName, Qsize); getValue(i, pValue, size); getType(i, pType, Typesize); Attribute := TSXPAttribute.Create; with Attribute do begin URI := WideCharLenToString(pURI, URIsize); LocalName := WideCharLenToString(pLocalName, Localsize); QName := WideCharLenToString(pQName, Qsize); Value := WideCharLenToString(pValue, size); AttType := WideCharLenToString(pType, Typesize); end; FAttributeList.Add(Attribute); end; // for end; // with end; // if pAttributes <> Nil // now call the application event handler FOnStartElement(strNamespaceUri,strLocalName,strQName,FAttributeList); finally // clean up the attributes list for i := 0 to FAttributeList.Count - 1 do begin TSXPAttribute(FAttributeList.Items[i]).Free; end; FAttributeList.Clear; end; Result := S_OK; except Result := E_Fail; end; end else begin Result := S_OK; end; end; Listing Three unit filterform; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, MSSAXParser; type TfrmFilter = class(TForm) SXP: TSAXParser; Memo1: TMemo; procedure SXPStartElement(const NamespaceURI, Localname, QName: String; const Attributes: TSXPAttributeList); procedure SXPEndElement(const NamespaceURI, Localname, QName: String); procedure SXPCharacters(const Chars: String); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } bWanted: boolean; strElement: string; end; var frmFilter: TfrmFilter; implementation {$R *.DFM} procedure TfrmFilter.SXPStartElement(const NamespaceURI, Localname, QName: String; const Attributes: TSXPAttributeList); var attr: TSXPAttribute; begin if bWanted then begin strElement := LocalName; exit; end; if CompareText(Localname, 'book') <> 0 then exit; if not Assigned (Attributes) then exit; attr := Attributes.GetItem('genre'); if (attr = Nil) or (CompareText(attr.Value, 'fiction') <> 0) then exit; attr := Attributes.GetItem('in_stock'); if (attr = Nil) or (CompareText(attr.Value, 'yes') <> 0) then exit; bWanted := true; end; procedure TfrmFilter.SXPEndElement(const NamespaceURI, Localname, QName: String); begin if CompareText(LocalName, 'book') = 0 then begin if bWanted then Memo1.Lines.Add('--------------------------------------------'); bWanted := false; end; end; procedure TfrmFilter.SXPCharacters(const Chars: String); begin if bWanted then if Trim(Chars) <> '' then Memo1.Lines.Add(Format('%-20s %s', [strElement, Chars])); end; procedure TfrmFilter.FormCreate(Sender: TObject); begin Memo1.Lines.Add('Fiction books currently in stock :'); Memo1.Lines.Add('=================================='); SXP.Parse; end; end.