I'm trying to figure out whether it's possible to use a dataset's read-xml() method to read in some XML automatically, or if this situation will be yet another "roll-your-own" solution.
Here's what the XML looks like:
<MainTable>
<Field1/>
<Field2/>
<Field3/>
<Subitems>
<Subitem>...</Subitem>
<Subitem>...</Subitem>
</Subitems>
</MainTable>
The above is the XML format that I'm given. I don't have a choice to make them change it to fit ABL constraints.
If I define temp-tables for MainTable and SubItem, I can get read-xml() to populate MainTable, but I can't get it to work for the SubItem temp-table unless I define a fake SubItems temp-table and define a data-relation between my real table and the fake one.
Is there a way to use xpath notation or something like that to give ABL the clue of how my child records are situated?
define temp-table tt-subitem
xml-node-name "SubItems/SubItem"
...
Try this. This loads the XML file into a dynamic dataset for which no temp-table has been defined, then outputs a txt file with the structure and contents of the generated temp-tables.
Good to know: READ-XML on a dataset handle will automatically create all the needed temp-tables and relations.
DEFINE VARIABLE hChildBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hDataset AS HANDLE NO-UNDO.
DEFINE VARIABLE hParentBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE hRelation AS HANDLE NO-UNDO.
DEFINE VARIABLE hTopBuffer AS HANDLE NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE VARIABLE lOK AS LOGICAL NO-UNDO.
CREATE DATASET hDataset.
lOK = hDataset:READ-XML("FILE", "C:\TEMP\myfile.xml", "EMPTY", "", NO).
hTopBuffer = hDataset:GET-TOP-BUFFER().
/* log the received data */
OUTPUT TO c:/temp/mydataset.log.
DO i = 1 TO hDataset:NUM-TOP-BUFFERS:
hTopBuffer = hDataset:GET-TOP-BUFFER(i).
IF VALID-HANDLE(hTopBuffer) THEN DO:
IF hTopBuffer:TABLE-HANDLE:HAS-RECORDS THEN blkRecords: DO:
CREATE QUERY hQuery.
IF NOT hQuery:SET-BUFFERS(hTopBuffer) THEN
LEAVE blkRecords.
IF NOT hQuery:QUERY-PREPARE("FOR EACH " + hTopBuffer:NAME) THEN
LEAVE blkRecords.
IF NOT hQuery:QUERY-OPEN THEN
LEAVE blkRecords.
PUT UNFORMATTED SKIP(1) hTopBuffer:NAME " records:" SKIP "--------------------" SKIP.
REPEAT:
hQuery:GET-NEXT().
IF hQuery:QUERY-OFF-END THEN LEAVE.
PUT UNFORMATTED "- " hTopBuffer:NAME " record, recid: " hTopBuffer:RECID SKIP.
DO j = 1 TO hTopBuffer:NUM-FIELDS:
PUT UNFORMATTED " . " hTopBuffer:BUFFER-FIELD(j):NAME " = " (IF hTopBuffer:BUFFER-FIELD(j):BUFFER-VALUE = ? THEN "<?>" ELSE hTopBuffer:BUFFER-FIELD(j):BUFFER-VALUE) SKIP.
END.
END.
hQuery:QUERY-CLOSE().
DELETE OBJECT hQuery.
END.
END.
END.
PUT UNFORMATTED SKIP(1) "Relations between temp-tables:" SKIP.
DO i = 1 TO hDataset:NUM-RELATIONS:
hRelation = hDataset:GET-RELATION(i).
hParentBuffer = hRelation:PARENT-BUFFER.
hChildBuffer = hRelation:CHILD-BUFFER.
MESSAGE hParentBuffer:NAME "->" hChildBuffer:NAME. /* debug */
PUT UNFORMATTED "* " hParentBuffer:NAME "->" hChildBuffer:NAME SKIP .
DO j = 1 TO hChildBuffer:NUM-FIELDS:
PUT UNFORMATTED " - " hChildBuffer:BUFFER-FIELD(j):NAME " / " hChildBuffer:BUFFER-FIELD(j):DATA-TYPE SKIP .
END.
END.
OUTPUT CLOSE.
You might also want to check this post from Mark Davies. He describes a way to generate a table structure to load the XML file. I have used it on more than one occasion and it works quite well.