Eduard Lebedyuk · Nov 30, 2022

Iterating HS.SDA3.Container container twice

I initialize a HS.SDA3.Container from a XML stream and I need to iterate over it twice. What is a correct way of doing it? Is it enough to adjust StreamPos/StreamOref?

The optimal solution would be to use one loop, but it's not possible to combine the processing logic.

set oSDA = ##class(HS.SDA3.Container).%New()
do oSDA.InitializeXMLParse(.tQuickStream)

while oSDA.GetNextSDA(.tType, .tPatient) {
        // processing logic A

set oSDA.StreamPos = 1
do oSDA.StreamOref.Rewind()

while oSDA.GetNextSDA(.tType, .tPatient) {
        // processing logic B
Product version: IRIS 2022.1
0 227
Discussion (4)2
Log in or sign up to continue

is the stream modified during logic A; I mean, why not to apply logicA & logicB at the same time? where is the restriction for that? 

InitializeXMLParse does a lot of necessary things including the following:

  1. Calls Rewind() on its stream property
  2. Uses XSL "OrderSDAElements" or "OrderSDAElementsEdge" to sort the SDA objects in the container.
  3. Replace the stream property on HS.SDA3.Container  with the sorted one
  4. Call Rewind() again and initialize a StreamPos property to 1   // This is used by FillBuffer()
  5. Initialize the ..StreamBuffer with the first 3600000 bytes of the stream 

This is a lot of overhead.  Also, "do oSDA.StreamOref.Rewind()" and "oSDA.StreamPos = 1" fails to re-initialize the ..StreamBuffer.

My suggestion would be to declare a MultiDimensional property in your class:
Property %sdaclass [ MultiDimensional, Private ];

Then follwing any call to GetNextSDA, save the SDA class in the MultiDimensional:
set ..%sdaclass($increment(%sdaclass))=tPatient     // replace tPatient with variable returned by GetNextSDA 

Your second pass can simply iterate over the MultiDimensional:
set subscript=""
for {
   set subscript=$order(..%sdaclass(subscript))

    set sdaclass=..%sdaclass(subscript)

    ... processing logic B


Thanks for that detailed reply, @Michael Cronin.

This is a lot of overhead.  Also, "do oSDA.StreamOref.Rewind()" and "oSDA.StreamPos = 1" fails to re-initialize the ..StreamBuffer.

That (StreamBuffer reinitialization by calling FillBuffer) is the first thing GetNextSDA does, so I thought it's okay? Is it not?