BookmarkSubscribeRSS Feed
vanmon1
Obsidian | Level 7

Hi there,

I am pretty new to macros and I have been trying this for days and days. My macros work and they produce the files but because I have 4 macros, each file its built in 4 steps (so it creates the 100 + xml files with the first macro and then builds them up until the last macro) which is a great problem for what we need them for. When trying to integrate them into one macro I lose information from steps 3 and 4 (macro3 and 4) and it will only keep the first date or the first device. Could someone please help me to integrate it so this does not happen? Thank you in advance.

libname Factory "S:\Libre_prueba0.8\factory";
libname Lista "S:\Libre_prueba0.8\Lista";


proc sql;
create table factory.macrofac as select memname as facil  from dictionary.tables where libname='LISTA' and nobs ne 0
order by memname ;quit;

data facil;
set factory.macrofac;
facil=facil;
call symput ('num_fals',_n_);
run;

%macro xmlone;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct station, datename  from factory.analysis_periodd&&facil; quit;

data _null_; 
set lines ; /* read the file names from the directory */
datename=datename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 

data y_&&facil;
set lines ;
if _n_=&j;
call symput ('datename',compress(datename));
call symput ('station',compress(station));
run;



libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml"  xmltype=generic;
libname odm xml formatnoreplace=NO;


data vms.program_version;
set factory.Program_versionD&&station ;
run;


data vms.Analysis_Period;
set  Factory.Analysis_PeriodD&&station ;
if compress(datename)="&&datename";
DROP DATENAME STATION;
run;


data vms.Facility_DailyOCC;
set  Factory.Facility_Daily_&&facil;
if compress(datename)="&&datename";
drop datename station measuredate;
run;

%end;
%end;
%mend xmlone;
%xmlone;

libname vms;

data facil;
set factory.macrofac;
facil=facil;
call symput ('num_fals',_n_);
run;

%macro xmltwo;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct datename, devicename from factory.device_daily_&&facil; quit;

data null_; 
set lines ; /* read the file names from the directory */
devicename=devicename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 

data y_&&facil;
set lines ;
if _n_=&j;
call symput ('datename',compress(datename));
call symput ('devicename',compress(devicename));
run;

libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml" ;
libname odm xml formatnoreplace=NO;

DATA DAILY_&&devicename&&j ;
SET Factory.device_daily_&&facil ;
IF compress(datename)="&&datename";
IF devicename="&&devicename";
DROP devicename DATENAME STATION MEASUREDATE;
RUN;

proc sql; create table vms.DAILY_&&devicename as select * from DAILY_&&devicename&&j; quit;


%end;
%end;
%mend xmltwo;

%xmltwo;

libname vms;

%macro xmlthree;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct datename, devicename,hour_range from factory.device_info_&&facil; quit;

data _null_; 
set lines ; /* read the file names from the directory */
devicename=devicename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 

data y_&&facil;
set lines ;
if _n_=&j;
call symput ('datename',compress(datename));
call symput ('devicename',compress(devicename));
call symput ('hour_range', compress(hour_range));
run;



libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml" ;
libname odm xml formatnoreplace=NO;


data Hourly_&&devicename&&j;
SET Factory.device_info_&&facil ;
if compress(datename)="&&datename" ;
if compress(devicename)="&&devicename" ;
drop devicename datename station;
run;

proc sql; create table vms.Hourly_&&devicename as select * from Hourly_&&devicename&&j;quit;
quit;



%end;
%end;
%mend xmlthree;

%xmlthree;


%macro xmlfour;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct station, datename  from factory.analysis_periodd&&facil; quit;

data _null_; 
set lines ; /* read the file names from the directory */
datename=datename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 

data y_&&facil;
set lines ;
if _n_=&j;
call symput ('datename',compress(datename));
call symput ('station',compress(station));
run;

libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml"  xmltype=generic;
libname odm xml formatnoreplace=NO;


data vms.Times_False_Occ;
set Factory.Times_False_Occ_&&facil;
if compress(datename)="&&datename";
drop datename file_csv station;
run;

%end;
%end;
%mend xmlfour;

%xmlfour;

libname vms;
16 REPLIES 16
Kurt_Bremser
Super User

What is the reason for using double ampersands for indirect macro variable addressing? Do you really have the names of macro variables in your datasets?

vanmon1
Obsidian | Level 7
Thanks for replying.
andreas_lds
Jade | Level 19

Have you tried solving the problem without any macro-code?

Can you add some descriptions to the steps explaining their purpose?

