How to create nested Json using Capesoft JFile?

Hi there,

I have read through JFiles doc and am still confused with how to create nested Json file. Here is a simple structure:

Buffer          QUEUE,PRE(BUF)
ID                  LONG
Name                STRING(30)
                END
                
Images          QUEUE,PRE(IMG)
ID                  LONG
FileName            STRING(100)
                END

I would like the Images queue to be nested in Buffer, i.e., each record in Buffer queue can have multiple Images records. PS, I have learnt and is able to create single level JSON by: JSon.Save(Buffer, ‘output.json’)

Thanks a lot.

Hi Tony,

I put together an example JSON structure that I believe matches what you’re aiming for:

[
  {
    "ID": 1,
    "Name": "John",
    "Images": [
      { "ID": 101, "FileName": "john_photo1.jpg" },
      { "ID": 102, "FileName": "john_photo2.jpg" }
    ]
  },
  {
    "ID": 2,
    "Name": "Alice",
    "Images": [
      { "ID": 201, "FileName": "alice_profile.png" },
      { "ID": 202, "FileName": "alice_event.jpg" }
    ]
  }
]

I then used the jFilesCode tool to generate the structure code, and added some sample data to the queues based on what it provided.

    PROGRAM

    INCLUDE('JFiles.inc')
    INCLUDE('StringTheory.inc')

Buffer                  QUEUE, NAME('Buffer')
ID                         LONG, NAME('ID')
Name                       STRING(255), NAME('Name| opt')
Images                     &ImagesQueueType, NAME('Images| opt | queue')
                    END

ImagesQueueType           QUEUE, TYPE, NAME('Images')
ID                         LONG, NAME('ID')
FileName                   STRING(255), NAME('FileName')
                        END

st                        StringTheory
json                      jsonClass

    CODE

    ! --- First Buffer: John ---
    
    Buffer.ID = 1
    Buffer.Name = 'John'
    
    Buffer.Images &= NEW(ImagesQueueType)
    Buffer.Images.ID = 101
    Buffer.Images.FileName = 'john_photo1.jpg'
    ADD(Buffer.Images)

    Buffer.Images.ID = 102
    Buffer.Images.FileName = 'john_photo2.jpg'
    ADD(Buffer.Images)
    ADD(Buffer)
    ! --- Second Buffer: Alice ---
    
    Buffer.ID = 2
    Buffer.Name = 'Alice'

    Buffer.Images &= NEW(ImagesQueueType)
    Buffer.Images.ID = 201
    Buffer.Images.FileName = 'alice_profile.png'
    ADD(Buffer.Images)

    Buffer.Images.ID = 202
    Buffer.Images.FileName = 'alice_event.jpg'
    ADD(Buffer.Images)

    ADD(Buffer)
    ! --- Serialize with JFiles ---
    json.start()
    json.SetTagCase(jf:CaseAsIs)
    json.SetDontSaveBlanks(true)
    json.SetDontSaveBlankArrays(true)
    json.SetDontSaveBlankArrayValues(true)
    json.SetDontSaveBlankGroups(true)

    json.Save(Buffer, st)

    MESSAGE(st.GetValue(), 'Nested JSON Output')

    ! --- Optional cleanup ---
    json.DisposeQueue(Buffer)

Hopefully this gives you a working starting point!

Mark

2 Likes

Hi Mark,

Thanks for your reply, I think this is quite close but I got some strange results from your code:

[
	{
		"ID" : 1,
		"Name" : "John",
		"Images" : "( h\u0000"
	},
	{
		"ID" : 2,
		"Name" : "Alice",
		"Images" : " h\u0000"
	}
]

Any ideas?

I did have a bug I noticed after the post, and fixed as quick as I could, so maybe try again?

Running the above code on my end shows

[
	{
		"ID" : 1,
		"Name" : "John",
		"Images" : [
			{
				"ID" : 101,
				"FileName" : "john_photo1.jpg"
			},
			{
				"ID" : 102,
				"FileName" : "john_photo2.jpg"
			}
		]
	},
	{
		"ID" : 2,
		"Name" : "Alice",
		"Images" : [
			{
				"ID" : 201,
				"FileName" : "alice_profile.png"
			},
			{
				"ID" : 202,
				"FileName" : "alice_event.jpg"
			}
		]
	}
]

I am having the same odd result, maybe is because of the template versions? I am using jFiles 1.86 and StringTheory 3.6

Ah, sorry about that —

I was using jFiles 3 for the example, and I’d definitely recommend upgrading if possible.

You might still be able to achieve similar results with jFiles 1, but it’s been so long since I last used that version that I’m afraid I wouldn’t be much help there.

