Help with Xfiles 4 loading File into Queue with Inner Queues

Hello
I could really use some help loading xml files with Xfiles 4 and unfortunately Bruce Johnson doesn’t have time.

I am trying to load the attached xml file (2023-07-27_7152310.xml) into group (Data.txt attached)

Either way, it’s as if Xfiles doesn’t read more than the first record in the queue.

Is there a kind soul who can tell me what I’m doing wrong?

Thanks

Local data:

str                 StringTheory
xml                 Class(xFilesTree)
NewPointer              Procedure(*CString pGroupName, *CString pColumnName),Derived
End

Code:

        str.LoadFile('2023-07-27_2061266.xml')
      
        Xml.start()
        Xml.SetTagCase(xf:CaseAsIs)
        Xml.Load(workshoporderwarrantycaseto,str,'workshopOrderWarrantyCaseTO')

Local Procedures:

xml.NewPointer                      procedure(*CString pGroupName, *CString pColumnName)
  code 
  Case pGroupName 
  Of 'workshopOrderWarrantyCaseTO'
        Case pColumnName
    Of 'orderClockTOs'   
        workshoporderwarrantycaseto.orderclocktos &= new orderclocktosQueueType
    Of 'orderItemTOs'
        workshoporderwarrantycaseto.orderitemtos &= new orderitemtosQueueType      
    else 
      self.trace('ERROR in xml.NewPointer  pGroupName=' & pGroupName & ' pColumnName=' & pColumnName)    
    End
  else 
    self.trace('ERROR in xml.NewPointer  pGroupName=' & pGroupName & ' pColumnName=' & pColumnName)    
  End  

I am using Clarion 9.1, xFiles 4.24, StringTheory 3.62 and Refelction 1.23.

Data.TXT (3.8 KB)
2023-07-27_7152310.txt (26.8 KB)

Hi,
Run your XML files via https://www.capesoft.com/xfilescode

It shows the following Clarion code:

workshoporderwarrantycaseto Group,Name('workshopOrderWarrantyCaseTO')
dealernumber               Long,Name('dealerNumber')
remoteuser                 STRING(255),Name('remoteUser')
warrantytype               STRING(255),Name('warrantyType')
invoicetype                STRING(255),Name('invoiceType')
appealdone                 Byte,Name('appealDone | boolean')
dissdone                   Byte,Name('dissDone | boolean')
urgent                     Byte,Name('urgent | boolean')
orderto                    Group,Name('orderTO')
accountno                    Long,Name('accountNo')
customerappealdate           STRING(255),Name('customerAppealDate')
orderdate                    STRING(255),Name('orderDate')
department                   STRING(255),Name('department')
ordercontent                 STRING(255),Name('orderContent')
orderno                      Long,Name('orderNo')
ordertype                    Long,Name('orderType')
serviceadvisorname           STRING(255),Name('serviceAdvisorName')
serviceadvisorref            Long,Name('serviceAdvisorRef')
vehicledeliverydate          STRING(255),Name('vehicleDeliveryDate')
vehicleguaranteeextcode      Long,Name('vehicleGuaranteeExtCode')
vehicleguaranteeexttext      Long,Name('vehicleGuaranteeExtText')
vehicletype                  STRING(255),Name('vehicleType')
vehiclemodeldescription      STRING(255),Name('vehicleModelDescription')
vehiclevin                   STRING(255),Name('vehicleVin')
vehiclelicensetag            STRING(255),Name('vehicleLicenseTag')
                           End
orderitemtos               Group,Name('orderItemTOs')
id                           STRING(255),Name('id | attribute')
sequencenumber               STRING(255),Name('sequenceNumber | attribute')
groupnumber                  STRING(255),Name('groupNumber | attribute')
description                  STRING(255),Name('description')
packetto                     Group,Name('packetTO')
id                             STRING(255),Name('id')
packettype                     STRING(255),Name('packetType')
fixedprice                     Real,Name('fixedPrice')
                             End
azcustomto                   Group,Name('azCustomTO')
billingcode                    Long,Name('billingCode')
employeeid                     Long,Name('employeeId')
hourlyrateid                   Long,Name('hourlyRateId')
timeto                         Group,Name('timeTO')
hours                            Long,Name('hours')
unitprice                        Real,Name('unitPrice')
                               End
settlementcode                 STRING(255),Name('settlementCode')
pricegroupto                   Group,Name('priceGroupTO')
price                            Long,Name('price')
                               End
                             End
sparepartto                  Group,Name('sparePartTO')
id                             STRING(255),Name('id')
quantity                       Long,Name('quantity')
unitprice                      Real,Name('unitPrice')
totalpriceexcludingvat         Real,Name('totalPriceExcludingVat')
economy                        Byte,Name('economy | boolean')
billingcode                    STRING(255),Name('billingCode')
discountgroup                  Long,Name('discountGroup')
employeeid                     Long,Name('employeeId')
settlementcode                 STRING(255),Name('settlementCode')
                             End
commentto                    Long,Name('commentTO')
labourto                     Group,Name('labourTO')
id                             Long,Name('id')
timeunits                      Long,Name('timeUnits')
unitprice                      Real,Name('unitPrice')
totalpriceexcludingvat         Real,Name('totalPriceExcludingVat')
billingcode                    Long,Name('billingCode')
hourlyrateid                   Long,Name('hourlyRateId')
employeeid                     Long,Name('employeeId')
                             End
                           End