vanmon1
Obsidian | Level 7
Thanks for replying.I have too many folders to export to and many files with a datename to create and I need to automatize the process.
Tom
Super User Tom
Super User

It is hard to tell what your macros are doing (or supposed to be doing) without comments.  

 

Usually I find it best to create macros that do a specific task and take as input parameters that drive that task.  For example your first macro appears to be trying to loop over some type of list of datasets but it is impossible to tell this from just the definition of the macro itself as it is constantly referring to input macro variables and datasets that were not passed into it as parameters. 

 

It looks a lot like this is one of the macros you might need:

%macro daily(facil,station,datename);

libname vms xmlv2 "S:\XML_RESULTS_VMS\&facil\daily\&datename..xml" xmltype=generic;
* Why is this ODM libref defined here? It is never referenced. ;
* libname odm xml formatnoreplace=NO;

data vms.program_version;
  set factory.Program_versionD&station ;
run;

data vms.Analysis_Period;
  set  Factory.Analysis_PeriodD&station ;
  if compress(datename)="&datename";
  drop DATENAME STATION;
run;

data vms.Facility_DailyOCC;
  set  Factory.Facility_Daily_&facil;
  if compress(datename)="&datename";
  drop datename station measuredate;
run;

libname vms clear;
%mend daily;

Then if you have a dataset named LIST that has the set of distinct values of STATION FACIL and DATENAME you can just use a simple data step to generate one call for each combination.

data _null_;
  set list ;
  call execute(cats('%nrstr(%daily)'
  ,'(station=',station
  ,',facil=',facil
  ,',datename=',datename
  ,')'
  ));
run;
vanmon1
Obsidian | Level 7

Thank you. I will try.

ScottBass
Rhodochrosite | Level 12

I can't tell what you're trying to do (but I haven't tried that hard).

 

Some comments:

 

* Use call symputx.  IMO call symput is deprecated.

* Perhaps these macros will help?

 

https://github.com/scottbass/SAS/blob/master/Macro/loop.sas

https://github.com/scottbass/SAS/blob/master/Macro/loop_control.sas

You'll also need 

https://github.com/scottbass/SAS/blob/master/Macro/parmv.sas

 

Save them somewhere, then either %include them to compile the macro, or add "somewhere" to your sasautos path.

 

There are loads of use cases in the macro header.

 

* Try consolidating your multiple macros into a single macro, and get that single macro working with a single table.  Then, replace all the bits that change with macro variables.  Then it should be simple to just loop over a list and replace your parameters.

 

As very quick, untested examples:

 

proc sql;
select memname into :tables separated by ' '
from dictionary.tables 
where libname='LISTA' 
and nobs ne 0
order by memname;
quit;

%macro code;
%put &word;
%mend;
%loop(&tables)

You're now parsing your list of tables.  Each space separated token is in the macro variable &word.  No data steps, if _n_ = whatever, call symputs, %do i=1 to &somenum, etc.

 

Building on that:

 

%macro code;
proc sql;
create table lines as 
select distinct station, datename  
from factory.analysis_periodd&word;
quit;

* inner macro ;
%macro lines;
%let datename=%trim(&datename);
%let station=%trim(&station);
%put *&datename*;
%put *&station*;  * the asterisks are to show that the macro variable is trimmed ;
%mend;
%loop_control(control=lines,mname=lines)
%mend;
%mend; %loop(&tables)

You're still looping over your list of tables in the outer macro, creating the dataset lines from factory.analysis_periodd&word, where &word is the current table name. 

You're then looping over the lines dataset via the inner macro, creating the macro variables &datename and &station for each row in that table.

You can then build the rest of your downstream code within the %lines macro.

 

Sorry for the text formatting, the forum software is buggy - setting the font and size makes no difference. 

 

HTH...


Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.
vanmon1
Obsidian | Level 7

Hi again, and sorry I was wrong, is not working. It keeps doing macro by macro, I would like it to generate one xml file with the 4 macros, then generate the next one. I have tried to explain my program a bit with comments. Is the problem that my data comes from 4 different tables, rather than just one? Thanks again.

;*%mend;*);*';*";**/;

proc printto; run;/* log="NULL";quit;*/

%let Program_version=0.80;
%let Prog_Description="MdB MFull Automation, stack overflow";

%let today=%sysfunc(today(),date9.);

libname Imported  "S:\Libre_prueba0.8\Imported";
libname Datos "S:\Libre_prueba0.8\datos";
libname Raw "S:\Libre_prueba0.8\raw";
libname Factory "S:\Libre_prueba0.8\factory";
libname Analysis "S:\Libre_prueba0.8\analysis";
libname Lista "S:\Libre_prueba0.8\Lista";