jFiles 3 adds a lot of functionality and really simplifies working with JSON — both reading and writing become much easier.

Mark

Thanks Mark, I will have it a try.

Hello there, I’m Julio, sorry but I have a similar problem in my result, it’s like this:

[
	{
		"numero_reserva" : "  59839",
		"tipo_cuarto" : "BWD",
		"cuarto" : "211",
		"fecha_llegada" : "2025-10-01",
		"fecha_salida" : "2025-11-15",
		"estatus" : "En Casa",
		"importes_por_noche" : "(\\�\u0001"
	}
]

I’m using JFiles 3.09 and StringTheory 3.70.
I’m new to Clarion and this forum, can I take help in this post or I need to create a new one?

Thanks.

What does you Clarion Queue structure look like? What JSON are you trying to achieve?

Have you tried feeding the JSON you want into https://capesoft.com/jfilescode
?

Hi Bruce, thank you for the answer.
This is an example for the structure what I need:

[
    {
        "numero_reserva": "14236",
        "tipo_cuarto": "STD",
        "cuarto": "101",
        "fecha_llegada": "2025-12-25",
        "fecha_salida": "2025-12-30",
        "estatus": "Garantizada",
        "codigo_tarifa": "RACK",
        "importes_por_noche": [
            {
                "fecha_aplicacion": "2025-12-25",
                "importe_s/impuestos": 840.34,
                "importe_c/impuestos": 1000
            },
            {
                "fecha_aplicacion": "2025-12-26",
                "importe_s/impuestos": 840.34,
                "importe_c/impuestos": 1000
            },
            {
                "fecha_aplicacion": "2025-12-27",
                "importe_s/impuestos": 840.34,
                "importe_c/impuestos": 1000
            },
            {
                "fecha_aplicacion": "2025-12-28",
                "importe_s/impuestos": 840.34,
                "importe_c/impuestos": 1000
            },
            {
                "fecha_aplicacion": "2025-12-29",
                "importe_s/impuestos": 840.34,
                "importe_c/impuestos": 1000
            }
        ]
    },
    {
        "numero_reserva": "14237",
        "tipo_cuarto": "STD",
        "fecha_llegada": "2025-12-26",
        "fecha_salida": "2025-12-28",
        "estatus": "No garantizada",
        "codigo_tarifa": "RACK",
        "importes_por_noche": [
            {
                "fecha_aplicacion": "2025-12-26",
                "importe_s/impuestos": 840.34,
                "importe_c/impuestos": 1000
            },
            {
                "fecha_aplicacion": "2025-12-27",
                "importe_s/impuestos": 840.34,
                "importe_c/impuestos": 1000
            }
        ]
    }
]

Have you tried feeding the JSON you want into https:// capesoft .com/jfilescode ?

Yes, I use the code exactly as it appears on the page, then I just fill the queues, but I get the error I posted before.
This is my queues definition:

response                    QUEUE,NAME('response')
numero_reserva                  STRING(7),NAME('numero_reserva| opt')
tipo_cuarto                     STRING(6),NAME('tipo_cuarto| opt')
cuarto                          STRING(4),NAME('cuarto| opt')
fecha_llegada                   STRING(10),NAME('fecha_llegada| opt')
fecha_salida                    STRING(10),NAME('fecha_salida| opt')
estatus                         STRING(20),NAME('estatus| opt')
codigo_tarifa                   STRING(8),NAME('codigo_tarifa| opt')
importes_por_noche              &importes_por_noche_QT,NAME('importes_por_noche| opt | queue')
                            END

importes_por_noche_QT       QUEUE,TYPE,NAME('importes_por_noche')
fecha_aplicacion                STRING(10),NAME('fecha_aplicacion')
importe_simpuestos              REAL,NAME('importe_s/impuestos')
importe_cimpuestos              REAL,NAME('importe_c/impuestos')
                            END

Show us your code for filling the queues, and the code you are calling jFiles with.

response                    QUEUE,NAME('response')
numero_reserva                  STRING(7),NAME('numero_reserva| opt')
tipo_cuarto                     STRING(6),NAME('tipo_cuarto| opt')
cuarto                          STRING(4),NAME('cuarto| opt')
fecha_llegada                   STRING(10),NAME('fecha_llegada| opt')
fecha_salida                    STRING(10),NAME('fecha_salida| opt')
estatus                         STRING(20),NAME('estatus| opt')
codigo_tarifa                   STRING(8),NAME('codigo_tarifa| opt')
importes_por_noche              &importes_por_noche_QT,NAME('importes_por_noche| opt | queue')
                            END

