Re: Reading XML (data) files in eMbedded Visual Basic.

From: Tony (icbm_NO_SPAM_at_PLEASE_hetnet.nl)
Date: 11/15/04

  • Next message: Taliesyn: "Re: Migrating applications from emVB 3.0 to Windows CE.NET 4.2"
    Date: Mon, 15 Nov 2004 19:18:23 GMT
    
    

    There is the DOM object on the PPC that can be used.

    In my projects I know the fields I want, so I can approach them directly.
    But here is some code samples:
    (Get the API file read/write for free ;-)
    (Oh, as you know CreateObject leaks, so only call it once, re-use the object
    when needed)

    ' For the DOM
    Private xmlDOM As DOMDocument ' The XML parser...
    Private mDOMLoaded As Boolean ' Indication DOM object is loaded
    Private mDOMFile As String ' Current filename in DOM memory
    Private mDOMTag As Integer ' Project related variable, can be
    removed (everywhere)
    Private mDOMMemoryFile As String
    Private mDOMMemoryTag As Integer

    ' Needed to read/write files
    Public Const CREATE_ALWAYS = 2
    Public Const OPEN_EXISTING = 3
    Public Const OPEN_ALWAYS = 4
    Public Const STANDARD_RIGHTS_WRITE = &H20000
    Public Const STANDARD_RIGHTS_READ = &H20000
    Public Const GENERIC_READ = &H80000000
    Public Const GENERIC_WRITE = &H40000000

    Public Const INVALID_HANDLE_VALUE = -1

    Public Declare Function CreateFile Lib "Coredll" Alias "CreateFileW" (ByVal
    lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As
    Long, lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long,
    ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
    Public Declare Function GetFileSize Lib "Coredll" (ByVal hFile As Long,
    lpFileSizeHigh) As Long
    Public Declare Function ReadFile Lib "Coredll" (ByVal hFile As Long, ByVal
    lpBuffer As String, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead
    As Long, ByVal lpOverlapped As Long) As Long
    Public Declare Function WriteFile Lib "Coredll" (ByVal hFile As Long, ByVal
    lpBuffer As String, ByVal nNumberOfBytesToWrite As Long,
    lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long
    Public Declare Function CloseHandle Lib "Coredll" (ByVal hObject As Long) As
    Long
    Public Declare Function FlushFileBuffers Lib "Coredll" (ByVal hFile As Long)
    As Long

    Public Declare Function WideCharToMultiByte Lib "Coredll" (ByVal CodePage As
    Long, ByVal dwFlags As Long, ByVal lpWideCharStr As String, ByVal
    cchWideChar As Long, ByVal lpMultiByteStr As String, ByVal cchMultiByte As
    Long, ByVal lpDefaultChar As String, ByVal lpUsedDefaultChar As Long) As
    Long
    Public Declare Function MultiByteToWideChar Lib "Coredll" (ByVal CodePage As
    Long, ByVal dwFlags As Long, ByVal lpMultiByteStr As String, ByVal
    cchMultiByte As Long, ByVal lpWideCharStr As String, ByVal cchWideChar As
    Long) As Long
    '
    Public Const CP_ACP = 0 ' default to ANSI code page

    ' --- The methods ---

    Public Sub Initialise_DOM()
        On Error Resume Next

        ' Init DOM
        Err.Clear
        Set xmlDOM = CreateObject("Microsoft.XMLDOM") ' Create a DOMDocument
        mDOMLoaded = CBool(Err.Number = 0)
        If mDOMLoaded Then xmlDOM.async = False ' Return control after
    the whole string has been loaded
    End Sub

    Public Sub Terminate_DOM()
        ' Close DOM
        Set xmlDOM = Nothing
    End Sub

    ' Load into DOM
    Public Function XML_Load(ByVal xmlFile As String, ByVal Tag As Integer) As
    Boolean
        Dim sXMLContents As String

        On Error Resume Next

        XML_Load = False

        If Not mDOMLoaded Then ' No object...
            Exit Function
        ElseIf mDOMFile = UCase(xmlFile) Then ' Already loaded
            XML_Load = True
            Exit Function
        End If

        ' This would be the easiest way to load the file into the parser, but...
        ' Returns an "Access Denied" error in the emulator and on a device
        'xmlDOM.Load xmlFile
        '
        ' Instead, open the XML file with the file control and store the
    contents in a string
        '
        sXMLContents = ReadTextFile(xmlFile)
        If Len(Trim(sXMLContents)) = 0 Then Exit Function ' No contents...

        mDOMFile = ""
        mDOMTag = -1

        ' Load the XML string into the parser
        xmlDOM.loadXML sXMLContents

        ' Check to see if the XML document is valid
        If xmlDOM.parseError.errorCode <> 0 Then Exit Function

        mDOMFile = UCase(xmlFile)
        mDOMTag = Tag

        XML_Load = True
    End Function

    Public Sub XML_Memorise(ByVal SaveState As Boolean)
        On Error Resume Next

        If Not mDOMLoaded Then Exit Sub

        If SaveState Then
            mDOMMemoryFile = mDOMFile
            mDOMMemoryTag = mDOMTag
        ElseIf Len(mDOMMemoryFile) = 0 Then
            XML_Clear
        Else
            XML_Load mDOMMemoryFile, mDOMMemoryTag
        End If
    End Sub

    Public Sub XML_Clear()
        On Error Resume Next
        If Not mDOMLoaded Then Exit Sub
        If Len(mDOMFile) = 0 Then Exit Sub
        xmlDOM.loadXML ""
        mDOMFile = ""
        mDOMTag = -1
    End Sub

    Public Function XML_Instance() As Boolean
        XML_Instance = mDOMLoaded
    End Function

    Public Function XML_Tag() As Integer
        XML_Tag = mDOMTag
    End Function

    Public Function XML_File() As String
        XML_File = mDOMFile
    End Function

    ' Use DOM to get value. Make sure to use LoadXML to set required XML file.
    Public Function XML_Value(ByVal xmlKey As String, ByVal xmlDefault As
    String) As String
        On Error Resume Next

        Dim nodeX As Object ' IXMLDOMNode

        If mDOMLoaded Then
            'Set nodeX = xmlDOM.selectSingleNode(".//" & node_name)
            Set nodeX = xmlDOM.selectSingleNode(xmlKey)
            If nodeX Is Nothing Then
                XML_Value = xmlDefault
            Else
                XML_Value = nodeX.Text
            End If
        Else
            XML_Value = xmlDefault
        End If

    End Function

    ' When key is missing, a new key will be created.
    Public Sub XML_SetValue(ByVal xmlKey As String, ByVal xmlValue As String)
        On Error Resume Next

        If Not mDOMLoaded Then Exit Sub

        Dim nodeX As Object ' IXMLDOMNode

        Set nodeX = xmlDOM.selectSingleNode(xmlKey)
        If nodeX Is Nothing Then
            XML_CreateKey xmlKey
            Set nodeX = xmlDOM.selectSingleNode(xmlKey)
        End If

        nodeX.Text = xmlValue
    End Sub

    Public Sub XML_CreateKey(ByVal xmlKey As String)
        Dim nMark As Long
        Dim nOffset As Long
        Dim sChildKey As String
        Dim sParentKey As String

        Dim parentX As Object
        Dim nodeX As Object ' IXMLDOMNode

        On Error Resume Next

        If Not mDOMLoaded Then Exit Sub

        If Mid(xmlKey, 1, 1) <> "/" Then xmlKey = "/" & xmlKey
        If Right(xmlKey, 1) = "/" Then xmlKey = Mid(xmlKey, 1, Len(xmlKey) - 1)

        nOffset = 2

        Do While True
            If nOffset > Len(xmlKey) Then Exit Do

            sParentKey = Mid(xmlKey, 1, nOffset - 2)

            nMark = InStr(nOffset, xmlKey, "/", vbBinaryCompare)
            If nMark = 0 Then nMark = Len(xmlKey) + 1

            sChildKey = Mid(xmlKey, nOffset, nMark - nOffset)
            nOffset = nMark + 1

            ' Does it exists?
            Set nodeX = xmlDOM.selectSingleNode(sParentKey & "/" & sChildKey)
            If nodeX Is Nothing Then
                ' Nope: Create.

                If Len(sParentKey) = 0 Then
                    Set nodeX = xmlDOM.ownerDocument.createElement(sChildKey)
                    xmlDOM.appendChild nodeX
                Else
                    Set parentX = xmlDOM.selectSingleNode(sParentKey)
                    Set nodeX = parentX.ownerDocument.createElement(sChildKey)
                    parentX.appendChild nodeX
                End If
            End If
        Loop
    End Sub

    Public Function XML_Save(ByVal xmlFile As String) As Boolean
        On Error Resume Next

        XML_Save = CreateTextFile(xmlFile, xmlDOM.xml)
    End Function

    ' --- File read/write methods ---

    Public Function ReadTextFile(ByVal FileName As String) As String
        Dim hFile As Long
        Dim nSize As Long
        Dim Contents As String
        Dim dwRead As Long
        Dim sUnicode As String

        ReadTextFile = ""

        ' get file size
        hFile = CreateFile(FileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)
        If hFile = INVALID_HANDLE_VALUE Then Exit Function

        nSize = GetFileSize(hFile, 0)

        If nSize > 0 Then
            ' allocate space for contents (ANSI = 1 byte/char, but VB stores
    strings as 2 bytes/char)
            If (nSize Mod 2) = 0 Then
                Contents = String(nSize \ 2, 0)
            Else
                Contents = String((nSize \ 2) + 1, 0)
            End If

            ' get contents
            ReadFile hFile, Contents, nSize, dwRead, 0

            ' convert ANSI (1 byte/char) to Unicode (2 bytes/char)
            sUnicode = String(dwRead, 0) ' Unicode is 2 bytes per character
            Call MultiByteToWideChar(CP_ACP, 0, Contents, dwRead, sUnicode,
    dwRead)

            ReadTextFile = sUnicode
        End If

        CloseHandle hFile
    End Function

    Public Function CreateTextFile(ByVal FileName As String, ByRef Contents As
    String) As Boolean
        Dim sANSI As String
        Dim hFile As Long
        Dim lWritten As Long

        On Error Resume Next

        CreateTextFile = False

        ' Create file
        hFile = CreateFile(FileName, GENERIC_READ + GENERIC_WRITE, 0, 0,
    CREATE_ALWAYS, 0, 0)
        If hFile = INVALID_HANDLE_VALUE Then Exit Function

        ' Now convert Unicode contents to ANSI
        sANSI = UnicodeToANSI(Contents)

        ' Write the ANSI bytes
        WriteFile hFile, sANSI, LenB(sANSI), lWritten, 0

        FlushFileBuffers hFile
        CloseHandle hFile

        ' Verify the bytes are written
        CreateTextFile = CBool(lWritten = LenB(sANSI))
    End Function

    ' Convert Unicode (2 bytes/char) to ANSI (1 byte/char)
    '
    ' (Slow) eVB code:
    ' For i = 1 To LenB(ContentsUnicode) Step 2
    ' ContentsANSI = ContentsANSI & MidB(ContentsUnicode, i, 1)
    ' Next
    '
    Public Function UnicodeToANSI(ByVal ContentsUnicode As String) As String
        Dim ContentsANSI As String
        Dim nSize As Long

        nSize = Len(ContentsUnicode)
        ContentsANSI = String((nSize \ 2) + 1, 0) ' VB stores strings as 2
    bytes/char, so you must divide count with 2
        Call WideCharToMultiByte(CP_ACP, 0, ContentsUnicode, nSize,
    ContentsANSI, nSize, 0, 0)

        UnicodeToANSI = MidB(ContentsANSI, 1, nSize)
    End Function

    "Kabouterbond" <kabouterbond@planet.nl> schreef in bericht
    news:cnapdp$54p$1@reader10.wxs.nl...
    > Dear All,
    >
    > I would like te write a programme that converts XML (data) files in to CSV
    > files on the PPC.
    > I already wrote a programme that is able to read and write text files.
    >
    > The problem is I can't find any information about reading XML files in
    > eMbedded Visual Basic.
    >
    > Is there anyone that can help me starting this programme.
    >
    > Some lines of code with explanation would be very nice.
    >
    > Thanks in advance,
    >
    > Alex.
    >
    > --


  • Next message: Taliesyn: "Re: Migrating applications from emVB 3.0 to Windows CE.NET 4.2"

    Relevant Pages

    • Project Error
      ... Private Declare Sub Sleep Lib "Kernel32" ... Dim strDataSrc As String ...
      (microsoft.public.vb.bugs)
    • Re: Is there a way to prevent a RichTextBox from scrolling?
      ... Private _isRegex As Boolean ... Public Sub New(ByVal thispattern As String, ... Dim entry As tDict ...
      (microsoft.public.dotnet.framework.windowsforms.controls)
    • Excel Listing tool using VB
      ... Sub ListFiles2() ... Dim directories() As String, CurrentDirectory As String ... Dim dirtopaste, dirok ...
      (microsoft.public.vb.general.discussion)
    • Form Error
      ... SMSDS_CallerID As String ... Private Declare Sub Sleep Lib "kernel32" ... Dim ComString As String ... Dim AppPath As String, FreeFileNo% ...
      (microsoft.public.vb.bugs)
    • Re: Encrypt/hide Password
      ... Public Sub New(ByVal strCryptoName As String) ... ' instantiated crypto class. ... Dim fsKey As New FileStream(strSaveToPath, FileMode.OpenOrCreate, _ ...
      (microsoft.public.scripting.wsh)

    Loading