data facil;
set factory.macrofac;
facil=facil;
call symput ('num_fals',_n_);
run;

/* I have 12 folders with the station name and each contain numerous csv files named as the date they are generated, I have to create an xml file for each 
station and each day in return. The macro xmlone reads from factory.analysis_periodd&&facil facil=station the name of the station and the date of the csv file
and has a datename wich will be the name of each xml file so for each station and date generates one xml*/

%macro xmlone;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct station, datename  from factory.analysis_periodd&&facil; quit;

data _null_; 
set lines ;
datename=datename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 

data y_&&facil;
set lines ;
if _n_=&j;
call symput ('datename',compress(datename));
call symput ('station',compress(station));
run;

/*so for each station and date generates one xml*/


/*and prints information consisting in only 1 line, program version, analysis period and a summary of the data by station and day level, which is again 1 line only
per station*/


libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml"  xmltype=generic;

data vms program_version;
set factory.Program_versionD&&station ;
run;


data vms.Analysis_Period;
set  Factory.Analysis_PeriodD&&station ;
if compress(datename)="&&datename";
run;


data vms.Facility_DailyOCC;
set  Factory.Facility_Daily_&&facil;
if compress(datename)="&&datename";
drop datename station measuredate;
run;

%end;
%end;
%mend xmlone;

/*macro xmltwo reads more than one line per station and date, this is why I had to do separate macros??
for each station reads about 30 devices, 30 lines. */

%macro xmltwo;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct datename, devicename from factory.device_daily_&&facil; quit;

data null_; 
set lines ; /* read the file names from the directory */
devicename=devicename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 

data y_&&facil;
set lines ;
if _n_=&j;
call symput ('datename',compress(datename));
call symput ('devicename',compress(devicename));
run;

proc sort data=Factory.device_daily_&&facil; by station datename devicename;run;


libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml"  xmltype=generic;

DATA vms.Daily_&&devicename ;
SET Factory.device_daily_&&facil ;
IF compress(datename)="&&datename";
IF devicename="&&devicename";
/*drop devicename DATENAME STATION MEASUREDATE;*/
RUN;



%end;
%end;
%mend xmltwo; 
/*The macro XMLthree reads then 24 hours per each station per each devices so about 720*/
%macro xmlthree;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct datename, devicename,hour_range from factory.device_info_&&facil; quit;

data _null_; 
set lines ; /* read the file names from the directory */
devicename=devicename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 

data y_&&facil;
set lines ;
if _n_=&j;
call symput ('datename',compress(datename));
call symput ('devicename',compress(devicename));
call symput ('hour_range', compress(hour_range));
run;


proc sort data=Factory.Device_info_&&facil; by station datename devicename hour_range;run;


libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml"  xmltype=generic;


data vms.Hourly_&&devicename;
SET Factory.device_info_&&facil ;
if compress(datename)="&&datename" ;
if compress(devicename)="&&devicename" ;
/*drop devicename datename station;*/
run;




%end;
%end;
%mend xmlthree;


/*Here I run the 4 macros but what ever i try it runs macro by macro so it goes round the hundreds of files 4 times*/

%macro xmlcompile;
%do k=1 %to &num_fals; 

data _null_; 
set factory.macrofac; 
facil=facil;
if _n_=&k;
call symput ('facil',compress(facil)); 
run; 

proc sql;
create table lines as select distinct station, datename  from factory.analysis_periodd&&facil; quit;

data _null_; 
set lines ; /* read the file names from the directory */
datename=datename;
call symput ('num_files',_n_);/* store the record number in a macro variable */
run; 

%do j=1 %to &num_files; 



libname vms xmlv2 "S:\XML_RESULTS_VMS\&&facil\daily\&&datename..xml"  xmltype=generic;



data vms._null_;
call execute('%nrstr(%xmlone)');
call execute ('%nrstr(%xmltwo)');
call execute('%nrstr(%xmlthree)');
run;


%end;
%end;
%end;
%end;
%mend xmlcompile;
%xmlcompile;

 

 

ScottBass
Rhodochrosite | Level 12

Step 1:  FORGET MACRO.  Get your code to work for a single iteration.  Hardcode everything, even the macro bits - your loop upper bounds, datename, station, etc, etc.  Get your code to work for a single iteration.

 

Step 2:  Macroize the bits that are dynamic and the looping logic.

 

If you post Step 1, I can probably help you with Step 2.  If you post more macro code, see Step 1.


Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.
vanmon1
Obsidian | Level 7

First of all, thanks again for your help.

 

