Example for XML simple interface (SAX2) implemented with Visual Basic

zhaozj2021-02-08  187

Martin Naughton June 2000 Download Example Code (351 KB) Abstract: This article summarizes the method of using the SAX2 interface with Microsoft Visual Basic. Introduction MAY 2000 MSXML TECHNOLOGY Preview is one of the key features of SAX2 (Simple API for XML, Version 2). The MSDN XML Developer Center provides the SAX2 Quick Getting Started with XML Developers, which can be downloaded as an introduction to SAX2. In this article, I will outline the way to develop SAX2 interfaces with Visual Basic®. Note that non-technical support will not be provided to this example, the purpose of this example is to help you create prototypes for SAX / Visual Basic solutions. Moreover, it should be apparent that the interfaces in this example will not affect the support of SAX in Microsoft Visual Basic. Hello World! After having Visual Basic (VB), the typical way of using the Component Object Model (for example, msxml3.dll) is to create a new standard EXE project, then enter the engineering / reference menu, add the MSXML3.DLL type library ( A reference to Microsoft XML, version 3.0). At this point, you can use the Visual Basic object browser to view properties, methods, and events of the selected interface. I used MSXML3.DLL to complete these tasks, then find the SAX2 interface in vain, but no remote SAX-Y found in this type library. Then I view the registry to determine if the correct MSXml3.dll version is installed. Of course, there are two very likely PROGIDs (especially msxml2.saxxmlreader and msxml2.saxxmlreader and msxml2.saxxmlreader.3.0), so I have asked "What I lost in the newsgroup continuous in the newsgroup." ?"The problem. Soon, I replied that I actually lost something. Source, the Luke SAX2 interface is defined in a file called Xmlsax.idl. If you install MSXML3.dll into the default folder, you can find XMLSax.idl in a folder called C: / Program Files / Microsoft XML Parser SDK / INC. After finding the file, I compile Xmlsax.idl into the type library called (very suitable) Xmlsax.tlb. MIDL IDL is a tool I have to compile. Go back to the Visual Basic Integrated Development Environment (IDE), I return to the Project / Reference menu, this time I select Browse from the Reference dialog box to find the new Xmlsax.tlb file. Use this method to select the result of the type library, VB IDE first registers the type library file. This is excited. Now the SAX2 interface can be displayed in the Object Browser. The character constructor has confirmed the inspection of certain method parameters to the newsgroup's response to me: The interface is a little unfriendled for Visual Basic. Keep in mind that documents in Microsoft XML SDK 3.0 describe the SAX2 interface as "COM / C implementation of Microsoft SAX2". All in all, where Visual Basic developers expect to see a string parameter is actually two parameters. The first of these parameters has a "PWCH" Hungarian prefix ("to the pointer to the array array"?), The second has a "cch" prefix ("character count"?).

Below is the ISAXCONTENTHANDLER IDL of the StartElement method: HRESULT STARTELEMENT ([in] const wchar_t * pwchnamespaceuri,

Int cchnamespaceuri,

[in] const wchar_t * pwchlocalname,

INT Cchlocalname,

[in] const wchar_t * pWCHQNAME,

INT cchqname,

ISAXATTRIBUTES * PATTRIBUTES);

Fortunately, the answers to the newsgroup provide a Visual Basic code that handles these parameters. The simplified version of this function is as follows. Public Function UNICODEARRAYTOSTRING (PWcharray As Integer, Byval Lcharcount As long) AS STRING

DIM Stext As String

'Adjusting string size is the right number of characters

Stext = string $ (lcharcount, 0)

'Copy these values. Please note that the size is twice the number of characters.

'Because the string is unicode (double byte)

Call CopyMemory (ByVal Strptr (Stext), IUnicodechararrayFirstelt,

LCHARCOUNT * 2)

UnicodeArrayToString = Stext

END FUNCTION

