I have to produce an XML file out of a SAS dataset. The format of the XML file is defined very strictly and I need to match it exactly. I'm using SAS 9.4 (note: and stuck with it!) and utilizing XMLMAPs and libname xmlv2. I feel like I'm very close to a solution, but there's a final hurdle that I cannot seem to pass!
The XML file has a 3-level structure, with a single lvl 2 element holding all the lvl 3 elements. Whatever I try, all my lvl 3 elements seem to spawn their own lvl 2 elements. It seems that the SAS xmlv2 libname engine even works differently when importing or exporting the exact same data! Examples & steps to reproduce below - help me out if you can!
Example data
The data is a list of files and some attributes related to those files. The attributes are common to all files, only filenames in the list differ. This creates a test dataset into SAS work:
proc sql;
create table input_data
(col1 char(1),
col2 char(1),
file char(20));
insert into input_data
values ('1', '2', 'file1.txt')
values ('1', '2', 'file2.txt');
quit;
Desired output XML
Note that all the filenames are listed together in their own FILE elements, nested inside a single FILES element. The common attributes are elements inside the main FILE_INFO element. This is the structure I need to be able to output.
<?xml version="1.0" encoding="windows-1252" ?>
<FILE_INFO>
<COL1>1</COL1>
<COL2>2</COL2>
<FILES>
<FILE>file1.txt</FILE>
<FILE>file2.txt</FILE>
</FILES>
</FILE_INFO>
SAS XMLMAP I've created
<?xml version="1.0" encoding="windows-1252"?>
<!-- ############################################################ -->
<!-- this is a map file for SAS-XML conversion -->
<!-- ############################################################ -->
<SXLEMAP name="file_test" version="2.1">
<!-- ############################################################ -->
<OUTPUT>
<TABLEREF name="FILE_INFO"/>
</OUTPUT>
<NAMESPACES count="0"/>
<!-- ############################################################ -->
<TABLE name="FILE_INFO">
<TABLE-PATH syntax="XPath">/FILE_INFO/FILES/FILE</TABLE-PATH>
<COLUMN name="col1" retain="YES">
<PATH syntax="XPath">/FILE_INFO/COL1</PATH>
<TYPE>character</TYPE>
<DATATYPE>string</DATATYPE>
<LENGTH>1</LENGTH>
</COLUMN>
<COLUMN name="col2" retain="YES">
<PATH syntax="XPath">/FILE_INFO/COL2</PATH>
<TYPE>character</TYPE>
<DATATYPE>string</DATATYPE>
<LENGTH>1</LENGTH>
</COLUMN>
<COLUMN name="file">
<PATH syntax="XPath">/FILE_INFO/FILES/FILE</PATH>
<TYPE>character</TYPE>
<DATATYPE>string</DATATYPE>
<LENGTH>20</LENGTH>
</COLUMN>
</TABLE>
</SXLEMAP>
SAS code to output the XML using the XMLMAP
filename out "C:\myfolder\test_out.xml";
libname out xmlv2 xmltype=xmlmap xmlmap="C:\myfolder\file_test.map";
data out.FILE_INFO;
set work.input_data;
run;
Actual result XML
<?xml version="1.0" encoding="windows-1252" ?>
<FILE_INFO>
<FILES>
<FILE>file1.txt</FILE>
</FILES>
<COL1>1</COL1>
<COL2>2</COL2>
<FILES>
<FILE>file2.txt</FILE>
</FILES>
</FILE_INFO>
Steps to reproduce
Generate test data set using the code above. Save XMLMAP into file_test.map. Run SAS Code, compare resulting XML to the desired result.
The Problem
See what happens there? All the FILE-elements go inside their own FILES-elements. This happens no matter how many rows with separate filenames I have in my data: each and every one of them has its own FILES-element.
The fun part is, if I take the desired output XML file above, and feed it back to SAS using the very same XMLMAP, the resulting SAS dataset is exactly the same as my original input dataset!
I've tried fiddling with RETAIN-options in the XMLMAP, I've tried defining FILES as its own column in the input dataset and defining it in the XMLMAP, I've tried all kinds of random stuff but to no avail. Any ideas?