Ok, let´s see if it is clearer this way. I also attach the final xml because I think it may help to see what I need. This is an example for one day, one station.

 

libname vms xmlv2 "Z:\VMS\sas_results_xml\Station_1\daily\2019-07-22.xml" ;

/*First block, let´s say my macro xmlone*/
/*There is one table for each station, so Program_versionDStation1,Program_versionDStation2 Program_versionDStation3 etc*/

data vms.program_version;
set factory.Program_versionDStation1 ;
if datename="2019-09-22"; /*different dates also needed*/

run;

data vms.Analysis_Period;
set  factory.Analysis_PeriodDStation1 ;
if datename="2019-09-22"; /*different dates also needed*/
drop year month;
run;

data vms.Facility_DailyOCC;
set  factory.Facility_Daily_Station1;
if datename="2019-09-22"; /*different dates also needed*/
run;
/*second block let´s say my macro xmltwo*
/*There is one table for each station, so device_daily_station1 ,device_daily_station2, device_daily_station3 etc
Each one contains all the devices, for that station and I need one table generated for each of them, so about 30 
tables per station, PER DAY, so if I have a back log like now, we are talking about hundreds of tables per station*/

data vms.DAILY_device1 ;
set factory.device_daily_station1  ;
if devicename="devicename1";
if datename="2019-09-22"; /*different dates also needed*/
drop devicename datename;
run;

data vms.DAILY_device2 ;
set factory.device_daily_station1  ;
if devicename="devicename2";
if datename="2019-09-22";/*different dates also needed*/
drop devicename datename;
run;


data vms.DAILY_device3 ;
set factory.device_daily_station1  ;
if devicename="devicename3";
if datename="2019-09-22"; /*different dates also needed*/
drop devicename datename;
run;

data vms.DAILY_deviceETC ;
set factory.device_daily_station1  ;
if devicename="devicename4";
if datename="2019-09-22"; /*different dates also needed*/
drop devicename datename;
run;
/*third block, xmlthree*/
/**** this is the 3rd lot of tables***//*there is also 1 table per station with all dates, devices and hours*/
/***Now it is by station, date, device and hour level**/
data vms.HOURLY_device1_Hour_00;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
drop devicename;
run;
data vms.HOURLY_device1_Hour_01;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
if hour_range="01:00";
drop devicename;
run;
data vms.HOURLY_device1_Hour_02;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
drop devicename;
run;

data vms.HOURLY_device1_Hour_ETC;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
if hour_range="02:00";
drop devicename;
run;  /*ETC to 24 hours (or what is available) per device, per day, per station*/


/*second device*/
data vms.HOURLY_device2_Hour_00;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
drop devicename;
run;
data vms.HOURLY_device2_Hour_01;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
drop devicename;
run;
data vms.HOURLY_device2_Hour_02;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
drop devicename;
run;

data vms.HOURLY_device2_Hour_ETC;
  set factory.device_info_station1 ;
if devicename="device1";
if datename="2019-09-22"; 
drop devicename;
run;
/*fourth block, so similar to the first block but needs to be at the end in the xml*/
/*last block, one table per sation*/

data vms.TIMES_FALSE_OCC;
set  factory.TIMES_FALSE_OCC_station1;
if if datename="2019-09-22"; 
run;

libname vms;
Tom
Super User Tom
Super User

How many input datasets do you?  Is this the full list?

factory.Program_versionDStation1
factory.Analysis_PeriodDStation1
factory.Facility_Daily_Station1
factory.device_daily_station1  
factory.device_info_station1
factory.TIMES_FALSE_OCC_station1

What are the key variables for those datasets? What is the relationship between the tables? 

How do those keys relate to the variable parts of the filename you are generating for the XML file?

Z:\VMS\sas_results_xml\Station_1\daily\2019-07-22.xml

What about the relationship between the input datasets and/or key variables and the member names you are using when writing to the XML library?

 

How many variables are you actually writing to the XML for each of these records?

Perhaps it would be much simpler to just write the XML tags yourself using a DATA step.

ScottBass
Rhodochrosite | Level 12

Hi,

 

I don't have a lot of time to spend on this today, but I will offer a few quick tips:

 

1) You can have multiple set statements in the same data step. 

 

2) You can use the NOBS= set statement option to get the number of observations in the input data set AT COMPILE TIME.  IOW, you can reference the nobs variable "before" you define it in your set statement.  I say "before" because it's not before; it's actually defined during the data step compilation.

 

3) You can use the POINT= set statement option to specify the particular observation (row) you want to read from the input data set.

 