importes_por_noche_QT       QUEUE,TYPE,NAME('importes_por_noche')
fecha_aplicacion                STRING(10),NAME('fecha_aplicacion')
importe_simpuestos              REAL,NAME('importe_s/impuestos')
importe_cimpuestos              REAL,NAME('importe_c/impuestos')
                            END

request              QUEUE,PRE(QREQ),NAME('request')       ! 
hotel_id             LONG,NAME('hotel_id')                 ! 
fecha_inicio         STRING(10),NAME('fecha_inicio')       ! 
fecha_final          STRING(10),NAME('fecha_final')        ! 
                     END 

json                        JSONClass
requestJSON                 StringTheory
responseJSON                StringTheory

        CODE
        DO OpenFiles
        requestJSON.Start()
        requestJSON.SetValue(pStringJson)
        json.Start()
        json.SetTagCase(jF:CaseAsIs)
        json.Load(request, requestJSON)
        GET(request, 1)
        IF NOT ERRORCODE()
            CargarColaResponse(FORMAT(DEFORMAT(QREQ:fecha_inicio, @D10-), @D12), FORMAT(DEFORMAT(QREQ:fecha_final, @D10-), @D12))
            json.SetDontSaveBlanks(true)
            json.SetDontSaveBlankArrays(true)
            json.SetDontSaveBlankArrayValues(true)
            json.SetDontSaveBlankGroups(true)
            json.Save(response, responseJSON)
            MESSAGE(responseJSON.GetValue(), 'Reservas en Periodo')
        END
        DO CloseFiles


CargarColaResponse  PROCEDURE(STRING pFechaInicial, STRING pFechaFinal)
    CODE
        json.DisposeQueue(response)
        CLEAR(HRES:Record)
        HRES:SRESFECSAL = pFechaInicial
        SET(HRES:KEY_HPDSALI, HRES:KEY_HPDSALI)
        LOOP
            NEXT(HPDRESE)
            IF ERRORCODE() THEN BREAK END
            IF NOT HRES:SRESNUMRES THEN CYCLE END
            IF HRES:SRESTIPFOL = '3' THEN CYCLE END
            IF HRES:SRESDUPLI <> '' THEN CYCLE END
            IF HRES:SRESESTRES = '3' OR HRES:SRESESTRES = '6' THEN CYCLE END
            IF HRES:SRESESTRES = '5'
                IF HRES:SRESCVEGPL <> '1' THEN CYCLE END
            END
            IF HRES:SRESFECLLE > pFechaFinal THEN CYCLE END
            IF HRES:SRESCVEGPL = '1'
                IF HRES:SRESFECLLE = HRES:SRESFECSAL OR HRES:SRESFECLLE > HRES:SRESFECSAL OR NOT HRES:SRESFECLLE OR NOT HRES:SRESFECSAL OR HRES:SRESFECLLE > pFechaFinal THEN CYCLE END
                ! Si es Folio Externo CYCLE
                IF HRES:SRESNUMCTO
                    CCTOS:SCTONUMCTO=HRES:SRESNUMCTO
                    GET(HCACTOS,CCTOS:KEY_HCACTOS)
                    IF NOT ERRORCODE() 
                        IF CCTOS:SCTODUMY='S' THEN CYCLE END 
                    END 
                END
                
                CLEAR(response)
                
                response.numero_reserva = HRES:SRESNUMRES
                response.tipo_cuarto = HRES:SRESTIPCTO
                IF HRES:SRESNUMCTO THEN response.cuarto = HRES:SRESNUMCTO END
                response.fecha_llegada = FORMAT(DEFORMAT(HRES:SRESFECLLE, @D12), @D010-)
                response.fecha_salida = FORMAT(DEFORMAT(HRES:SRESFECSAL, @D12), @D010-)
                CASE HRES:SRESESTRES
                OF NoGarantizada
                    response.estatus = 'No Garantizada'
                OF Garantizada
                    response.estatus = 'Garantizada'
                OF EnCasa
                    response.estatus = 'En Casa'
                OF SalidaEfectuada
                    response.estatus = 'Salida Efectuada'
                END
                IF HRES:SRESCODTAR THEN response.codigo_tarifa = HRES:SRESCODTAR END
                
                response.importes_por_noche &= NEW(importes_por_noche_QT)
                response.importes_por_noche.importe_simpuestos = 840.34
                response.importes_por_noche.importe_cimpuestos = 1000
                ADD(response.importes_por_noche)
                CLEAR(response.importes_por_noche)
                
                ADD(response)
                CLEAR(response)
            END
        END

It’s a try to understand how to use JFiles to extract info on TPS.