orderclocktos              Group,Name('orderClockTOs')
in                           STRING(255),Name('in')
out                          STRING(255),Name('out')
time                         STRING(255),Name('time')
employeeref                  Long,Name('employeeRef')
employeename                 STRING(255),Name('employeeName')
timetypecode                 Long,Name('timeTypeCode')
timetypecodetext             STRING(255),Name('timeTypeCodeText')
jobcode                      STRING(255),Name('jobCode')
jobcodetext                  STRING(255),Name('jobCodeText')
ordernumber                  Long,Name('orderNumber')
departmentref                Long,Name('departmentRef')
departmenttext               STRING(255),Name('departmentText')
employeetype                 Long,Name('employeeType')
employeetypetext             STRING(255),Name('employeeTypeText')
employeecategory             STRING(255),Name('employeeCategory')
employeecategorytext         STRING(255),Name('employeeCategoryText')
hourlyratecode               Long,Name('hourlyRateCode')
status                       STRING(255),Name('status')
id                           STRING(255),Name('id')
                           End
                         End

Xml                     xFilesTree

  CODE
  
  !-- Load From StringTheory object into Structure---
  xml.start()
  xml.SetTagCase(xf:CaseAsIs)
  xml.Load(workshoporderwarrantycaseto,SomeLoadString,'workshopOrderWarrantyCaseTO') ! Load From a StringTheory object

Hope this helps.

Regards
Johan de Klerk

Thanks, but the online code generator do not set orderClockTOs and orderItemTOs as queues. There are several of them - not just one.

The demo app sometimes code orderClockTOs and orderItemTOs as queues, and sometime as groups.

So maybe I’m missing something, but I would suspect that if there is more than one, I need them to be queues?

Thanks.

Hi Peter,

I was playing with a similar structure recently, where there are repeated elements rather than the elements being in a container element.

Whilst both are legal in XML, I didn’t find a way to be able to get XFiles4 to read the repeated elements into a queue, so I will be watching this thread to see if someone has an answer.

For clarity for others watching along:

Repeated element example

<invoice>
  <invoiceItem>...</invoiceItem>
  <invoiceItem>...</invoiceItem>
</invoice>

Container Element Example

<invoice>
  <invoiceItems>
    <invoiceItem>...</invoiceItem>
    <invoiceItem>...</invoiceItem>
  </invoiceItems>
</invoice>

Mark

Hi Mark.

At least now I know what the problem is and I could write my way out of it with an extra TAG, but I think xFiles should be able to handle this though.

Hope Bruce sees this so there can be an update

        s# = str.Instring('<orderClockTOs>')
        e# = str.FindLast('</orderClockTOs>')
        stq.SetValue(str.Slice(1,s#) & 'TEST><13,10>')
        stq.Append(str.Slice(s#,e#+17) & '/TEST>')
        stq.Append(str.Slice(e#+17,))

There are some conditions in which what xFiles4 does not get the QUEUEs thing completely right, specially if you not have repeating XML stuff where there is only one record, so you will have to play a bit with the structures.

A group is a queue with only one item.

So the suggestion will be for you take your groups, make them into types, create queue types from the groups types and make all the nested groups into QUEUE references. Adjust your new pointer procedure accordingly.

In the webinar “Fun with XML and JSON” the basic techniques of the generation of those type of nested structures are shown from dictionary entries. The structures you are showing should be able to moved to some type of header.inc file and the basic skeleton used in the example provided in the GitHub repo can possibly be changed to do your structure hierarchy.

@Mark Sarson - Taking the container example you have shown, this is the code I get out of xFiles4:

invoice                  Group,Name('invoice')
invoiceitems               &invoiceitemsQueueType,Name('invoiceItems | queue | RowName()')
                         End
invoiceitemsQueueType    Queue,Type,Name('invoiceItems | RowName()')
invoiceitem                STRING(255),Name('invoiceItem')
                         End


Xml                     Class(xFilesTree)
NewPointer                 Procedure(*Cstring pGroupName, *CString pColumnName),Derived
                         End

  CODE
  
  !-- Load From StringTheory object into Structure---
  xml.start()
  xml.SetTagCase(xf:CaseAsIs)
  xml.Load(invoice,SomeLoadString,'invoice') ! Load From a StringTheory object

  xml.DisposeGroup(invoice) !Optional Safe Tidy up of nested pointers

!--------------------------------------------------------------------------------
!-- Used by Load-Into-Structure
!--------------------------------------------------------------------------------
xml.NewPointer          Procedure(*Cstring pGroupName, *CString pColumnName)
  ! note that pColumnName is the xml tag name, not the label. case sensitive.
  Code
  Case pGroupName
  Of 'invoice'
    Case pColumnName
    Of 'invoiceItems'
      invoice.invoiceitems &= NEW invoiceitemsQueueType  
    Else
      self.trace('ERROR in xml.NewPointer pGroupName=' & pGroupName & ' pColumnName=' & pColumnName)
    End
  Else
    self.trace('ERROR in xml.NewPointer pGroupName=' & pGroupName & ' pColumnName=' & pColumnName)
  End

The thing I would change is to make the invoice also a queue and use a stub example like in the webinar to start the xml reading. But the generated code should work.

Thanks for the input @RobertoArtigas.

In the case of @Peter_Kvist issue, it’s the repeated elements and not the container.

If I get time, I’ll have another play with what I was doing to see if the GROUP, TYPE QUEUE,TYPE makes a difference.

Mark