The XMLSAX interface returns the Visual Basic integer array, plus the number of items in the array. The UnicodeArrayTString function uses an unapproved Visual Basic StrPtr function, plus the call to the CopyMemory Windows API to convert these values ​​to the Visual Basic string. CopyMemory is an alias for Windows API RTLMoveMemory. SAX2 "Quick Start" for Visual Basic We can now start writing "SAX2 Quick Getting Started" in Visual Basic. To obtain results similar to the C "Quick Getting Started" application, use the following instructions. Note that you don't need reference to MSXML.

Create a Visual Basic standard EXE project. Add a reference to the XMLSax.tlb file (including in download). Copy and paste the following code into the Visual Basic Form code window (after the code is passed, you need to delete the Enter from the code). Add CommandButton (Command1) in the form. Save the project. If it has not yet existed, place the correct XML file named Test.xml in the folder of the saved project. Run the project in the Debug mode. Click the COMMAND1 button. Observe the Immediate window. Option expedition

Private Declare Sub CopyMemory Lib "kernel32" Alias ​​"RTLMOVEMEMORY" (PDEST

As Any, Psource As Any, ByVal Bytelen As Long

Implements Xmlsax.isaxContentHandler

Private submmand1_click ()

Call Parse

End Sub

Private function parse () as boolean

DIM i () AS Integer

Dim Str As String

Dim Sax as SaxxmlReader30

Set Sax = New Saxxmlreader30

Call Sax.putContentHandler (ME)

Str = app.path & "/" & "test.xml"

'Adjust the number of arrays as characters

Redim I (Len (STR))

'Copy memory, pay attention to the size of the character is twice the number of characters,

'Because it is a Unicode string

CopyMemory I (0), ByVal Strptr (STR), LEN (STR) * 2

'Ignore the first matrix item below

SAX.PARSEURL I (0), LEN (STR)

END FUNCTION

Private sub isxcontenthandler_characters (PWchchars as INTEGER, BYVAL

Cchchars as long

'do nothing

End Sub

Private sub isaxContentHandler_EndDocument ()

'do nothing

End Sub

Private sub isaxContentHandler_Endelement (PWchnAMespaceuri AS INTEGER,

Byval Cchnamespaceuri As Long, PWCHLOCALNAME AS INTEGER, BYVAL

Cchlocalname As Long, PWCHQNAME AS INTEGER, BYVAL CCHQNAME AS Long

'do nothing

End Sub

Private sub isxcontenthandler_endprefixmapping (PWCHPREFIX AS INTEGER,

BYVAL CCHPREFIX AS Long

'do nothing

End Sub

Private sub isxcontenthandler_IgnorableWhitespace (PWCHCHARS AS INTEGER,

BYVAL CCHCHARS AS Long)

'do nothing

End Sub

Private sub isxcontentHandler_Processinginstruction (PWCHTARGET AS)

INTEGER, BYVAL CCHTARGET AS Long, PWCHDATA AS INTEGER, BYVAL CCHDATA

As long

'do nothing

End Sub

Private sub isxcontenthandler_putdocumentlocator (Byval Plocator As

Xmlsax.isaxlocator)

'do nothing

End Sub

Private sub isxcontenthandler_skippedentity (pwchname as integer, ByVal

Cchname as long

'do nothing

End Sub

Private sub isxcontenthandler_startDocument ()

End Sub

Private sub isaxContentHandler_StartElement (pwchnamespaceuri as integer,

Byval Cchnamespaceuri As Long, PWCHLOCALNAME AS INTEGER, BYVAL

Cchlocalname As Long, PWCHQNAME AS INTEGER, BYVAL CCHQNAME AS Long,

ByVal Pattributes as Xmlsax.Isaxattributes)

Dim Str As String

'Adjusting string size is the right number of characters

Str = string $ (cchlocalname, 0)

'Copy these values. Please note that the size is twice the number of characters.

'Because it is a Unicode string

CopyMemory Byval Strptr (Str), PWCHLOCALNAME, CCHLOCALNAME * 2

Debug.print Str

End Sub

Private sub isxcontenthandler_startprefixmapping (PWCHPREFIX AS INTEGER,

BYVAL CCHPREFIX As Long, PWCHURI AS INTEGER, BYVAL CCHURI AS LONG

'do nothing

End Sub

Pack it up after overcoming the initial difficulties of writing SAX2 programs with Visual Basic, I decided to pack all Visual Basic's internal SAX2 interface package categories in all Visual Basic. Work results can be seen in the download location of this article. Although it is incomplete, all points are demonstrated. This sample code can be compiled into ActiveX® components (VBXmlsax) and then reuse (in Visual Basic, VBScript, JScript®, or even Visual C ), do not need to know the implementation of the implementation. For those who want to know some of the problems, please read them. Stop the analyzer, I want to leave! One of the power-based analyzers (such as SAX2), it is possible to stop analyzing when matched with user-defined conditions. For example, you may want to stop analyzing when you encounter an element called "uninteresting" in an XML document. The SAX2 handler interface allows the user to stop analyzing. We tried to represent the methods on the handler interface as the Visual Basic event in your own packaging program class, so that the event recipient (eg, VB form object) can control the termination of the analysis. Observation of the handler of the interface tells us that the handler method represents the need to stop analysis by setting the return value (HRESULT) to the ERR_FAIL value. There is only one question: VB hides HRESULT, so it cannot be set in the custom handler code. In fact, this value can be set, but some links must be skipped. This technology is called "vTable modification" and is described in the BRUCE MCKINNEY book Hardcore Visual Basic. At runtime, it is possible to reordforward calls from Visual Basic's event handler to user's own function. The key to the technology is to use the Addressof operator to obtain overloaded function addresses, and then use CopyMemory to overwrite the VTABLE item of the respective interface. Since the overload function is defined by the user (not Visual Basic), the return value is controllable. Let's take an example. The IsaxContentHandler interface provides a way called STARTDocument. If we create the Visual Basic class packager that implements IsaxContentHandler (CVBSAXContentHandler), Visual Basic will provide a procedure protocol similar to: private sub isaxContentHandler_StartDocument ()

In the back function prototype is actually: public function isaxContentHandler_StartDocument (ByVal this as

IsaxContentHandler) As Long

In fact, the return type is HRESULT, but the HRESULT value can be stored using the Visual Basic long data type. Therefore, in order to overrunate the STARTDocument method, we created a function with the latter prototype in the BAS file. Calling at runtime is a program in the Visual Basic class package. Please pay attention to the increased parameter this. It is an instance of the ISAXCONTENTLER handler called. Here is the overload function of StartDocument: public function isaxcontenthandler_startdocument (byval this asxcontenthandler) as long # if Idebug = -1 Then

Debug.print "vtable replacement for isaxcontentrandler_startdocument"

#End IF

DIM Booabort as boolean

Dim objvbsaxContentHandler As CvbsaxContentHandler

Set objvbsaxcontenthandler = this

Call ObjvbsaxContentHandler.StartDocument (booabort)

IF booabort then

IsaxContentHandler_StartDocument = E_FAIL

Else

IsaxContentHandler_StartDocument = S_OK

END IF

END FUNCTION

There is a problem with this technology. The AddRessof operator can only be used for functions defined in standard modules (BAS files). Therefore, the same function will be called on all instances of a particular processing program interface. This proposes a problem, how to determine an instance of the called handler packager (because it is a packager that triggers the event). Fortunately, the format required by the VTable overload function contains this parameters (see the previous code example), and its type is the called interface. Through this parameter, we can declare the variables of the CVBSAXContentHandler to perform the equivalence of the queryinterface, and then make the following assignment. Dim objcvbsaxContentHandler As CvbsaxContentHandler

Set objcvbsaxcontenthandler = this

The call effectively obtained the Visual Basic packaging interface. Then we can call the packaging, and then trigger the event in the expected manner. In order to achieve this effect, we are defined by the "Friend" range on CVBSAXContentHandler. In this way, the internal code of the VBSAXXML component can access the function, but the external client can't see it. The implementation of the Friend method only triggers events, transmits all raw parameters, plus the Abort flag (transfer with Byref), thus handling the code to set the flag. Below is the code: Friend Sub StartDocument (Abort as Boolean)

RaiseEvent StartDocument (Abort)

End Sub

After returning from the server application (e.g., a form), the Friend StartDocument method in the CVBSAXContentHandler simply passes the value of the ABORT parameter back to the VTable overload function. According to the value of the Abort logo, the VTable overload can correctly set the HRESULT return value of the underlying IsaxContentHandler.StartElement method. Other handler methods can also be overloaded in a similar manner. Below is a function prototype of the STARTELEMENT method, which has its own parameters. Public Function IsaxContentHandler_StartElement (Byval this AsiaxContenthandler, PWchnamespaceuri As INTEGER, BYVAL CCHNAMESPACEURI

As Long, PWCHLOCALNAME AS INTEGER, BYVAL CCHLOCALNAME AS Long, PWCHQNAME

As integer, byval cchqname as long, ByVal Pattributes AS

Xmlsax.isaxattributes) as long

Friend equivalents are similar to: Friend Sub StartElement (Byval Namespaceuri As String, ByVal Localname As

String, Byval Qname As String, ByVal Attributes As Cvbsaxattributes,

Abort as boolean

RaiseEvent StartElement (Namespaceuri, localname, qname, attributes,

Abort)

End Sub

This function has its own function, which is a VTABLE overload function that maps C style parameters to the Visual Basic friendly string. Type library Hacking In some cases, you can find that the XMLSax.TLB type library generated by the XMLSax.idl file is compiled, not only for Visual Basic, but also can't be used in Visual Basic. In particular, the parameters of the method defined as [OUT] in the IDL are unacceptable to Visual Basic. If the parameter is defined as [IN, OUT] or [OUT, RETVAL], the Visual Basic is not allowed to use it. This is the condition of some methods in the SAX2 interface. In addition, I have encountered trouble when I call most methods on the Isaxattributes interface. For example, a getLocalName method produces a subroutine in Visual Basic. The caller transmits the index to the Attributes collection. The program returns an integer BY-NOW-FAMILIAR array and an array length parameter. IDL is similar to: HRESULT GETLOCALNAME

INT NINDEX,

[OUT] const wchar_t ** ppwchlocalname,

[OUT] INT * PCCHLOCALNAME);

I know [OUT] parameters are unacceptable in Visual Basic. Therefore, I decided to change the [OUT] parameter in the IDL to [IN, OUT]. But I can't determine how to decode const wchar_t ** data type. I noticed that the Hardcore Visual Basic book provides a function called UPOINTERTOSTRING, it seems to be helpful. But UPOINTERTOSTRING needs a pointer (which is long in VB). So I decided to change the data type from const wchar_t ** to INT *. Modified IDL is similar to: HRESULT GETLOCALNAME ([In] Int Nindex,

[in, out] int * ppwchlocalname,

INT * PCCHLOCALNAME);

Result This format is acceptable in Visual Basic. String values ​​can be successfully decoded with UPoinTostRingex (same as UpointertString, but using character count as parameters). The method on IsaxAttributes can now be used as subroutine: Call Pattributes.getValue (0, PWCHVALUE, CCHVALUE)

The above call obtains an attribute value of the index position 0, assigns the pointer to the value in the PWCHVALUE and the value length in the cchvalue. Then return from the following code (similar to the above description). SattValue = string $ (cchvalue, 0)

CopyMemory Byval Strptr (SattValue), ByVal PWCHVALUE, CCHVALUE * 2

Note that PWCHVALUE must be added to BYVAL. I copied Xmlsax.idl files, called Xmlsaxvb.idl, and then modified a copy before compiling the modified copy to Xmlsaxvb.TLB. The ActiveX Component Engineering included in the download will reference this modified type library. Of course, it is not recommended to modify the IDL file as a general rule. But it is recommended that do not allow the modified type library to leave your computer. If you create an installer with the Package and Deployment Wizard, such a library should not include in the installation package. However, since the MSXML discussed herein is just a technical preview, no one is not dangerous to introduce this example in the production environment.

转载请注明原文地址:https://www.9cbs.com/read-3220.html

New Post(0)