4) The data step ends when any of the set statements tries to read past the end of its input data set.  The POINT= option prevents that.  (It also means you can code an infinite loop with the POINT= option if you're not careful).  The POINT= option allows you to "rewind" the data set based on the POINT= value at run time.

 

5) Each time the set statement executes, it reads a row from the input data set and populates the Program Data Vector (PDV).

 

6) A data set variable (as opposed to a data *step* variable) has an implied retain.  This means you can use a conditional set statement, and the data set variable is carried forward from the last time the set statement executed (due to the implied retain).  (This may or may not be relevant to your problem statement).

 

Putting this all together:

 

data x (keep=x)
     y (keep=y)
     z (keep=z)
   ;
   do x=1 to 10;
      y=x*2;
      z=x*3;
      output x;
      if x <= 5 then output y;
      if x > 5 then output z;
   end;
run;
   
data test;
   set x;
   do i=1 to nobs_y;
      set y nobs=nobs_y point=i;

      do j=1 to nobs_z;
         if mod(j,2)=1 then set z nobs=nobs_z point=j;
         output;
      end;
   end;
   * don't need to drop i and j because they are used with point= ;
run;

* dynamic processing ;
* you can't use a where clause but you can use an if statement ;
data test2;
   set x;  /* 1 to 10 */
   _y=x*3; /* 3,6,9, etc */
   _z=x*4; /* 4,8,16, etc */

   * still need point= to prevent reading past end of file ;
   * it allows "rewinding" the dataset each time ;
   do i=1 to nobs_y;
      set y nobs=nobs_y point=i;
      if y < _y;

      do j=1 to nobs_z;
         set z nobs=nobs_z point=j;
         if z < _z;
         output;
      end;
   end;
   * drop _:;
run;

Hopefully you can wrap your head around this. 

 

This means you may be able to drop much of your macro processing where you were running a secondary data step, specifying if _n_=<some number>, then creating macro variables to use in downstream processing.

 

Lastly, do you have, and have you ever used, the XMLMAPPER application?  It is a Java program supplied by SAS that creates a UI, where you can create an XML map.  Usually this is a map of an input XML file, flattening that file into a tabular format that is then used to read the data into SAS.  Check Start -> Programs -> SAS.  You'll either see XMLMAPPER or you won't.  If not, check with your SAS administrator.  AFAIK, there are no licensing issues - XMLMAPPER is a free utility provided by SAS.

 

An XML map can also be used to specify an output XML file format.  It's been a while since I've used it, but you may be able to create an XML map that will create the output format you want.  If so, the process would be to flatten (merge, join, etc) your data so that your combined SAS dataset is how you want to represent your data.  You would then use a data step, PROC PRINT, PROC REPORT, etc. to "print" your SAS dataset to your output XML fileref, supplying the XML map as a parameter to your filename statement.

 

Otherwise, as Tom said, you could just hand generate your XML tags.

 

HTH...

 

Edit:  If you have installation rights on your machine (and perhaps even if you don't - you don't HAVE to install to C:\Program Files), then it looks like XML mapper is a free download:

 

https://support.sas.com/downloads/package.htm?pid=713

 


Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.
ScottBass
Rhodochrosite | Level 12

SASxml.txt isn't valid XML (according to XML mapper).

 

An excerpt:

 

TABLE>
   PROGRAM_VERSION>
      Program_version>0.4/Program_version>
      Program_description>crs/Program_description>
      FacilityID>9c809b45-828c-4a9b-b9b0-98caa06524b0/FacilityID>
      GenerationDate>2019-09-06T15:03:20/GenerationDate>
   /PROGRAM_VERSION>
   ANALYSIS_PERIOD>
      MeasureDate>2019-07-22/MeasureDate>
   /ANALYSIS_PERIOD>

Change to:

 

<TABLE>
   <PROGRAM_VERSION>
      <Program_version>0.4</Program_version>
      <Program_description>crs</Program_description>
      <FacilityID>9c809b45-828c-4a9b-b9b0-98caa06524b0</FacilityID>
      <GenerationDate>2019-09-06T15:03:20</GenerationDate>
   </PROGRAM_VERSION>
   <ANALYSIS_PERIOD>
      <MeasureDate>2019-07-22</MeasureDate>
   </ANALYSIS_PERIOD>

etc, etc

And re-attach to your post.


Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.
vanmon1
Obsidian | Level 7

Hello, I had to delete < so it let me attach the file. Just so you could see the content. Even when trying to attach a txt file it would recognise the content as xml...

Now as rtf it works. Thank you.

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 16 replies
  • 3044 views
  • 5 likes
  • 5 in conversation