Results 1 to 15 of 15

Thread: XML Node text and UDT buffer string...!!!

  1. #1

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632

    XML Node text and UDT buffer string...!!!

    OK I have:
    VB Code:
    1. Public Type gtypStructureProps
    2.     IsNew           As Boolean
    3.     IsDirty         As Boolean
    4.     IsDeleted       As Boolean
    5.     Key             As String * 36
    6.     ID              As Long
    7.     Description     As String * 30
    8. End Type
    9.  
    10. Public Type gtypStructureData
    11.     Data            As String * 72
    12. End Type
    Which are the UDTs for my table tblStructures...
    Now, in the load event I have:
    VB Code:
    1. Set adoRec = New Recordset
    2.     With adoRec
    3.         .Open strSQL, DB_CONN, adOpenForwardOnly, adLockReadOnly
    4.         Do While Not .EOF
    5.        
    6.             Set objRoot = objDOM.createElement("Structure")
    7.            
    8.             udtProps.ID = .Fields("ID").Value
    9.             udtProps.Description = .Fields("Description").Value
    10.             udtProps.Key = vbNullString
    11.             udtProps.IsNew = False
    12.             udtProps.IsDirty = False
    13.             udtProps.IsDeleted = False
    14.             LSet udtData = udtProps
    15.                    
    16.             Set objProp = objDOM.createElement("UDT")
    17.             objProp.Text = "Q" & udtData.Data & "P"
    18.             Debug.Print objProp.Text
    19.             Debug.Print udtData.Data
    20.             objRoot.appendChild objProp
    21.             Set objProp = Nothing
    My udtData.Data is a string and contains the data from the props UDT, and the debug.print statement proves that it contains the correct data...HOWEVER! When I assign this string to the text property of an XML node all the data vanishes!!!
    The debug.Print objProp.Text just prints "Q" to the immediate window...the trailing "P" AND all the data vanishes!!!
    Is there something up with XML that stops me doing this???

    Woka

  2. #2

  3. #3
    Let me in .. techyspecy's Avatar
    Join Date
    Aug 2002
    Location
    Back to VBF.
    Posts
    2,456
    This is weird .. Post the code project if you can ...
    Last edited by techyspecy; Jun 18th, 2003 at 08:39 AM.

  4. #4
    Addicted Member
    Join Date
    Mar 2003
    Location
    Minneapolis, MN
    Posts
    151
    I believe the problem lies in that a buffered UDT containing non-string data, packs the data for those data-types.

    If you place a break point in your code following the LSet udtData = udtProps and then hover over the udtData.Data in your Debug.Print statement, you will find that the first three positions of the buffered string will contain either a "?" if the value of a boolean is True or a box if the value is false. Also in the positions following the 36 positions for the .Key element, you will find non-printable characters containing the packed Long (.ID element).

    The .Text property of the DOM's Element may not be accepting the packed values.

    One way to verify this is to rearrange the elements of your Props UDT, placing all of the string elements at the beginning. What I would expect then is that you would have the values of the Key and Description elements set to the .Text property, but lose the IsNew, IsDirty, IsDeleted, and ID elements.

    What you may need to do, is convert the elements in the UDT to store fixed-length strings for the IsNew, IsDirty, IsDeleted, and ID elements. This way, the data is not packed and the buffered string will contain nothing but printable-characters.

  5. #5

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Originally posted by MartinLiss
    Does objProp.Text = "Q" & CStr(udtData.Data) & "P" make any difference?
    Nope, it just prints "Q"


    So, ALL my properties in the UDT must be string...Hmmmm...

    i am afraid I can't post the code as it's a small part of very large project and complex TCP/IP activeX EXE's which read from other processes memories...

    It take 12 seconds to load and populate a class structure with 4000 items using an XMLnode for each field...it takes 1.2 seconds using one node...but the data that is passed is incorrect...


    Putting all the string varible at the top of the UDT does,'t work, as what if the 1st few are blank???

    I am not happy at all with this...It should work..!!!

    Woka *sob*

  6. #6

  7. #7

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    I have coming to the conclusion that using XML to pass data round is pretty crap
    Very slow with large amounts of data and is a pain in the arse to do simple things, like above...

    I really should have stuck to property bags...

    Woka

  8. #8

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    NODE_CDATA_SECTION
    Has an interface type of:
    XMLDOMCDATASection

    Can have the following children types:
    None



    Sometimes you will want to insert unusual characters in your XML Nodes. To do this, you need to use a CDATA section (also known as a Marked section).

    Yes, we know that you can also use built-in entities instead of a CDATA section, but there are currently only five of these built-in entities that the DOMDocument will parse. (See the XMLDOMEntity object section earlier in this chapter.)

    But built-in entities don't sort out all our problems. What do we do about a hash character (#)? An XML parser does not allow you to use a # character in your XML, but there is no DOMDocument built-in entity for a # character.

    Note
    Built-in entities are like VB constants, but they are built into XML. Because XML has certain characters that are used specifically for XML (like a < character), you can use the entity to represent your character.

    Here we talk specifically about what the DOMDocument can parse. Many browsers support numerous entities that they recognize, but the DOMDocument seems to support only these five built-in entities.

    To use a CDATA section this in our XML code, instead of declaring an element in the DTD as CDATA element, we can use the following in our XML code:

    ![CDATA[]]

    Here is an example of an element that uses a CDATA section with a # in it:

    <ADDRESS><![CDATA[#911 Somewhere Circle, Canberra, Australia]]></ADDRESS>

    Note
    If you do a Select Case in VB to find the enumeration of a Node, using the NODE_TEXT you will miss the text that is put into CDATA sections to protect reserved characters. Therefore, don't forget to look for NODE_CDATA_SECTION in your Select Case.

    A CDATA section Node can be the child Node of Elements, EntityReferences, and DocumentFragments.

    If you try to use an Entity in a CDATA section, the entity will not be parsed, and therefore not interpreted. For example the following XML code is embedded in a CDATA section:

    <ADDRESS><![CDATA[#911 O&apos;Hara Circle, Canberra, Australia]]></ADDRESS>

    Did you note the &apos; entity? The &apos; entity represents an ' (apostrophe) and we would expect the output to display O` Hara Circle, wouldn't we? However, this will not be interpreted as O'Hara Circle, because the text is contained in CDATA section and won't be parsed. When we examine the above XML code from VB, using the nodeTypedValue property to get the value of the element, we observe the following:

    strValue = objXMLElement.nodeTypedValue

    strValue returns: #911 O&apos;Hara Circle, Canberra, Australia.

    Note
    When you allow users to add data to a DOMDocument, don't forget to check for any unparsable characters. Embed these unparsable characters in a CDATA section before saving the DOMDocument. If you do not this, when someone has typed in an apostrophe in one of the fields (e.g., O'Mally), the DOMDocument will save this and return no errors. However, when you try to load this saved XML file into the DOMDocument, you will receive an error because of this unparsable character.
    I wonder....Hmmmmmmmmmmmmm

    Woka

  9. #9
    Addicted Member
    Join Date
    Mar 2003
    Location
    Minneapolis, MN
    Posts
    151
    Why not stick with what you've already started. Using buffered UDT's.

    What the following does is create a large buffered string containing a collection of buffered UDT's.

    VB Code:
    1. Attribute VB_Name = "basGlobal"
    2. ' Application  : ColBuffer (CollectionBuffer Utility Object Library)
    3. ' Object       : basGlobal
    4. ' Purpose      : Provides a centralized location for the declaration of
    5. '                variables, constants, objects, and methods that can be
    6. '                used by any object in the application.
    7.  
    8. Option Explicit
    9.  
    10. ' UDT containing the information about the collection of data contained
    11. ' in the buffer.
    12. Public Type type_CollectionAttributes
    13.   intLength         As Integer
    14.   lngEstimatedCount As Long
    15.   lngMaximumCount   As Long
    16.   lngCount          As Long
    17. End Type
    18.  
    19. ' UDT containing a buffered copy of the type_CollectionAttributes UDT.
    20. Public Type type_CollectionAttributesBuffer
    21.   strBuffer As String * 8
    22. End Type
    23.  
    24. ' Provides self-documenting code for custom Error Numbers.
    25. Public Const gc_lngNotInitialized As Long = 5000

    VB Code:
    1. VERSION 1.0 CLASS
    2. BEGIN
    3.   MultiUse = -1  'True
    4.   Persistable = 0  'NotPersistable
    5.   DataBindingBehavior = 0  'vbNone
    6.   DataSourceBehavior  = 0  'vbNone
    7.   MTSTransactionMode  = 0  'NotAnMTSObject
    8. END
    9. Attribute VB_Name = "clsCollectionBuffer"
    10. Attribute VB_GlobalNameSpace = False
    11. Attribute VB_Creatable = True
    12. Attribute VB_PredeclaredId = False
    13. Attribute VB_Exposed = True
    14. ' Application  : ColBuffer (CollectionBuffer Utility Object Library)
    15. ' Object       : clsCollectionBuffer
    16. ' Purpose      : Defines the CollectionBuffer utility object.
    17.  
    18. Option Explicit
    19.  
    20. ' Identifies the point in the buffered string where the data actually
    21. ' starts.
    22. Private Const mc_intDataStartingPosition As Integer = 9
    23. ' Member instance of the type_CollectionAttributes global UDT.
    24. Private m_udtAttributes As type_CollectionAttributes
    25. ' Member string containing the current data buffer.
    26. Public m_strBuffer As String
    27. ' Member long containing the current insertion point in the data buffer.
    28. Public m_lngPosition As Long
    29. ' Member boolean indicating whether or not an instance of the
    30. ' CollectionBuffer has been initialized.
    31. Public m_blnInitialized As Boolean
    32.  
    33.  
    34. Public Sub AddItem(ByVal strData As String)
    35.   ' Purpose  : Adds a data string to the data buffer.
    36.   ' Accepts  : strData    A string containing the Item to be added to the
    37.   '                       data buffer.
    38.   ' Returns  : n/a
    39.  
    40.   ' If the CollectionBuffer has not been initialized, then return to
    41.   ' the calling procedure and report the error.
    42.   If Not m_blnInitialized Then
    43.     Err.Raise Number:=vbObjectError + gc_lngNotInitialized, _
    44.               Source:=App.Title & "::" & TypeName(Me) & ":AddItem", _
    45.               Description:="Object not initialized"
    46.   Else
    47.     With m_udtAttributes
    48.       ' If the data buffer is full, then increase it enough for the
    49.       ' new Item to be added.
    50.       If .lngCount = .lngMaximumCount Then
    51.         m_strBuffer = m_strBuffer & Space$(.intLength)
    52.         .lngMaximumCount = .lngMaximumCount + 1
    53.       End If
    54.       ' Add the Item to the data buffer
    55.       Mid$(m_strBuffer, m_lngPosition, .intLength) = strData
    56.       ' Set the new current insertion point within the data buffer.
    57.       m_lngPosition = m_lngPosition + .intLength
    58.       ' Increment the Item count.
    59.       .lngCount = .lngCount + 1
    60.     End With
    61.   End If
    62.  
    63. End Sub
    64.  
    65.  
    66. Public Function Count() As Long
    67.   ' Purpose  : Returns the number of Items in the CollectionBuffer.
    68.   ' Accepts  : n/a
    69.   ' Returns  : A long indicating the number of Items in the data buffer.
    70.  
    71.   ' If the CollectionBuffer has not been initialized, then return zero.
    72.   If Not m_blnInitialized Then
    73.     Count = 0
    74.   ElseIf m_udtAttributes.lngCount > 2090000 Then
    75.     Count = 0
    76.   ' Return the number of Items in the data buffer.
    77.   Else
    78.     Count = m_udtAttributes.lngCount
    79.   End If
    80.  
    81. End Function
    82.  
    83.  
    84. Public Function GetData() As String
    85.   ' Purpose  : Returns the data buffer to the calling procedure.
    86.   ' Accepts  : n/a
    87.   ' Returns  : A string containing the data buffer.
    88.  
    89.   Dim udtBuffer As type_CollectionAttributesBuffer
    90.  
    91.   ' Copy the CollectionBuffer attributes to a buffered string.
    92.   LSet udtBuffer = m_udtAttributes
    93.   ' Set the reserved space of the data buffer to the CollectionBuffer
    94.   ' attributes.
    95.   If m_strBuffer <> "" Then
    96.     Mid$(m_strBuffer, 1, Len(udtBuffer)) = udtBuffer.strBuffer
    97.     ' Record the data buffer to be returned.
    98.     GetData = Left$(m_strBuffer, m_lngPosition)
    99.   Else
    100.     GetData = ""
    101.   End If
    102.  
    103. End Function
    104.  
    105.  
    106. Public Sub Initialize(ByVal intLength As Integer, _
    107.                       ByVal lngEstimatedCount As Long)
    108.   ' Purpose  : Initializes the CollectionBuffer making it ready to
    109.   '            receive and store data.
    110.   ' Accepts  : intLength            An integer indicating the length of
    111.   '                                 each Item to be added to the data
    112.   '                                 buffer.
    113.   '            lngEstimatedCount    A long indicating the estimated
    114.   '                                 number of Items that will be added
    115.   '                                 to the data buffer
    116.   ' Returns  : n/a
    117.  
    118.   ' If the CollectionBuffer has already been initialized, then don't let
    119.   ' it be initialized again.
    120.   If m_blnInitialized Then Exit Sub
    121.   With m_udtAttributes
    122.     ' Set the attributes for the CollectionBuffer
    123.     .intLength = intLength
    124.     .lngEstimatedCount = lngEstimatedCount
    125.     .lngMaximumCount = lngEstimatedCount
    126.     ' Create a buffered string big enough to hold the estimated number
    127.     ' of Items.
    128.     m_strBuffer = Space$((mc_intDataStartingPosition + _
    129.                           .lngMaximumCount) * .intLength)
    130.     ' Set the current insertion point for the data buffer.
    131.     m_lngPosition = mc_intDataStartingPosition
    132.   End With
    133.   ' Indicate that the CollectionBuffer has been initialized
    134.   m_blnInitialized = True
    135.  
    136. End Sub
    137.  
    138.  
    139. Public Function IsInitialized() As Boolean
    140.   ' Purpose  : Returns whether or not the CollectionBuffer has been
    141.   '            initialized.
    142.   ' Accepts  : n/a
    143.   ' Returns  : A boolean indicating whether or not the CollectionBuffer
    144.   '            has been initialized.
    145.   IsInitialized = m_blnInitialized
    146.  
    147. End Function
    148.  
    149.  
    150. Public Function Item(ByVal lngIndex As Long) As String
    151.   ' Purpose  : Returns the Item for the specified position within the
    152.   '            data buffer.
    153.   ' Accepts  : lngIndex   A long indicating which Item to return.
    154.   ' Returns  : A string containing the Item from the data buffer.
    155.  
    156.   ' If the CollectionBuffer has not been initialized, then an empty
    157.   ' string to the calling procedure.
    158.   If Not m_blnInitialized Then
    159.     Item = ""
    160.   Else
    161.     With m_udtAttributes
    162.       ' Attempt to return the requested Item from the data buffer.
    163.       Item = Mid$(m_strBuffer, mc_intDataStartingPosition + _
    164.                  (lngIndex - 1) * .intLength, .intLength)
    165.     End With
    166.   End If
    167.  
    168. End Function
    169.  
    170.  
    171. Public Sub SetData(ByVal strDataBuffer As String)
    172.   ' Purpose  : Populates an unpopulated CollectionBuffer with a data
    173.   '            buffer.
    174.   ' Accepts  : strDataBuffer    A string containing the data buffer to
    175.   '                             bo stored.
    176.   ' Returns  : n/a
    177.  
    178.   Dim udtBuffer As type_CollectionAttributesBuffer
    179.  
    180.   ' Retrieve the CollectionBuffer attributes from the data buffer.
    181.   udtBuffer.strBuffer = Mid$(strDataBuffer, 1, Len(udtBuffer.strBuffer))
    182.   LSet m_udtAttributes = udtBuffer
    183.   ' Store the data buffer.
    184.   m_strBuffer = strDataBuffer
    185.   ' Indicate that the CollectionBuffer has been initialized.
    186.   m_blnInitialized = True
    187.  
    188. End Sub
    189.  
    190.  
    191. Private Sub Class_Initialize()
    192.   ' Purpose  : Initialize variables and objects used by this Class.
    193.   ' Accepts  : n/a
    194.   ' Returns  : n/a
    195.  
    196.   ' Initialize the CollectionBuffer attributes.
    197.   With m_udtAttributes
    198.     .intLength = 0
    199.     .lngEstimatedCount = 0
    200.     .lngMaximumCount = 0
    201.     .lngCount = 0
    202.   End With
    203.  
    204. End Sub
    205.  
    206.  
    207. Private Sub Class_Terminate()
    208.   ' Purpose  : Destroys variables and objects used by this Class.
    209.  
    210.   ' Clear the CollectionBuffer attributes.
    211.   With m_udtAttributes
    212.     .intLength = 0
    213.     .lngEstimatedCount = 0
    214.     .lngMaximumCount = 0
    215.     .lngCount = 0
    216.   End With
    217.  
    218. End Sub

  10. #10
    Hyperactive Member
    Join Date
    Sep 2001
    Location
    San Jose, Ca. - USA
    Posts
    302
    Might I suggest using the DataBagLib Library at Killervb.com

    here's a description of it from the site:
    The DataBag is a light-weight Recordset-like object that's serializable. This is perfect for storing structured data that's not suitable for a database, and when you need to pass the data between two processes via a Winsock socket, or DCOM. The DataBag is very fast and the serializable data structure produces a small compressed footprint.

    It doesn't use xml and it's slower to fill with data versus a stongly typed collection, but it seems to have been built for what you are doing. This code has a method for righting it's structure to a uncompressed or compressed text file, maybe you can alter it to xml if you really need that.

    Now that I think about it this might not be a good work around for you.

  11. #11

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    I used to use that buffer class to create a string of UDT's, but it doesn't do parent child relationships Very limited.

    Jerky boy, I used to use a property bag, which does the trick perfectly, but I was led to believe XML was the way to go...I would never use a 3rd party control like that, I would write my own...cheers anyways.

    Am still working on XML...

    Woka

  12. #12
    Hyperactive Member
    Join Date
    Sep 2001
    Location
    San Jose, Ca. - USA
    Posts
    302
    Woka, I understand how you wouldn't want to use a third party control. But all the libraries at that site come with full source code for free! I try to only recommend things that come with source because I don't like how some people just want the controls or libraries handed over without ubderstanding how they work.

    Although I have not used XML, I have read a lot about it (hopefully, I understand it). I agree with you it seems like a silly way about doing things, good luck with that.

  13. #13
    The picture isn't missing BuggyProgrammer's Avatar
    Join Date
    Oct 2000
    Location
    Vancouver, Canada
    Posts
    5,217
    could it be because

    udtData.Data

    contains a Null at the end?
    Remember, if someone's post was not helpful, you can always rate their post negatively .

  14. #14

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Yea, just found that it's the vbNullChar that it doesn't like...Hmmmmm
    OK...
    Done some more bench testing...
    It's the loading that takes all the time...sorry I'll explain a bit more...
    I can populate a DOM, and pass it back to the XML strign back to my objects DLL in 2 seconds...it's getting the data back out of the DOM that's slow...
    VB Code:
    1. Friend Property Set State(ByRef pobjValue As IXMLDOMNode)
    2. Dim objNode     As IXMLDOMNode
    3.     With mudtProps
    4.         .IsNew = pobjValue.selectSingleNode("IsNew").Text
    5.         .IsDirty = pobjValue.selectSingleNode("IsDirty").Text
    6.         .IsDeleted = pobjValue.selectSingleNode("IsDeleted").Text
    7.         .ID = pobjValue.Attributes.getNamedItem("ID").Text
    8.         .Key = pobjValue.selectSingleNode("Key").Text
    9.         .Description = pobjValue.selectSingleNode("Description").Text
    10.     End With
    11.     Set objNode = pobjValue.selectSingleNode("Recipes")
    12.     If Not objNode Is Nothing Then
    13.         Set mobjRecipes = New Recipes
    14.         Set mobjRecipes.State = objNode
    15.         Set objNode = Nothing
    16.     End If
    17. End Property
    That is what I am having to use instead of the Data.Buffer UDT...This code looks wrong, is there a way I can speed it up using .NextNode or something?

    Woka

  15. #15

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632
    Right...after further bench testing I have this:

    Here are the times it takes to load x many records to the client...

    2000 takes 1850 ms
    4000 takes 12352 ms
    8000 takes 59456 ms

    The speed goes UP exponentially! Which IS NOT good...for now anyways, I am switching back to property bags...I have no use for XML whatso ever...in fact, I'd prefer to pass a disconnected recordset to the client UI Hahahaha...and some people know what my feeling on that is...

    However, if anyone can shed some light on the problem above then I would be very grateful...

    Woka

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width